[{"data":1,"prerenderedAt":3172},["ShallowReactive",2],{"article_list_bporter_":3},[4,389,615,2370,2539,2942,3085],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"image":11,"publishDate":12,"tags":13,"excerpt":10,"body":17,"_type":380,"_id":381,"_source":382,"_file":383,"_stem":384,"_extension":385,"author":386},"/bporter/2020-10/reanimated","2020-10",false,"","Re-animated","Last year, I posted here about an animation control framework called 'Friz' that works within the JUCE Application Framework.","/bporter/2020-10/img/module.png","2020-10-01",[14,15,16],"juce","ui","c++",{"type":18,"children":19,"toc":373},"root",[20,48,53,79,145,180,185,192,197,202,210,215,243,248,254,277,343,349,362,367],{"type":21,"tag":22,"props":23,"children":24},"element","p",{},[25,28,37,39,46],{"type":26,"value":27},"text","Last year, I ",{"type":21,"tag":29,"props":30,"children":34},"a",{"href":31,"rel":32},"https://artandlogic.com/2019/09/friz-and-the-illusion-of-life/",[33],"nofollow",[35],{"type":26,"value":36},"posted here",{"type":26,"value":38}," about an animation control framework called 'Friz' that works within the ",{"type":21,"tag":29,"props":40,"children":43},{"href":41,"rel":42},"https://www.juce.com",[33],[44],{"type":26,"value":45},"JUCE Application Framework",{"type":26,"value":47},".",{"type":21,"tag":22,"props":49,"children":50},{},[51],{"type":26,"value":52},"As I said in that post:",{"type":21,"tag":54,"props":55,"children":56},"blockquote",{},[57],{"type":21,"tag":22,"props":58,"children":59},{},[60,62,68,70,77],{"type":26,"value":61},"I sat down to sketch some things out and ended up making a small framework for generating dynamic data that can be used to animate pretty much any aspect of the user interface of a program written using the ",{"type":21,"tag":29,"props":63,"children":65},{"href":41,"rel":64},[33],[66],{"type":26,"value":67},"JUCE application framework",{"type":26,"value":69}," (which I've written about here ",{"type":21,"tag":29,"props":71,"children":74},{"href":72,"rel":73},"https://artandlogic.com/?s=juce",[33],[75],{"type":26,"value":76},"many times",{"type":26,"value":78}," before), and has the goals of being:",{"type":21,"tag":54,"props":80,"children":81},{},[82],{"type":21,"tag":83,"props":84,"children":85},"ul",{},[86,98,108,127],{"type":21,"tag":87,"props":88,"children":89},"li",{},[90,96],{"type":21,"tag":91,"props":92,"children":93},"strong",{},[94],{"type":26,"value":95},"Lightweight",{"type":26,"value":97},"—if there aren't any animations in progress, there's no runtime overhead.",{"type":21,"tag":87,"props":99,"children":100},{},[101,106],{"type":21,"tag":91,"props":102,"children":103},{},[104],{"type":26,"value":105},"Flexible",{"type":26,"value":107},"—it's easy to add new types of animation curves if you want to, or to chain multiple curves together into a more complex sequence.",{"type":21,"tag":87,"props":109,"children":110},{},[111,116,118,125],{"type":21,"tag":91,"props":112,"children":113},{},[114],{"type":26,"value":115},"Decoupled",{"type":26,"value":117},"—it doesn't need or want to know anything about your application. When your code creates an animation effect, you pass it a pair of ",{"type":21,"tag":119,"props":120,"children":122},"code",{"className":121},[],[123],{"type":26,"value":124},"std::function",{"type":26,"value":126}," objects; one to handle updates for each frame, and another one to handle the completion of the effect.",{"type":21,"tag":87,"props":128,"children":129},{},[130,135,137,144],{"type":21,"tag":91,"props":131,"children":132},{},[133],{"type":26,"value":134},"Modern",{"type":26,"value":136},"—written using current C++ techniques (defined for our purposes as C++11 and later). I spent some time away from C++ and have come back to find the language has undergone some seroius changes that require me to consciously update my habits, making me feel like the programmer version of SNL's ",{"type":21,"tag":29,"props":138,"children":141},{"href":139,"rel":140},"https://en.wikipedia.org/wiki/Unfrozen_Caveman_Lawyer",[33],[142],{"type":26,"value":143},"Unfrozen Caveman Lawyer",{"type":26,"value":47},{"type":21,"tag":54,"props":146,"children":147},{},[148],{"type":21,"tag":22,"props":149,"children":150},{},[151,153,160,162,169,171,178],{"type":26,"value":152},"As the code began to take shape, I decided to name it after the great Warner Bros. animator/director ",{"type":21,"tag":29,"props":154,"children":157},{"href":155,"rel":156},"https://en.wikipedia.org/wiki/Friz_Freleng",[33],[158],{"type":26,"value":159},"Friz Freling",{"type":26,"value":161},". I would like to have called it 'Chuck' after his colleague ",{"type":21,"tag":29,"props":163,"children":166},{"href":164,"rel":165},"https://en.wikipedia.org/wiki/Chuck_Jones",[33],[167],{"type":26,"value":168},"Chuck Jones",{"type":26,"value":170},", but \"",{"type":21,"tag":29,"props":172,"children":175},{"href":173,"rel":174},"https://chuck.cs.princeton.edu/",[33],[176],{"type":26,"value":177},"ChucK",{"type":26,"value":179},"\" already means something else in the electronic music software world.",{"type":21,"tag":22,"props":181,"children":182},{},[183],{"type":26,"value":184},"I found the time this past weekend to update the Friz code with two things that I've had on my list for a long time:",{"type":21,"tag":186,"props":187,"children":189},"h2",{"id":188},"juce-module",[190],{"type":26,"value":191},"JUCE Module",{"type":21,"tag":22,"props":193,"children":194},{},[195],{"type":26,"value":196},"The library is now packaged as a JUCE module, so it's straightforward to include in a JUCE project without needing to manually copy files around. In reality, I should have done this from day one (and now that I understand how trivial it is to work with JUCE modules, that's how I'll approach anything like this in the future).",{"type":21,"tag":22,"props":198,"children":199},{},[200],{"type":26,"value":201},"To use friz as a module, get it from the GitHub repo (see below) and then use the Projucer to add it to your project from that directory:",{"type":21,"tag":22,"props":203,"children":204},{},[205],{"type":21,"tag":206,"props":207,"children":209},"img",{"alt":208,"src":11},"projucer view",[],{"type":21,"tag":22,"props":211,"children":212},{},[213],{"type":26,"value":214},"Once you've done that, you can just add",{"type":21,"tag":216,"props":217,"children":221},"pre",{"className":218,"code":219,"language":220,"meta":8,"style":8},"language-cpp shiki shiki-themes github-light github-dark","#include \"friz.h\"\n","cpp",[222],{"type":21,"tag":119,"props":223,"children":224},{"__ignoreMap":8},[225],{"type":21,"tag":226,"props":227,"children":230},"span",{"class":228,"line":229},"line",1,[231,237],{"type":21,"tag":226,"props":232,"children":234},{"style":233},"--shiki-default:#D73A49;--shiki-dark:#F97583",[235],{"type":26,"value":236},"#include",{"type":21,"tag":226,"props":238,"children":240},{"style":239},"--shiki-default:#032F62;--shiki-dark:#9ECBFF",[241],{"type":26,"value":242}," \"friz.h\"\n",{"type":21,"tag":22,"props":244,"children":245},{},[246],{"type":26,"value":247},"...and start using it as described in my earlier post.",{"type":21,"tag":186,"props":249,"children":251},{"id":250},"new-parametric-easing-curves",[252],{"type":26,"value":253},"New 'parametric' easing curves",{"type":21,"tag":22,"props":255,"children":256},{},[257,259,266,268,275],{"type":26,"value":258},"Shortly after releasing the original version of this last year, I stumbled on an ",{"type":21,"tag":29,"props":260,"children":263},{"href":261,"rel":262},"https://easings.net",[33],[264],{"type":26,"value":265},"excellent site",{"type":26,"value":267}," that described itself as an \"Easing Curve Cheat Sheet\" that shows examples of a whole bunch of curves that are commonly found in the wild—libraries and frameworks like jQuery, Cinder, and Flutter all support a set of curves that all point back to functions defined by ",{"type":21,"tag":29,"props":269,"children":272},{"href":270,"rel":271},"http://robertpenner.com/easing/",[33],[273],{"type":26,"value":274},"Robert Penner",{"type":26,"value":276},", whose site you should check out.",{"type":21,"tag":22,"props":278,"children":279},{},[280,282,288,290,295,297,303,305,311,313,318,320,326,328,333,335,341],{"type":26,"value":281},"The new ",{"type":21,"tag":119,"props":283,"children":285},{"className":284},[],[286],{"type":26,"value":287},"Parametric",{"type":26,"value":289}," class may be created to implement any of those Penner curves, or you can use it to follow any curve that you design, by passing in a function (whether a ",{"type":21,"tag":119,"props":291,"children":293},{"className":292},[],[294],{"type":26,"value":124},{"type":26,"value":296},", lambda, or plain old C function) that accepts a single ",{"type":21,"tag":119,"props":298,"children":300},{"className":299},[],[301],{"type":26,"value":302},"float",{"type":26,"value":304}," parameter in the range ",{"type":21,"tag":119,"props":306,"children":308},{"className":307},[],[309],{"type":26,"value":310},"[0..1]",{"type":26,"value":312}," and returns a ",{"type":21,"tag":119,"props":314,"children":316},{"className":315},[],[317],{"type":26,"value":302},{"type":26,"value":319}," that is typically ",{"type":21,"tag":321,"props":322,"children":323},"em",{},[324],{"type":26,"value":325},"but not necessarily",{"type":26,"value":327}," also in the ",{"type":21,"tag":119,"props":329,"children":331},{"className":330},[],[332],{"type":26,"value":310},{"type":26,"value":334}," range. The animation framework will interpolate that output value between the start/end values used in your animation. Since these curves may have overshoot on either end (see for example, the ",{"type":21,"tag":119,"props":336,"children":338},{"className":337},[],[339],{"type":26,"value":340},"easeInOutElastic",{"type":26,"value":342}," curve, which has fairly complex under- and overshoot on both ends of the curve), the code that handles your animation must work correctly when passed values outside of your start/stop values (where only you can define what 'correctly' means other than 'don't crash').",{"type":21,"tag":186,"props":344,"children":346},{"id":345},"downloadlicenceetc",[347],{"type":26,"value":348},"Download/Licence/etc.",{"type":21,"tag":22,"props":350,"children":351},{},[352,354,360],{"type":26,"value":353},"You can get the library at ",{"type":21,"tag":29,"props":355,"children":358},{"href":356,"rel":357},"https://github.com/bgporter/animator",[33],[359],{"type":26,"value":356},{"type":26,"value":361},", and it's MIT licensed. Open source, closed source, it's all fine by me as long as you only use it for good and not evil.",{"type":21,"tag":22,"props":363,"children":364},{},[365],{"type":26,"value":366},"Go make cool stuff.",{"type":21,"tag":368,"props":369,"children":370},"style",{},[371],{"type":26,"value":372},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":8,"searchDepth":374,"depth":374,"links":375},3,[376,378,379],{"id":188,"depth":377,"text":191},2,{"id":250,"depth":377,"text":253},{"id":345,"depth":377,"text":348},"markdown","content:bporter:2020-10:reanimated.md","content","bporter/2020-10/reanimated.md","bporter/2020-10/reanimated","md",{"user":387,"name":388},"bporter","Brett Porter",{"_path":390,"_dir":391,"_draft":7,"_partial":7,"_locale":8,"title":392,"description":393,"image":394,"publishDate":395,"tags":396,"excerpt":393,"body":399,"_type":380,"_id":611,"_source":382,"_file":612,"_stem":613,"_extension":385,"author":614},"/bporter/2019-4/aesannounce","2019-4","Art+Logic In the Real World","There are a few events coming up in the next few weeks where A+L will have people in attendance. If you're going to be there or nearby, please get in touch and we'll meet up.","/bporter/2019-4/img/aesLogo.jpg","2019-04-01",[397,398],"a+l","event",{"type":18,"children":400,"toc":605},[401,405,411,419,427,432,441,446,460,466,473,478,500,513,524,530,553,566,572,580,585],{"type":21,"tag":22,"props":402,"children":403},{},[404],{"type":26,"value":393},{"type":21,"tag":186,"props":406,"children":408},{"id":407},"mondonycsf-musictech",[409],{"type":26,"value":410},"Mondo.NYC/SF MusicTech",{"type":21,"tag":22,"props":412,"children":413},{},[414],{"type":21,"tag":206,"props":415,"children":418},{"alt":416,"src":417},"Mondo logo","/bporter/2019-4/img/mondo-logo-black-360-300x74.jpg",[],{"type":21,"tag":22,"props":420,"children":421},{},[422],{"type":21,"tag":206,"props":423,"children":426},{"alt":424,"src":425},"SF POP UP logo","/bporter/2019-4/img/sfmusictech-popup-1024x200.png",[],{"type":21,"tag":22,"props":428,"children":429},{},[430],{"type":26,"value":431},"16-18 October, Brooklyn",{"type":21,"tag":22,"props":433,"children":434},{},[435],{"type":21,"tag":29,"props":436,"children":439},{"href":437,"rel":438},"https://mondo.nyc",[33],[440],{"type":26,"value":437},{"type":21,"tag":22,"props":442,"children":443},{},[444],{"type":26,"value":445},"Mondo.NYC bills itself as \"a festival and global business summit of music and tech industry insiders and innovators, emerging artists and their fans. Mondo connects fans and creators in a shared mission of empowering artists and advancing ideas in an ever-changing music business and technology landscape.\"",{"type":21,"tag":22,"props":447,"children":448},{},[449,451,458],{"type":26,"value":450},"We'll be there on Wednesday for the ",{"type":21,"tag":29,"props":452,"children":455},{"href":453,"rel":454},"http://www.sfmusictech.com/popup",[33],[456],{"type":26,"value":457},"SF Music Tech",{"type":26,"value":459}," pop-up event.",{"type":21,"tag":186,"props":461,"children":463},{"id":462},"aes-convention",[464],{"type":26,"value":465},"AES Convention",{"type":21,"tag":22,"props":467,"children":468},{},[469],{"type":21,"tag":206,"props":470,"children":472},{"alt":471,"src":394},"AES logo",[],{"type":21,"tag":22,"props":474,"children":475},{},[476],{"type":26,"value":477},"16-19 October, Jacob Javits Convention Center, New York.",{"type":21,"tag":22,"props":479,"children":480},{},[481,483,490,492,499],{"type":26,"value":482},"On Saturday, 19 October, ",{"type":21,"tag":29,"props":484,"children":487},{"href":485,"rel":486},"https://artandlogic.com/2018/07/announcing-the-winner-of-our-first-annual-software-incubator-lab/",[33],[488],{"type":26,"value":489},"Dr Scott Hawley",{"type":26,"value":491}," of Belmont University will present an Engineering Brief paper discussing the \"Vibrary\" application developed as part of the ",{"type":21,"tag":29,"props":493,"children":496},{"href":494,"rel":495},"https://artandlogic.com/incubator/",[33],[497],{"type":26,"value":498},"Art+Logic Incubator Lab",{"type":26,"value":47},{"type":21,"tag":22,"props":501,"children":502},{},[503,505,512],{"type":26,"value":504},"You can learn more about the brief, co-authored with three Art+Logic developers ",{"type":21,"tag":29,"props":506,"children":509},{"href":507,"rel":508},"http://www.aes.org/events/147/ebriefs/?ID=6938",[33],[510],{"type":26,"value":511},"here",{"type":26,"value":47},{"type":21,"tag":22,"props":514,"children":515},{},[516,518],{"type":26,"value":517},"Convention information and registration is at ",{"type":21,"tag":29,"props":519,"children":522},{"href":520,"rel":521},"http://www.aesshow.com",[33],[523],{"type":26,"value":520},{"type":21,"tag":186,"props":525,"children":527},{"id":526},"audio-programmer-meetup",[528],{"type":26,"value":529},"Audio Programmer Meetup",{"type":21,"tag":22,"props":531,"children":532},{},[533,535,542,544,551],{"type":26,"value":534},"On Thursday, 17 October, Joshua Hodge, who runs the excellent site ",{"type":21,"tag":29,"props":536,"children":539},{"href":537,"rel":538},"https://theaudioprogrammer.com",[33],[540],{"type":26,"value":541},"theaudioprogrammer.com",{"type":26,"value":543}," and its matching ",{"type":21,"tag":29,"props":545,"children":548},{"href":546,"rel":547},"https://www.youtube.com/theaudioprogrammer",[33],[549],{"type":26,"value":550},"YouTube channel",{"type":26,"value":552}," will be hosting a meetup for audio developers a few blocks away from the AES show.",{"type":21,"tag":22,"props":554,"children":555},{},[556,558,565],{"type":26,"value":557},"Information and RSVP on ",{"type":21,"tag":29,"props":559,"children":562},{"href":560,"rel":561},"https://theaudioprogrammer.com/ny-meetup/",[33],[563],{"type":26,"value":564},"his site",{"type":26,"value":47},{"type":21,"tag":186,"props":567,"children":569},{"id":568},"music-tectonics",[570],{"type":26,"value":571},"Music Tectonics",{"type":21,"tag":22,"props":573,"children":574},{},[575],{"type":21,"tag":206,"props":576,"children":579},{"alt":577,"src":578},"Music Tectonics logo","/bporter/2019-4/img/tectonics.jpg",[],{"type":21,"tag":22,"props":581,"children":582},{},[583],{"type":26,"value":584},"28-29 October, Skirball Cultural Center, Los Angeles",{"type":21,"tag":22,"props":586,"children":587},{},[588,590,596,598],{"type":26,"value":589},"We will be attending and exhibiting at the inaugural ",{"type":21,"tag":29,"props":591,"children":594},{"href":592,"rel":593},"https://www.musictectonics.com",[33],[595],{"type":26,"value":571},{"type":26,"value":597}," conference, which looks to be worth the trip just for a panel billed as a ",{"type":21,"tag":29,"props":599,"children":602},{"href":600,"rel":601},"https://sites.grenadine.co/sites/rps/en/music-tectonics/schedule/1658/Blockchain%20Cage%20Match%20with%20NWA's%20Arabian%20Prince:%20Enthusiasts%20and%20Skeptics%20Duke%20It%20Out",[33],[603],{"type":26,"value":604},"\"Blockchain Cage Match.\"",{"title":8,"searchDepth":374,"depth":374,"links":606},[607,608,609,610],{"id":407,"depth":377,"text":410},{"id":462,"depth":377,"text":465},{"id":526,"depth":377,"text":529},{"id":568,"depth":377,"text":571},"content:bporter:2019-4:aesAnnounce.md","bporter/2019-4/aesAnnounce.md","bporter/2019-4/aesAnnounce",{"user":387,"name":388},{"_path":616,"_dir":617,"_draft":7,"_partial":7,"_locale":8,"title":618,"description":619,"excerpt":619,"image":620,"publishDate":621,"tags":622,"body":623,"_type":380,"_id":2366,"_source":382,"_file":2367,"_stem":2368,"_extension":385,"author":2369},"/bporter/2019-3/animator","2019-3","Friz: A flexible animation controller for JUCE","As is often the case, I found myself working on a personal project and had some UI elements that really wanted to have some life to them on the screen.","/bporter/2019-3/img/animator.png","2019-03-01",[14,15,16],{"type":18,"children":624,"toc":2345},[625,637,650,655,668,673,678,683,692,697,713,760,782,788,793,818,823,830,835,840,848,854,875,886,891,901,906,913,923,928,941,949,959,964,972,982,987,992,999,1006,1016,1021,1035,1040,1118,1123,1943,1956,1961,1971,1984,1999,2012,2023,2044,2049,2060,2079,2084,2112,2122,2134,2139,2144,2191,2196,2243,2255,2261,2279,2301,2315,2320,2326,2331,2336,2341],{"type":21,"tag":22,"props":626,"children":627},{},[628,630,635],{"type":26,"value":629},"As is often the case, I found myself working on a personal project and had some UI elements that ",{"type":21,"tag":321,"props":631,"children":632},{},[633],{"type":26,"value":634},"really",{"type":26,"value":636}," wanted to have some life to them on the screen.",{"type":21,"tag":22,"props":638,"children":639},{},[640,642,648],{"type":26,"value":641},"I tucked into the JUCE documentation expecting to see something that I could use to easily add some personality to the interface, and...didn't find what I was looking for. There's a ",{"type":21,"tag":119,"props":643,"children":645},{"className":644},[],[646],{"type":26,"value":647},"ComponentAnimator",{"type":26,"value":649}," class that supports moving a single component from one set of coordinates/bounds to another linearly, and also modify the component's alpha value to have it fade in or out.",{"type":21,"tag":22,"props":651,"children":652},{},[653],{"type":26,"value":654},"I was looking for something...more expressive.",{"type":21,"tag":22,"props":656,"children":657},{},[658,660,666],{"type":26,"value":659},"Earlier this year, I read Ge Wang's book \"Artful Design\" (see my review ",{"type":21,"tag":29,"props":661,"children":664},{"href":662,"rel":663},"https://artandlogic.com/2019/02/book-review-artful-design/",[33],[665],{"type":26,"value":511},{"type":26,"value":667},") and it's occupied a larger than expected chunk of my brain for a long time, especially some of the topics covered there in Chapter 3 on Visual Design.",{"type":21,"tag":22,"props":669,"children":670},{},[671],{"type":26,"value":672},"The ideas presented there on animation and design and interactivity resonated so strongly with me at least partly because I've always been a student and fan of animation as an art form, whether classic-era hand drawn or eventually computer-created. I have vivid memories from my time in college studying to become a composer of the look of shock and disappointment on my professor's face when I told him that most of my thinking about musical structure had its roots in the Warner Bros. cartoons of Chuck Jones.",{"type":21,"tag":22,"props":674,"children":675},{},[676],{"type":26,"value":677},"Somewhere in my house I still have an old copy of the book \"The Illusion of Life,\" written by Frank Thomas and Ollie Johnston, two of Disney's \"Nine Old Men,\" the animators who led the creation of Disney's post-war feature films. In that book they call out some principles that I wanted to be able to express at least in some small ways in my software.",{"type":21,"tag":22,"props":679,"children":680},{},[681],{"type":26,"value":682},"This video is a quick look at them:",{"type":21,"tag":22,"props":684,"children":685},{},[686],{"type":21,"tag":29,"props":687,"children":690},{"href":688,"rel":689},"https://www.youtube.com/watch?v=yiGY0qiy8fY",[33],[691],{"type":26,"value":688},{"type":21,"tag":22,"props":693,"children":694},{},[695],{"type":26,"value":696},"Not all of them are directly applicable to software that's restricting itself to living in a 2D plane, but let's take them as an inspiration, and something to aspire to.",{"type":21,"tag":22,"props":698,"children":699},{},[700,701,706,707,712],{"type":26,"value":61},{"type":21,"tag":29,"props":702,"children":704},{"href":41,"rel":703},[33],[705],{"type":26,"value":67},{"type":26,"value":69},{"type":21,"tag":29,"props":708,"children":710},{"href":72,"rel":709},[33],[711],{"type":26,"value":76},{"type":26,"value":78},{"type":21,"tag":83,"props":714,"children":715},{},[716,724,732,746],{"type":21,"tag":87,"props":717,"children":718},{},[719,723],{"type":21,"tag":91,"props":720,"children":721},{},[722],{"type":26,"value":95},{"type":26,"value":97},{"type":21,"tag":87,"props":725,"children":726},{},[727,731],{"type":21,"tag":91,"props":728,"children":729},{},[730],{"type":26,"value":105},{"type":26,"value":107},{"type":21,"tag":87,"props":733,"children":734},{},[735,739,740,745],{"type":21,"tag":91,"props":736,"children":737},{},[738],{"type":26,"value":115},{"type":26,"value":117},{"type":21,"tag":119,"props":741,"children":743},{"className":742},[],[744],{"type":26,"value":124},{"type":26,"value":126},{"type":21,"tag":87,"props":747,"children":748},{},[749,753,754,759],{"type":21,"tag":91,"props":750,"children":751},{},[752],{"type":26,"value":134},{"type":26,"value":136},{"type":21,"tag":29,"props":755,"children":757},{"href":139,"rel":756},[33],[758],{"type":26,"value":143},{"type":26,"value":47},{"type":21,"tag":22,"props":761,"children":762},{},[763,764,769,770,775,776,781],{"type":26,"value":152},{"type":21,"tag":29,"props":765,"children":767},{"href":155,"rel":766},[33],[768],{"type":26,"value":159},{"type":26,"value":161},{"type":21,"tag":29,"props":771,"children":773},{"href":164,"rel":772},[33],[774],{"type":26,"value":168},{"type":26,"value":170},{"type":21,"tag":29,"props":777,"children":779},{"href":173,"rel":778},[33],[780],{"type":26,"value":177},{"type":26,"value":179},{"type":21,"tag":186,"props":783,"children":785},{"id":784},"orbital-view",[786],{"type":26,"value":787},"Orbital View",{"type":21,"tag":22,"props":789,"children":790},{},[791],{"type":26,"value":792},"At the outermost level, all we want to be able to do is:",{"type":21,"tag":83,"props":794,"children":795},{},[796,801,806],{"type":21,"tag":87,"props":797,"children":798},{},[799],{"type":26,"value":800},"define one or more values that will change from one value to another value...",{"type":21,"tag":87,"props":802,"children":803},{},[804],{"type":26,"value":805},"...over some period of time...",{"type":21,"tag":87,"props":807,"children":808},{},[809,811,816],{"type":26,"value":810},"...using some set of curves that describe ",{"type":21,"tag":321,"props":812,"children":813},{},[814],{"type":26,"value":815},"how",{"type":26,"value":817}," the values change over time.",{"type":21,"tag":22,"props":819,"children":820},{},[821],{"type":26,"value":822},"It's just a question of how to create those pieces and plug them together. We'll start looking at the pieces from the bottom up, with a look at the curves we support, using a demo application that lets us play with things.",{"type":21,"tag":22,"props":824,"children":825},{},[826],{"type":21,"tag":206,"props":827,"children":829},{"alt":828,"src":620},"The Animator",[],{"type":21,"tag":22,"props":831,"children":832},{},[833],{"type":26,"value":834},"The Animator is mostly a blank window that you can click inside to create randomly colored squares that will animate away from the mouse using one of the pre-defined curves. After the animation of a square completes, the square will animate its color to fade away, until it disappears.",{"type":21,"tag":22,"props":836,"children":837},{},[838],{"type":26,"value":839},"The control panel on the right lets you tweak parameters for each of the animation types to explore the different behaviors. The control panel is itself animated:",{"type":21,"tag":22,"props":841,"children":842},{},[843],{"type":21,"tag":206,"props":844,"children":847},{"alt":845,"src":846},"panel","/bporter/2019-3/img/panel.mp4",[],{"type":21,"tag":186,"props":849,"children":851},{"id":850},"available-curves",[852],{"type":26,"value":853},"Available Curves",{"type":21,"tag":22,"props":855,"children":856},{},[857,859,865,867,873],{"type":26,"value":858},"All of the classes that are used to generate animated data are derived from the ",{"type":21,"tag":119,"props":860,"children":862},{"className":861},[],[863],{"type":26,"value":864},"friz::AnimatedValue",{"type":26,"value":866}," class (which you can also derive classes from to define any behavior makes sense for your application). Right now, the following are available as part of the ",{"type":21,"tag":119,"props":868,"children":870},{"className":869},[],[871],{"type":26,"value":872},"friz",{"type":26,"value":874}," module:",{"type":21,"tag":876,"props":877,"children":879},"h3",{"id":878},"constant",[880],{"type":21,"tag":119,"props":881,"children":883},{"className":882},[],[884],{"type":26,"value":885},"Constant",{"type":21,"tag":22,"props":887,"children":888},{},[889],{"type":26,"value":890},"Generates a single value for the duration of the effect. Perhaps it's not obviously useful to be able to generate unchanging values in an animation, this can be useful when building up sequences of multiple effects or when controlling the regeneration of cyclical effects.",{"type":21,"tag":876,"props":892,"children":894},{"id":893},"linear",[895],{"type":21,"tag":119,"props":896,"children":898},{"className":897},[],[899],{"type":26,"value":900},"Linear",{"type":21,"tag":22,"props":902,"children":903},{},[904],{"type":26,"value":905},"Performs a simple linear interpolation between two values over a specified amount of time.",{"type":21,"tag":22,"props":907,"children":908},{},[909],{"type":21,"tag":206,"props":910,"children":912},{"alt":893,"src":911},"/bporter/2019-3/img/linear.mp4",[],{"type":21,"tag":876,"props":914,"children":916},{"id":915},"easein",[917],{"type":21,"tag":119,"props":918,"children":920},{"className":919},[],[921],{"type":26,"value":922},"EaseIn",{"type":21,"tag":22,"props":924,"children":925},{},[926],{"type":26,"value":927},"Accelerates quickly away from the start value, decelerates smoothly into the end value. The amount of time for the animation is not specified, instead your code specifies a tolerance of how close to the end value it needs to be before the effect is complete.",{"type":21,"tag":22,"props":929,"children":930},{},[931,933,939],{"type":26,"value":932},"In his ",{"type":21,"tag":119,"props":934,"children":936},{"className":935},[],[937],{"type":26,"value":938},"Artful Design",{"type":26,"value":940}," book, Dr Wang refers to this as \"Zeno's Interpolator\" because it keeps moving some fraction of the way between the current value and the end value, never quite getting there. Our tolerance argument keeps us from calculating ever smaller slices.",{"type":21,"tag":22,"props":942,"children":943},{},[944],{"type":21,"tag":206,"props":945,"children":948},{"alt":946,"src":947},"easeIn","/bporter/2019-3/img/easeIn.mp4",[],{"type":21,"tag":876,"props":950,"children":952},{"id":951},"easeout",[953],{"type":21,"tag":119,"props":954,"children":956},{"className":955},[],[957],{"type":26,"value":958},"EaseOut",{"type":21,"tag":22,"props":960,"children":961},{},[962],{"type":26,"value":963},"Accelerates slowly away from the start values, accelerates into the end value. Also tolerance-based.",{"type":21,"tag":22,"props":965,"children":966},{},[967],{"type":21,"tag":206,"props":968,"children":971},{"alt":969,"src":970},"easeOut","/bporter/2019-3/img/easeOut.mp4",[],{"type":21,"tag":876,"props":973,"children":975},{"id":974},"spring",[976],{"type":21,"tag":119,"props":977,"children":979},{"className":978},[],[980],{"type":26,"value":981},"Spring",{"type":21,"tag":22,"props":983,"children":984},{},[985],{"type":26,"value":986},"Accelerates away from the start value, and may go past the end value; if so, it does a simplified model of the oscillation of a  dampened spring (...and if I wasn't worried that there might be physics professors reading this I'd insert some text here about Young's Modulus and how that affects the behavior here but instead will point out that this is in no way intended as a realistic physics modeling engine).",{"type":21,"tag":22,"props":988,"children":989},{},[990],{"type":26,"value":991},"A few examples of different damping values:",{"type":21,"tag":22,"props":993,"children":994},{},[995],{"type":21,"tag":206,"props":996,"children":998},{"alt":974,"src":997},"/bporter/2019-3/img/spring1.mp4",[],{"type":21,"tag":22,"props":1000,"children":1001},{},[1002],{"type":21,"tag":206,"props":1003,"children":1005},{"alt":974,"src":1004},"/bporter/2019-3/img/spring2.mp4",[],{"type":21,"tag":876,"props":1007,"children":1009},{"id":1008},"sinusoid",[1010],{"type":21,"tag":119,"props":1011,"children":1013},{"className":1012},[],[1014],{"type":26,"value":1015},"Sinusoid",{"type":21,"tag":22,"props":1017,"children":1018},{},[1019],{"type":26,"value":1020},"Generates sin/cos wave values between any two arbitrary phase points. The data generated is always in the natural (-1.0..+1.0) range of those functions.",{"type":21,"tag":186,"props":1022,"children":1024},{"id":1023},"the-animation-class",[1025,1027,1033],{"type":26,"value":1026},"The ",{"type":21,"tag":119,"props":1028,"children":1030},{"className":1029},[],[1031],{"type":26,"value":1032},"Animation",{"type":26,"value":1034}," class",{"type":21,"tag":22,"props":1036,"children":1037},{},[1038],{"type":26,"value":1039},"In code, the basic process is to",{"type":21,"tag":1041,"props":1042,"children":1043},"ol",{},[1044,1049,1062,1074,1086,1106],{"type":21,"tag":87,"props":1045,"children":1046},{},[1047],{"type":26,"value":1048},"decide how many curves your animation needs -- perhaps one for a control panel opening/closing or a color/alpha change, two for moving a component around, more for changing location/size of a component",{"type":21,"tag":87,"props":1050,"children":1051},{},[1052,1054,1060],{"type":26,"value":1053},"Create ",{"type":21,"tag":119,"props":1055,"children":1057},{"className":1056},[],[1058],{"type":26,"value":1059},"AnimatedValue",{"type":26,"value":1061}," objects of the appropriate types and parameters",{"type":21,"tag":87,"props":1063,"children":1064},{},[1065,1067,1072],{"type":26,"value":1066},"Add those value objects to a new instance of the ",{"type":21,"tag":119,"props":1068,"children":1070},{"className":1069},[],[1071],{"type":26,"value":1032},{"type":26,"value":1073}," class.",{"type":21,"tag":87,"props":1075,"children":1076},{},[1077,1079,1084],{"type":26,"value":1078},"Configure the ",{"type":21,"tag":119,"props":1080,"children":1082},{"className":1081},[],[1083],{"type":26,"value":1032},{"type":26,"value":1085}," appropriately -- usually, this will require you to at least provide a function to call on each frame of the animation.",{"type":21,"tag":87,"props":1087,"children":1088},{},[1089,1091,1096,1098,1104],{"type":26,"value":1090},"Add that ",{"type":21,"tag":119,"props":1092,"children":1094},{"className":1093},[],[1095],{"type":26,"value":1032},{"type":26,"value":1097}," object to the appropriate ",{"type":21,"tag":119,"props":1099,"children":1101},{"className":1100},[],[1102],{"type":26,"value":1103},"Animator",{"type":26,"value":1105}," object, which will start executing the animation.",{"type":21,"tag":87,"props":1107,"children":1108},{},[1109,1111,1116],{"type":26,"value":1110},"When all of the values in the animation are complete, your completion function (if any) will be called, and the ",{"type":21,"tag":119,"props":1112,"children":1114},{"className":1113},[],[1115],{"type":26,"value":1032},{"type":26,"value":1117}," will be deleted.",{"type":21,"tag":22,"props":1119,"children":1120},{},[1121],{"type":26,"value":1122},"An example—this is the code inside the animator demo application that closes the control panel when the mouse is clicked:",{"type":21,"tag":216,"props":1124,"children":1126},{"className":218,"code":1125,"language":220,"meta":8,"style":8},"void MainComponent::ClosePanel()\n{\n   // 1. get parameters in place \n   jassert(PanelState::kOpen == fPanelState);\n   int width = this->getWidth();\n   \n   int startX = fControls->getX();\n   int endX = width - kClosedPanelWidth;\n   \n   float accel = 1.4f;\n   float dampen = 0.4f;\n   \n   // 2. Create a Spring value\n   auto curve = std::make_unique\u003Cfriz::Spring>(startX, endX, 0.5, accel, dampen);\n   \n   // 3. Create an animation and add the curve to it. \n   auto animation = std::make_unique\u003Cfriz::Animation\u003C1>>(\n      friz::Animation\u003C1>::SourceList{std::move(curve)}, 0);\n   \n   // 4. Add a lambda to the animation that will move the panel\n   animation->OnUpdate([=] (int id, const friz::Animation\u003C1>::ValueList& val){\n      fControls->setTopLeftPosition(val[0], 0);\n   });\n   \n   // 5. Add a lambda to call when the effect is complete. \n   animation->OnCompletion([=] (int id) {\n      fPanelState = PanelState::kClosed;\n   });\n   \n   fPanelState = PanelState::kClosing;\n   // 6. Add the animation to the animator, starting it.  \n   fPanelAnimator.AddAnimation(std::move(animation));\n   \n}\n\n",[1127],{"type":21,"tag":119,"props":1128,"children":1129},{"__ignoreMap":8},[1130,1160,1168,1177,1211,1251,1260,1291,1322,1330,1363,1393,1401,1410,1474,1482,1491,1550,1609,1617,1626,1721,1757,1766,1774,1783,1821,1844,1852,1860,1882,1891,1926,1934],{"type":21,"tag":226,"props":1131,"children":1132},{"class":228,"line":229},[1133,1138,1144,1150,1155],{"type":21,"tag":226,"props":1134,"children":1135},{"style":233},[1136],{"type":26,"value":1137},"void",{"type":21,"tag":226,"props":1139,"children":1141},{"style":1140},"--shiki-default:#6F42C1;--shiki-dark:#B392F0",[1142],{"type":26,"value":1143}," MainComponent",{"type":21,"tag":226,"props":1145,"children":1147},{"style":1146},"--shiki-default:#24292E;--shiki-dark:#E1E4E8",[1148],{"type":26,"value":1149},"::",{"type":21,"tag":226,"props":1151,"children":1152},{"style":1140},[1153],{"type":26,"value":1154},"ClosePanel",{"type":21,"tag":226,"props":1156,"children":1157},{"style":1146},[1158],{"type":26,"value":1159},"()\n",{"type":21,"tag":226,"props":1161,"children":1162},{"class":228,"line":377},[1163],{"type":21,"tag":226,"props":1164,"children":1165},{"style":1146},[1166],{"type":26,"value":1167},"{\n",{"type":21,"tag":226,"props":1169,"children":1170},{"class":228,"line":374},[1171],{"type":21,"tag":226,"props":1172,"children":1174},{"style":1173},"--shiki-default:#6A737D;--shiki-dark:#6A737D",[1175],{"type":26,"value":1176},"   // 1. get parameters in place \n",{"type":21,"tag":226,"props":1178,"children":1180},{"class":228,"line":1179},4,[1181,1186,1191,1196,1201,1206],{"type":21,"tag":226,"props":1182,"children":1183},{"style":1140},[1184],{"type":26,"value":1185},"   jassert",{"type":21,"tag":226,"props":1187,"children":1188},{"style":1146},[1189],{"type":26,"value":1190},"(",{"type":21,"tag":226,"props":1192,"children":1193},{"style":1140},[1194],{"type":26,"value":1195},"PanelState",{"type":21,"tag":226,"props":1197,"children":1198},{"style":1146},[1199],{"type":26,"value":1200},"::kOpen ",{"type":21,"tag":226,"props":1202,"children":1203},{"style":233},[1204],{"type":26,"value":1205},"==",{"type":21,"tag":226,"props":1207,"children":1208},{"style":1146},[1209],{"type":26,"value":1210}," fPanelState);\n",{"type":21,"tag":226,"props":1212,"children":1214},{"class":228,"line":1213},5,[1215,1220,1225,1230,1236,1241,1246],{"type":21,"tag":226,"props":1216,"children":1217},{"style":233},[1218],{"type":26,"value":1219},"   int",{"type":21,"tag":226,"props":1221,"children":1222},{"style":1146},[1223],{"type":26,"value":1224}," width ",{"type":21,"tag":226,"props":1226,"children":1227},{"style":233},[1228],{"type":26,"value":1229},"=",{"type":21,"tag":226,"props":1231,"children":1233},{"style":1232},"--shiki-default:#005CC5;--shiki-dark:#79B8FF",[1234],{"type":26,"value":1235}," this",{"type":21,"tag":226,"props":1237,"children":1238},{"style":1146},[1239],{"type":26,"value":1240},"->",{"type":21,"tag":226,"props":1242,"children":1243},{"style":1140},[1244],{"type":26,"value":1245},"getWidth",{"type":21,"tag":226,"props":1247,"children":1248},{"style":1146},[1249],{"type":26,"value":1250},"();\n",{"type":21,"tag":226,"props":1252,"children":1254},{"class":228,"line":1253},6,[1255],{"type":21,"tag":226,"props":1256,"children":1257},{"style":1146},[1258],{"type":26,"value":1259},"   \n",{"type":21,"tag":226,"props":1261,"children":1263},{"class":228,"line":1262},7,[1264,1268,1273,1277,1282,1287],{"type":21,"tag":226,"props":1265,"children":1266},{"style":233},[1267],{"type":26,"value":1219},{"type":21,"tag":226,"props":1269,"children":1270},{"style":1146},[1271],{"type":26,"value":1272}," startX ",{"type":21,"tag":226,"props":1274,"children":1275},{"style":233},[1276],{"type":26,"value":1229},{"type":21,"tag":226,"props":1278,"children":1279},{"style":1146},[1280],{"type":26,"value":1281}," fControls->",{"type":21,"tag":226,"props":1283,"children":1284},{"style":1140},[1285],{"type":26,"value":1286},"getX",{"type":21,"tag":226,"props":1288,"children":1289},{"style":1146},[1290],{"type":26,"value":1250},{"type":21,"tag":226,"props":1292,"children":1294},{"class":228,"line":1293},8,[1295,1299,1304,1308,1312,1317],{"type":21,"tag":226,"props":1296,"children":1297},{"style":233},[1298],{"type":26,"value":1219},{"type":21,"tag":226,"props":1300,"children":1301},{"style":1146},[1302],{"type":26,"value":1303}," endX ",{"type":21,"tag":226,"props":1305,"children":1306},{"style":233},[1307],{"type":26,"value":1229},{"type":21,"tag":226,"props":1309,"children":1310},{"style":1146},[1311],{"type":26,"value":1224},{"type":21,"tag":226,"props":1313,"children":1314},{"style":233},[1315],{"type":26,"value":1316},"-",{"type":21,"tag":226,"props":1318,"children":1319},{"style":1146},[1320],{"type":26,"value":1321}," kClosedPanelWidth;\n",{"type":21,"tag":226,"props":1323,"children":1325},{"class":228,"line":1324},9,[1326],{"type":21,"tag":226,"props":1327,"children":1328},{"style":1146},[1329],{"type":26,"value":1259},{"type":21,"tag":226,"props":1331,"children":1333},{"class":228,"line":1332},10,[1334,1339,1344,1348,1353,1358],{"type":21,"tag":226,"props":1335,"children":1336},{"style":233},[1337],{"type":26,"value":1338},"   float",{"type":21,"tag":226,"props":1340,"children":1341},{"style":1146},[1342],{"type":26,"value":1343}," accel ",{"type":21,"tag":226,"props":1345,"children":1346},{"style":233},[1347],{"type":26,"value":1229},{"type":21,"tag":226,"props":1349,"children":1350},{"style":1232},[1351],{"type":26,"value":1352}," 1.4",{"type":21,"tag":226,"props":1354,"children":1355},{"style":233},[1356],{"type":26,"value":1357},"f",{"type":21,"tag":226,"props":1359,"children":1360},{"style":1146},[1361],{"type":26,"value":1362},";\n",{"type":21,"tag":226,"props":1364,"children":1366},{"class":228,"line":1365},11,[1367,1371,1376,1380,1385,1389],{"type":21,"tag":226,"props":1368,"children":1369},{"style":233},[1370],{"type":26,"value":1338},{"type":21,"tag":226,"props":1372,"children":1373},{"style":1146},[1374],{"type":26,"value":1375}," dampen ",{"type":21,"tag":226,"props":1377,"children":1378},{"style":233},[1379],{"type":26,"value":1229},{"type":21,"tag":226,"props":1381,"children":1382},{"style":1232},[1383],{"type":26,"value":1384}," 0.4",{"type":21,"tag":226,"props":1386,"children":1387},{"style":233},[1388],{"type":26,"value":1357},{"type":21,"tag":226,"props":1390,"children":1391},{"style":1146},[1392],{"type":26,"value":1362},{"type":21,"tag":226,"props":1394,"children":1396},{"class":228,"line":1395},12,[1397],{"type":21,"tag":226,"props":1398,"children":1399},{"style":1146},[1400],{"type":26,"value":1259},{"type":21,"tag":226,"props":1402,"children":1404},{"class":228,"line":1403},13,[1405],{"type":21,"tag":226,"props":1406,"children":1407},{"style":1173},[1408],{"type":26,"value":1409},"   // 2. Create a Spring value\n",{"type":21,"tag":226,"props":1411,"children":1413},{"class":228,"line":1412},14,[1414,1419,1424,1428,1433,1437,1442,1447,1451,1455,1459,1464,1469],{"type":21,"tag":226,"props":1415,"children":1416},{"style":233},[1417],{"type":26,"value":1418},"   auto",{"type":21,"tag":226,"props":1420,"children":1421},{"style":1146},[1422],{"type":26,"value":1423}," curve ",{"type":21,"tag":226,"props":1425,"children":1426},{"style":233},[1427],{"type":26,"value":1229},{"type":21,"tag":226,"props":1429,"children":1430},{"style":1140},[1431],{"type":26,"value":1432}," std",{"type":21,"tag":226,"props":1434,"children":1435},{"style":1146},[1436],{"type":26,"value":1149},{"type":21,"tag":226,"props":1438,"children":1439},{"style":1140},[1440],{"type":26,"value":1441},"make_unique",{"type":21,"tag":226,"props":1443,"children":1444},{"style":1146},[1445],{"type":26,"value":1446},"\u003C",{"type":21,"tag":226,"props":1448,"children":1449},{"style":1140},[1450],{"type":26,"value":872},{"type":21,"tag":226,"props":1452,"children":1453},{"style":1146},[1454],{"type":26,"value":1149},{"type":21,"tag":226,"props":1456,"children":1457},{"style":1140},[1458],{"type":26,"value":981},{"type":21,"tag":226,"props":1460,"children":1461},{"style":1146},[1462],{"type":26,"value":1463},">(startX, endX, ",{"type":21,"tag":226,"props":1465,"children":1466},{"style":1232},[1467],{"type":26,"value":1468},"0.5",{"type":21,"tag":226,"props":1470,"children":1471},{"style":1146},[1472],{"type":26,"value":1473},", accel, dampen);\n",{"type":21,"tag":226,"props":1475,"children":1477},{"class":228,"line":1476},15,[1478],{"type":21,"tag":226,"props":1479,"children":1480},{"style":1146},[1481],{"type":26,"value":1259},{"type":21,"tag":226,"props":1483,"children":1485},{"class":228,"line":1484},16,[1486],{"type":21,"tag":226,"props":1487,"children":1488},{"style":1173},[1489],{"type":26,"value":1490},"   // 3. Create an animation and add the curve to it. \n",{"type":21,"tag":226,"props":1492,"children":1494},{"class":228,"line":1493},17,[1495,1499,1504,1508,1512,1516,1520,1524,1528,1532,1536,1540,1545],{"type":21,"tag":226,"props":1496,"children":1497},{"style":233},[1498],{"type":26,"value":1418},{"type":21,"tag":226,"props":1500,"children":1501},{"style":1146},[1502],{"type":26,"value":1503}," animation ",{"type":21,"tag":226,"props":1505,"children":1506},{"style":233},[1507],{"type":26,"value":1229},{"type":21,"tag":226,"props":1509,"children":1510},{"style":1140},[1511],{"type":26,"value":1432},{"type":21,"tag":226,"props":1513,"children":1514},{"style":1146},[1515],{"type":26,"value":1149},{"type":21,"tag":226,"props":1517,"children":1518},{"style":1140},[1519],{"type":26,"value":1441},{"type":21,"tag":226,"props":1521,"children":1522},{"style":1146},[1523],{"type":26,"value":1446},{"type":21,"tag":226,"props":1525,"children":1526},{"style":1140},[1527],{"type":26,"value":872},{"type":21,"tag":226,"props":1529,"children":1530},{"style":1146},[1531],{"type":26,"value":1149},{"type":21,"tag":226,"props":1533,"children":1534},{"style":1140},[1535],{"type":26,"value":1032},{"type":21,"tag":226,"props":1537,"children":1538},{"style":1146},[1539],{"type":26,"value":1446},{"type":21,"tag":226,"props":1541,"children":1542},{"style":1232},[1543],{"type":26,"value":1544},"1",{"type":21,"tag":226,"props":1546,"children":1547},{"style":1146},[1548],{"type":26,"value":1549},">>(\n",{"type":21,"tag":226,"props":1551,"children":1553},{"class":228,"line":1552},18,[1554,1559,1563,1567,1571,1575,1580,1585,1589,1594,1599,1604],{"type":21,"tag":226,"props":1555,"children":1556},{"style":1140},[1557],{"type":26,"value":1558},"      friz",{"type":21,"tag":226,"props":1560,"children":1561},{"style":1146},[1562],{"type":26,"value":1149},{"type":21,"tag":226,"props":1564,"children":1565},{"style":1140},[1566],{"type":26,"value":1032},{"type":21,"tag":226,"props":1568,"children":1569},{"style":1146},[1570],{"type":26,"value":1446},{"type":21,"tag":226,"props":1572,"children":1573},{"style":1232},[1574],{"type":26,"value":1544},{"type":21,"tag":226,"props":1576,"children":1577},{"style":1146},[1578],{"type":26,"value":1579},">::SourceList{",{"type":21,"tag":226,"props":1581,"children":1582},{"style":1140},[1583],{"type":26,"value":1584},"std",{"type":21,"tag":226,"props":1586,"children":1587},{"style":1146},[1588],{"type":26,"value":1149},{"type":21,"tag":226,"props":1590,"children":1591},{"style":1140},[1592],{"type":26,"value":1593},"move",{"type":21,"tag":226,"props":1595,"children":1596},{"style":1146},[1597],{"type":26,"value":1598},"(curve)}, ",{"type":21,"tag":226,"props":1600,"children":1601},{"style":1232},[1602],{"type":26,"value":1603},"0",{"type":21,"tag":226,"props":1605,"children":1606},{"style":1146},[1607],{"type":26,"value":1608},");\n",{"type":21,"tag":226,"props":1610,"children":1612},{"class":228,"line":1611},19,[1613],{"type":21,"tag":226,"props":1614,"children":1615},{"style":1146},[1616],{"type":26,"value":1259},{"type":21,"tag":226,"props":1618,"children":1620},{"class":228,"line":1619},20,[1621],{"type":21,"tag":226,"props":1622,"children":1623},{"style":1173},[1624],{"type":26,"value":1625},"   // 4. Add a lambda to the animation that will move the panel\n",{"type":21,"tag":226,"props":1627,"children":1629},{"class":228,"line":1628},21,[1630,1635,1640,1645,1649,1654,1659,1665,1670,1675,1680,1684,1688,1692,1696,1701,1706,1711,1716],{"type":21,"tag":226,"props":1631,"children":1632},{"style":1146},[1633],{"type":26,"value":1634},"   animation->",{"type":21,"tag":226,"props":1636,"children":1637},{"style":1140},[1638],{"type":26,"value":1639},"OnUpdate",{"type":21,"tag":226,"props":1641,"children":1642},{"style":1146},[1643],{"type":26,"value":1644},"([",{"type":21,"tag":226,"props":1646,"children":1647},{"style":233},[1648],{"type":26,"value":1229},{"type":21,"tag":226,"props":1650,"children":1651},{"style":1146},[1652],{"type":26,"value":1653},"] (",{"type":21,"tag":226,"props":1655,"children":1656},{"style":233},[1657],{"type":26,"value":1658},"int",{"type":21,"tag":226,"props":1660,"children":1662},{"style":1661},"--shiki-default:#E36209;--shiki-dark:#FFAB70",[1663],{"type":26,"value":1664}," id",{"type":21,"tag":226,"props":1666,"children":1667},{"style":1146},[1668],{"type":26,"value":1669},", ",{"type":21,"tag":226,"props":1671,"children":1672},{"style":233},[1673],{"type":26,"value":1674},"const",{"type":21,"tag":226,"props":1676,"children":1677},{"style":1140},[1678],{"type":26,"value":1679}," friz",{"type":21,"tag":226,"props":1681,"children":1682},{"style":1146},[1683],{"type":26,"value":1149},{"type":21,"tag":226,"props":1685,"children":1686},{"style":1140},[1687],{"type":26,"value":1032},{"type":21,"tag":226,"props":1689,"children":1690},{"style":1146},[1691],{"type":26,"value":1446},{"type":21,"tag":226,"props":1693,"children":1694},{"style":1232},[1695],{"type":26,"value":1544},{"type":21,"tag":226,"props":1697,"children":1698},{"style":1146},[1699],{"type":26,"value":1700},">::",{"type":21,"tag":226,"props":1702,"children":1703},{"style":1140},[1704],{"type":26,"value":1705},"ValueList",{"type":21,"tag":226,"props":1707,"children":1708},{"style":233},[1709],{"type":26,"value":1710},"&",{"type":21,"tag":226,"props":1712,"children":1713},{"style":1661},[1714],{"type":26,"value":1715}," val",{"type":21,"tag":226,"props":1717,"children":1718},{"style":1146},[1719],{"type":26,"value":1720},"){\n",{"type":21,"tag":226,"props":1722,"children":1724},{"class":228,"line":1723},22,[1725,1730,1735,1740,1744,1749,1753],{"type":21,"tag":226,"props":1726,"children":1727},{"style":1146},[1728],{"type":26,"value":1729},"      fControls->",{"type":21,"tag":226,"props":1731,"children":1732},{"style":1140},[1733],{"type":26,"value":1734},"setTopLeftPosition",{"type":21,"tag":226,"props":1736,"children":1737},{"style":1146},[1738],{"type":26,"value":1739},"(val[",{"type":21,"tag":226,"props":1741,"children":1742},{"style":1232},[1743],{"type":26,"value":1603},{"type":21,"tag":226,"props":1745,"children":1746},{"style":1146},[1747],{"type":26,"value":1748},"], ",{"type":21,"tag":226,"props":1750,"children":1751},{"style":1232},[1752],{"type":26,"value":1603},{"type":21,"tag":226,"props":1754,"children":1755},{"style":1146},[1756],{"type":26,"value":1608},{"type":21,"tag":226,"props":1758,"children":1760},{"class":228,"line":1759},23,[1761],{"type":21,"tag":226,"props":1762,"children":1763},{"style":1146},[1764],{"type":26,"value":1765},"   });\n",{"type":21,"tag":226,"props":1767,"children":1769},{"class":228,"line":1768},24,[1770],{"type":21,"tag":226,"props":1771,"children":1772},{"style":1146},[1773],{"type":26,"value":1259},{"type":21,"tag":226,"props":1775,"children":1777},{"class":228,"line":1776},25,[1778],{"type":21,"tag":226,"props":1779,"children":1780},{"style":1173},[1781],{"type":26,"value":1782},"   // 5. Add a lambda to call when the effect is complete. \n",{"type":21,"tag":226,"props":1784,"children":1786},{"class":228,"line":1785},26,[1787,1791,1796,1800,1804,1808,1812,1816],{"type":21,"tag":226,"props":1788,"children":1789},{"style":1146},[1790],{"type":26,"value":1634},{"type":21,"tag":226,"props":1792,"children":1793},{"style":1140},[1794],{"type":26,"value":1795},"OnCompletion",{"type":21,"tag":226,"props":1797,"children":1798},{"style":1146},[1799],{"type":26,"value":1644},{"type":21,"tag":226,"props":1801,"children":1802},{"style":233},[1803],{"type":26,"value":1229},{"type":21,"tag":226,"props":1805,"children":1806},{"style":1146},[1807],{"type":26,"value":1653},{"type":21,"tag":226,"props":1809,"children":1810},{"style":233},[1811],{"type":26,"value":1658},{"type":21,"tag":226,"props":1813,"children":1814},{"style":1661},[1815],{"type":26,"value":1664},{"type":21,"tag":226,"props":1817,"children":1818},{"style":1146},[1819],{"type":26,"value":1820},") {\n",{"type":21,"tag":226,"props":1822,"children":1824},{"class":228,"line":1823},27,[1825,1830,1834,1839],{"type":21,"tag":226,"props":1826,"children":1827},{"style":1146},[1828],{"type":26,"value":1829},"      fPanelState ",{"type":21,"tag":226,"props":1831,"children":1832},{"style":233},[1833],{"type":26,"value":1229},{"type":21,"tag":226,"props":1835,"children":1836},{"style":1140},[1837],{"type":26,"value":1838}," PanelState",{"type":21,"tag":226,"props":1840,"children":1841},{"style":1146},[1842],{"type":26,"value":1843},"::kClosed;\n",{"type":21,"tag":226,"props":1845,"children":1847},{"class":228,"line":1846},28,[1848],{"type":21,"tag":226,"props":1849,"children":1850},{"style":1146},[1851],{"type":26,"value":1765},{"type":21,"tag":226,"props":1853,"children":1855},{"class":228,"line":1854},29,[1856],{"type":21,"tag":226,"props":1857,"children":1858},{"style":1146},[1859],{"type":26,"value":1259},{"type":21,"tag":226,"props":1861,"children":1863},{"class":228,"line":1862},30,[1864,1869,1873,1877],{"type":21,"tag":226,"props":1865,"children":1866},{"style":1146},[1867],{"type":26,"value":1868},"   fPanelState ",{"type":21,"tag":226,"props":1870,"children":1871},{"style":233},[1872],{"type":26,"value":1229},{"type":21,"tag":226,"props":1874,"children":1875},{"style":1140},[1876],{"type":26,"value":1838},{"type":21,"tag":226,"props":1878,"children":1879},{"style":1146},[1880],{"type":26,"value":1881},"::kClosing;\n",{"type":21,"tag":226,"props":1883,"children":1885},{"class":228,"line":1884},31,[1886],{"type":21,"tag":226,"props":1887,"children":1888},{"style":1173},[1889],{"type":26,"value":1890},"   // 6. Add the animation to the animator, starting it.  \n",{"type":21,"tag":226,"props":1892,"children":1894},{"class":228,"line":1893},32,[1895,1900,1905,1909,1913,1917,1921],{"type":21,"tag":226,"props":1896,"children":1897},{"style":1146},[1898],{"type":26,"value":1899},"   fPanelAnimator.",{"type":21,"tag":226,"props":1901,"children":1902},{"style":1140},[1903],{"type":26,"value":1904},"AddAnimation",{"type":21,"tag":226,"props":1906,"children":1907},{"style":1146},[1908],{"type":26,"value":1190},{"type":21,"tag":226,"props":1910,"children":1911},{"style":1140},[1912],{"type":26,"value":1584},{"type":21,"tag":226,"props":1914,"children":1915},{"style":1146},[1916],{"type":26,"value":1149},{"type":21,"tag":226,"props":1918,"children":1919},{"style":1140},[1920],{"type":26,"value":1593},{"type":21,"tag":226,"props":1922,"children":1923},{"style":1146},[1924],{"type":26,"value":1925},"(animation));\n",{"type":21,"tag":226,"props":1927,"children":1929},{"class":228,"line":1928},33,[1930],{"type":21,"tag":226,"props":1931,"children":1932},{"style":1146},[1933],{"type":26,"value":1259},{"type":21,"tag":226,"props":1935,"children":1937},{"class":228,"line":1936},34,[1938],{"type":21,"tag":226,"props":1939,"children":1940},{"style":1146},[1941],{"type":26,"value":1942},"}\n",{"type":21,"tag":22,"props":1944,"children":1945},{},[1946,1948,1954],{"type":26,"value":1947},"Each animation may also be given an optional ",{"type":21,"tag":119,"props":1949,"children":1951},{"className":1950},[],[1952],{"type":26,"value":1953},"id",{"type":26,"value":1955}," value.",{"type":21,"tag":22,"props":1957,"children":1958},{},[1959],{"type":26,"value":1960},"This id will be passed as an argument to the Update and Completion functions registered with the animation, and may also be used to cancel an animation that's in progress.",{"type":21,"tag":876,"props":1962,"children":1964},{"id":1963},"sequence",[1965],{"type":21,"tag":119,"props":1966,"children":1968},{"className":1967},[],[1969],{"type":26,"value":1970},"Sequence",{"type":21,"tag":22,"props":1972,"children":1973},{},[1974,1976,1982],{"type":26,"value":1975},"There's also a separate ",{"type":21,"tag":119,"props":1977,"children":1979},{"className":1978},[],[1980],{"type":26,"value":1981},"friz::Sequence",{"type":26,"value":1983}," class that can hold a series of Animation objects and execute them in order as if they were a single long animation. Here's an example of EaseIn and EaseOut combined into a single effect:",{"type":21,"tag":1985,"props":1986,"children":1988},"h4",{"id":1987},"about-those-lambda-callbacks",[1989,1991,1997],{"type":26,"value":1990},"About Those ",{"type":21,"tag":119,"props":1992,"children":1994},{"className":1993},[],[1995],{"type":26,"value":1996},"lambda",{"type":26,"value":1998}," Callbacks",{"type":21,"tag":22,"props":2000,"children":2001},{},[2002,2004,2011],{"type":26,"value":2003},"You will want to provide at least one (a per-frame callback) and possibly two (an animation complete callback) lambda(s) to each animation you create. The example code in the demo app gives several models for how these functions should be declared and used. If you, like me, have a bit of Unfrozen Caveman Programmer in you, there are tons of references out there on using lambdas in modern C++; my favorite in terms of depth can be found in Meyers' ",{"type":21,"tag":29,"props":2005,"children":2008},{"href":2006,"rel":2007},"https://www.aristeia.com/books.html",[33],[2009],{"type":26,"value":2010},"EffectiveModern C++",{"type":26,"value":47},{"type":21,"tag":22,"props":2013,"children":2014},{},[2015,2016,2021],{"type":26,"value":1026},{"type":21,"tag":91,"props":2017,"children":2018},{},[2019],{"type":26,"value":2020},"per-frame update callback",{"type":26,"value":2022}," will always have two arguments:",{"type":21,"tag":83,"props":2024,"children":2025},{},[2026,2031],{"type":21,"tag":87,"props":2027,"children":2028},{},[2029],{"type":26,"value":2030},"The ID for the animation being performed",{"type":21,"tag":87,"props":2032,"children":2033},{},[2034,2036,2042],{"type":26,"value":2035},"an ",{"type":21,"tag":119,"props":2037,"children":2039},{"className":2038},[],[2040],{"type":26,"value":2041},"std::array",{"type":26,"value":2043}," of float values for this frame.",{"type":21,"tag":22,"props":2045,"children":2046},{},[2047],{"type":26,"value":2048},"Your callback should do whatever it needs to do to implement the effect as quickly as it can—remember that another callback will be coming when the timer elapses again.",{"type":21,"tag":22,"props":2050,"children":2051},{},[2052,2053,2058],{"type":26,"value":1026},{"type":21,"tag":91,"props":2054,"children":2055},{},[2056],{"type":26,"value":2057},"completion",{"type":26,"value":2059}," callback will have a single argument, the ID of the animation being completed.",{"type":21,"tag":22,"props":2061,"children":2062},{},[2063,2065,2070,2072,2077],{"type":26,"value":2064},"Note that if you are combining multiple ",{"type":21,"tag":119,"props":2066,"children":2068},{"className":2067},[],[2069],{"type":26,"value":1032},{"type":26,"value":2071}," objects together into a single ",{"type":21,"tag":119,"props":2073,"children":2075},{"className":2074},[],[2076],{"type":26,"value":1970},{"type":26,"value":2078},", your callbacks will receive updates using the ID assigned to the sequence, not to the individual animation objects.",{"type":21,"tag":22,"props":2080,"children":2081},{},[2082],{"type":26,"value":2083},"You should also be very careful to watch the lifetimes of variables carried inside of the lambda objects via capture. It's tempting to think that \"hey, we're using smart pointers because we're all modern here so object lifetime is handled for us!\"",{"type":21,"tag":22,"props":2085,"children":2086},{},[2087,2089,2094,2096,2102,2104,2110],{"type":26,"value":2088},"That's not always true with constructs like these -- make sure that you puzzle out all the ownership and lifetime issues (and test, test, test!). A good pattern to follow is to make sure that the object that owns the ",{"type":21,"tag":119,"props":2090,"children":2092},{"className":2091},[],[2093],{"type":26,"value":1103},{"type":26,"value":2095}," object driving an animation also owns any ",{"type":21,"tag":119,"props":2097,"children":2099},{"className":2098},[],[2100],{"type":26,"value":2101},"Component",{"type":26,"value":2103}," objects that will be controlled by an animation, and that in the destructor of that object, you ",{"type":21,"tag":119,"props":2105,"children":2107},{"className":2106},[],[2108],{"type":26,"value":2109},"CancelAllAnimations()",{"type":26,"value":2111}," to prevent stray timer updates from trying to update a component that's about to be deleted.",{"type":21,"tag":186,"props":2113,"children":2115},{"id":2114},"the-animator",[2116,2117],{"type":26,"value":1026},{"type":21,"tag":119,"props":2118,"children":2120},{"className":2119},[],[2121],{"type":26,"value":1103},{"type":21,"tag":22,"props":2123,"children":2124},{},[2125,2127,2132],{"type":26,"value":2126},"Your app will need one or more instances of the ",{"type":21,"tag":119,"props":2128,"children":2130},{"className":2129},[],[2131],{"type":26,"value":1103},{"type":26,"value":2133}," object. The easiest approach is likely to be having any component that wants to control some aspect of one or more child components own an Animator.",{"type":21,"tag":22,"props":2135,"children":2136},{},[2137],{"type":26,"value":2138},"To start an animation, pass it to an Animator, which will take ownership of it and control its lifecycle from there. Ordinarily, the animation will run to its completion and be destroyed.",{"type":21,"tag":22,"props":2140,"children":2141},{},[2142],{"type":26,"value":2143},"You may, however, want to explicitly cancel a single animation that's in progress (or perhaps a group of animations). The Animator exposes two methods to cancel in-progress animations:",{"type":21,"tag":216,"props":2145,"children":2147},{"className":218,"code":2146,"language":220,"meta":8,"style":8},"bool Animator::CancelAllAnimations(bool moveToEndPosition)\n",[2148],{"type":21,"tag":119,"props":2149,"children":2150},{"__ignoreMap":8},[2151],{"type":21,"tag":226,"props":2152,"children":2153},{"class":228,"line":229},[2154,2159,2164,2168,2173,2177,2181,2186],{"type":21,"tag":226,"props":2155,"children":2156},{"style":233},[2157],{"type":26,"value":2158},"bool",{"type":21,"tag":226,"props":2160,"children":2161},{"style":1140},[2162],{"type":26,"value":2163}," Animator",{"type":21,"tag":226,"props":2165,"children":2166},{"style":1146},[2167],{"type":26,"value":1149},{"type":21,"tag":226,"props":2169,"children":2170},{"style":1140},[2171],{"type":26,"value":2172},"CancelAllAnimations",{"type":21,"tag":226,"props":2174,"children":2175},{"style":1146},[2176],{"type":26,"value":1190},{"type":21,"tag":226,"props":2178,"children":2179},{"style":233},[2180],{"type":26,"value":2158},{"type":21,"tag":226,"props":2182,"children":2183},{"style":1661},[2184],{"type":26,"value":2185}," moveToEndPosition",{"type":21,"tag":226,"props":2187,"children":2188},{"style":1146},[2189],{"type":26,"value":2190},")\n",{"type":21,"tag":22,"props":2192,"children":2193},{},[2194],{"type":26,"value":2195},"will cancel all animations that are currently executing, optionally advancing them all to their final positions.",{"type":21,"tag":216,"props":2197,"children":2199},{"className":218,"code":2198,"language":220,"meta":8,"style":8},"bool CancelAnimation(int id, bool moveToEndPosition);\n",[2200],{"type":21,"tag":119,"props":2201,"children":2202},{"__ignoreMap":8},[2203],{"type":21,"tag":226,"props":2204,"children":2205},{"class":228,"line":229},[2206,2210,2215,2219,2223,2227,2231,2235,2239],{"type":21,"tag":226,"props":2207,"children":2208},{"style":233},[2209],{"type":26,"value":2158},{"type":21,"tag":226,"props":2211,"children":2212},{"style":1140},[2213],{"type":26,"value":2214}," CancelAnimation",{"type":21,"tag":226,"props":2216,"children":2217},{"style":1146},[2218],{"type":26,"value":1190},{"type":21,"tag":226,"props":2220,"children":2221},{"style":233},[2222],{"type":26,"value":1658},{"type":21,"tag":226,"props":2224,"children":2225},{"style":1661},[2226],{"type":26,"value":1664},{"type":21,"tag":226,"props":2228,"children":2229},{"style":1146},[2230],{"type":26,"value":1669},{"type":21,"tag":226,"props":2232,"children":2233},{"style":233},[2234],{"type":26,"value":2158},{"type":21,"tag":226,"props":2236,"children":2237},{"style":1661},[2238],{"type":26,"value":2185},{"type":21,"tag":226,"props":2240,"children":2241},{"style":1146},[2242],{"type":26,"value":1608},{"type":21,"tag":22,"props":2244,"children":2245},{},[2246,2248,2253],{"type":26,"value":2247},"cancels any animations with an ",{"type":21,"tag":119,"props":2249,"children":2251},{"className":2250},[],[2252],{"type":26,"value":1953},{"type":26,"value":2254}," value that matches the argument. Since there's no requirement that animations use unique id values (or any id at all), you can use this knowledge to group animations together with a shared id value if that is useful to you.",{"type":21,"tag":186,"props":2256,"children":2258},{"id":2257},"technical-details",[2259],{"type":26,"value":2260},"Technical Details",{"type":21,"tag":22,"props":2262,"children":2263},{},[2264,2266,2271,2273,2278],{"type":26,"value":2265},"You can grab the demo application that includes the ",{"type":21,"tag":119,"props":2267,"children":2269},{"className":2268},[],[2270],{"type":26,"value":872},{"type":26,"value":2272}," code from GitHub at ",{"type":21,"tag":29,"props":2274,"children":2276},{"href":356,"rel":2275},[33],[2277],{"type":26,"value":356},{"type":26,"value":47},{"type":21,"tag":22,"props":2280,"children":2281},{},[2282,2284,2291,2293,2299],{"type":26,"value":2283},"If you have ",{"type":21,"tag":29,"props":2285,"children":2288},{"href":2286,"rel":2287},"http://www.doxygen.nl/",[33],[2289],{"type":26,"value":2290},"Doxygen",{"type":26,"value":2292}," installed, you can use the included ",{"type":21,"tag":119,"props":2294,"children":2296},{"className":2295},[],[2297],{"type":26,"value":2298},"doxygen/Doxyfile",{"type":26,"value":2300}," to generate a local copy of HTML documentation that should prove useful.",{"type":21,"tag":22,"props":2302,"children":2303},{},[2304,2306,2313],{"type":26,"value":2305},"It's licensed under the terms of the ",{"type":21,"tag":29,"props":2307,"children":2310},{"href":2308,"rel":2309},"https://github.com/bgporter/animator/blob/master/LICENSE",[33],[2311],{"type":26,"value":2312},"MIT license",{"type":26,"value":2314},"—if it's useful to you, use it as you like. Open source, closed source, commercial, free, whatever, as long as the terms of that license are amenable to you (and perhaps to whoever writes the checks funding your project).",{"type":21,"tag":22,"props":2316,"children":2317},{},[2318],{"type":26,"value":2319},"At some point I will package it up as a JUCE user module to make it easier to work with.",{"type":21,"tag":186,"props":2321,"children":2323},{"id":2322},"aspirations",[2324],{"type":26,"value":2325},"Aspirations",{"type":21,"tag":22,"props":2327,"children":2328},{},[2329],{"type":26,"value":2330},"Part of me felt a strange obligation to say something about how animation is like a seasoning where a little goes a long way, and about the value and importance of subtlety. Part of me actually believes those things.",{"type":21,"tag":22,"props":2332,"children":2333},{},[2334],{"type":26,"value":2335},"A different part of me walks around the show floor at NAMM every January, checking out new music software releases and dies a little inside from the sameness of everything. That part of me is hoping that someone will use this and create something that's way outside the lines.",{"type":21,"tag":22,"props":2337,"children":2338},{},[2339],{"type":26,"value":2340},"Make cool things.",{"type":21,"tag":368,"props":2342,"children":2343},{},[2344],{"type":26,"value":372},{"title":8,"searchDepth":374,"depth":374,"links":2346},[2347,2348,2356,2363,2364,2365],{"id":784,"depth":377,"text":787},{"id":850,"depth":377,"text":853,"children":2349},[2350,2351,2352,2353,2354,2355],{"id":878,"depth":374,"text":885},{"id":893,"depth":374,"text":900},{"id":915,"depth":374,"text":922},{"id":951,"depth":374,"text":958},{"id":974,"depth":374,"text":981},{"id":1008,"depth":374,"text":1015},{"id":1023,"depth":377,"text":2357,"children":2358},"The Animation class",[2359],{"id":1963,"depth":374,"text":1970,"children":2360},[2361],{"id":1987,"depth":1179,"text":2362},"About Those lambda Callbacks",{"id":2114,"depth":377,"text":828},{"id":2257,"depth":377,"text":2260},{"id":2322,"depth":377,"text":2325},"content:bporter:2019-3:animator.md","bporter/2019-3/animator.md","bporter/2019-3/animator",{"user":387,"name":388},{"_path":2371,"_dir":2372,"_draft":7,"_partial":7,"_locale":8,"title":2373,"description":2374,"publishDate":2375,"tags":2376,"image":2380,"excerpt":2374,"body":2381,"_type":380,"_id":2535,"_source":382,"_file":2536,"_stem":2537,"_extension":385,"author":2538},"/bporter/2012-6/dsl","2012-6","Watch Your Language","Interesting to see a theme emerge in my Pinboard account this week -- lots of stuff about the idea of 'programming language'. I've spent the last few weeks preparing to dive back into a personal interactive music project that I've been working on sporadically since I was in graduate school. I had recently realized that the conceptual roadblock I hit before my last hiatus was something that I'd need to address by adding some sort of little programming language into the system. After following Martin Fowler's many blog posts over the years discussing domain specific languages, I finally broke down and bought his book on the topic. It's too early yet for me to have much concrete to say about the book, but I remember getting enough out of those blog posts to be confident that it will be worth the money and time to read.","2012-06-29",[2377,2378,2379],"dsl","erlang","go","/bporter/2012-6/img/dsl.jpg",{"type":18,"children":2382,"toc":2530},[2383,2415,2420,2431,2439,2452,2463,2471,2484,2495,2500],{"type":21,"tag":22,"props":2384,"children":2385},{},[2386,2388,2395,2397,2404,2406,2413],{"type":26,"value":2387},"Interesting to see a theme emerge in my ",{"type":21,"tag":29,"props":2389,"children":2392},{"href":2390,"rel":2391},"http://pinboard.in/u:bgporter",[33],[2393],{"type":26,"value":2394},"Pinboard",{"type":26,"value":2396}," account this week -- lots of stuff about the idea of 'programming language'. I've spent the last few weeks preparing to dive back into a personal interactive music project that I've been working on sporadically since I was in graduate school. I had recently realized that the conceptual roadblock I hit before my last hiatus was something that I'd need to address by adding some sort of little programming language into the system. After following Martin Fowler's many blog posts over the years discussing ",{"type":21,"tag":29,"props":2398,"children":2401},{"href":2399,"rel":2400},"http://martinfowler.com/tags/domain%20specific%20language.html",[33],[2402],{"type":26,"value":2403},"domain specific languages",{"type":26,"value":2405},", I finally broke down and bought his ",{"type":21,"tag":29,"props":2407,"children":2410},{"href":2408,"rel":2409},"http://martinfowler.com/dsl.html",[33],[2411],{"type":26,"value":2412},"book",{"type":26,"value":2414}," on the topic. It's too early yet for me to have much concrete to say about the book, but I remember getting enough out of those blog posts to be confident that it will be worth the money and time to read.",{"type":21,"tag":22,"props":2416,"children":2417},{},[2418],{"type":26,"value":2419},"At the same time, these pertinent posts came through my feeds:",{"type":21,"tag":186,"props":2421,"children":2423},{"id":2422},"false-cognates-and-syntax",[2424],{"type":21,"tag":29,"props":2425,"children":2428},{"href":2426,"rel":2427},"http://www.txt.io/t-2eewd",[33],[2429],{"type":26,"value":2430},"False Cognates and Syntax",{"type":21,"tag":54,"props":2432,"children":2433},{},[2434],{"type":21,"tag":22,"props":2435,"children":2436},{},[2437],{"type":26,"value":2438},"So what is a false cognate? Well consider your reaction if I held something out to you and said, “Gift?” Would you thank me or politely demur? Would your reaction change if you knew I was speaking German? (For those not in on the joke, “gift” in English is a synonym for “present” while in German “Gift” is “poison”.) The confusion of poison for present is an example of a false cognate. In natural language, especially in related languages, false cognates abound.",{"type":21,"tag":22,"props":2440,"children":2441},{},[2442,2444,2450],{"type":26,"value":2443},"Interesting and important thoughts on languages borrowing from each other in deeply confusing ways. The note on Erlang's use of ",{"type":21,"tag":119,"props":2445,"children":2447},{"className":2446},[],[2448],{"type":26,"value":2449},"if",{"type":26,"value":2451}," is especially notable, considering how little concern there seems to have been given to making Erlang's syntax look inviting and comfortable.",{"type":21,"tag":186,"props":2453,"children":2455},{"id":2454},"socio-plt-principles-for-programming-language-adoption",[2456],{"type":21,"tag":29,"props":2457,"children":2460},{"href":2458,"rel":2459},"http://www.eecs.berkeley.edu/~lmeyerov/projects/socioplt/index.html",[33],[2461],{"type":26,"value":2462},"Socio-PLT: Principles for Programming Language Adoption",{"type":21,"tag":54,"props":2464,"children":2465},{},[2466],{"type":21,"tag":22,"props":2467,"children":2468},{},[2469],{"type":26,"value":2470},"This paper presents a survey for programming language adoption principles drawn from various sociological fields. For example, many programming language features provide benefits that programmers cannot directly and immediately observe and therefore may not find compelling. From clean water to safe sex, the health community has long examined how to surmount similar observability barriers. We discuss how principles and techniques drawn from social sciences such as economics, public health, and historical linguistics relate to programming languages. Finally, we examine implications of our approach, such as for the design space of language features and even the expectations of scientific research into programming languages.",{"type":21,"tag":22,"props":2472,"children":2473},{},[2474,2476,2483],{"type":26,"value":2475},"In related news, our grandchildren will still be listening to LISP advocates predicting that the whole world is about to finally understand the beauty and necessity of programming in LISP. They'll also still be arguing about whether or not ",{"type":21,"tag":29,"props":2477,"children":2480},{"href":2478,"rel":2479},"http://c2.com/cgi/wiki?IsSchemeLisp",[33],[2481],{"type":26,"value":2482},"Scheme should be considered a dialect of LISP",{"type":26,"value":47},{"type":21,"tag":186,"props":2485,"children":2487},{"id":2486},"less-is-exponentially-more",[2488],{"type":21,"tag":29,"props":2489,"children":2492},{"href":2490,"rel":2491},"http://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html",[33],[2493],{"type":26,"value":2494},"Less is exponentially more",{"type":21,"tag":22,"props":2496,"children":2497},{},[2498],{"type":26,"value":2499},"Rob Pike from Google talking about patterns of adoption of the Go language, and some thoughts behind the primary design philosophy of the language.",{"type":21,"tag":54,"props":2501,"children":2502},{},[2503,2508,2520,2525],{"type":21,"tag":22,"props":2504,"children":2505},{},[2506],{"type":26,"value":2507},"Python and Ruby programmers come to Go because they don't have to surrender much expressiveness, but gain performance and get to play with concurrency.",{"type":21,"tag":22,"props":2509,"children":2510},{},[2511,2513,2518],{"type":26,"value":2512},"C++ programmers ",{"type":21,"tag":321,"props":2514,"children":2515},{},[2516],{"type":26,"value":2517},"don't",{"type":26,"value":2519}," come to Go because they have fought hard to gain exquisite control of their programming domain, and don't want to surrender any of it. To them, software isn't just about getting the job done, it's about doing it a certain way.",{"type":21,"tag":22,"props":2521,"children":2522},{},[2523],{"type":26,"value":2524},"The issue, then, is that Go's success would contradict their world view.",{"type":21,"tag":22,"props":2526,"children":2527},{},[2528],{"type":26,"value":2529},"And we should have realized that from the beginning. People who are excited about C++11's new features are not going to care about a language that has so much less.  Even if, in the end, it offers so much more.",{"title":8,"searchDepth":374,"depth":374,"links":2531},[2532,2533,2534],{"id":2422,"depth":377,"text":2430},{"id":2454,"depth":377,"text":2462},{"id":2486,"depth":377,"text":2494},"content:bporter:2012-6:dsl.md","bporter/2012-6/dsl.md","bporter/2012-6/dsl",{"user":387,"name":388},{"_path":2540,"_dir":2541,"_draft":7,"_partial":7,"_locale":8,"title":2542,"description":2543,"publishDate":2544,"tags":2545,"image":2548,"excerpt":2543,"body":2549,"_type":380,"_id":2938,"_source":382,"_file":2939,"_stem":2940,"_extension":385,"author":2941},"/bporter/2012-5/improtech","2012-5","ImproTech Paris-New York 2012","Last week, I took a vacation day to attend one day of workshops at NYU as part of ImproTech 2012 Paris-New York That website descibes the event as:","2012-05-24",[2546,2547],"improvisation","music","/bporter/2012-5/img/affichemartin.jpg",{"type":18,"children":2550,"toc":2936},[2551,2565,2622,2627,2635,2656,2679,2684,2705,2719,2732,2737,2752,2766,2778,2801,2823,2835,2847,2859,2871,2876,2905,2917,2931],{"type":21,"tag":22,"props":2552,"children":2553},{},[2554,2556,2563],{"type":26,"value":2555},"Last week, I took a vacation day to attend one day of workshops at NYU as part of ",{"type":21,"tag":29,"props":2557,"children":2560},{"href":2558,"rel":2559},"http://repmus.ircam.fr/improtechpny",[33],[2561],{"type":26,"value":2562},"ImproTech 2012 Paris-New York",{"type":26,"value":2564}," That website descibes the event as:",{"type":21,"tag":54,"props":2566,"children":2567},{},[2568,2596],{"type":21,"tag":22,"props":2569,"children":2570},{},[2571,2572,2582,2584,2588,2590,2595],{"type":26,"value":1026},{"type":21,"tag":91,"props":2573,"children":2574},{},[2575],{"type":21,"tag":29,"props":2576,"children":2579},{"href":2577,"rel":2578,"title":2577},"http://repmus.ircam.fr/improtechpny/",[33],[2580],{"type":26,"value":2581},"ImproTech Paris - NYC 2012",{"type":26,"value":2583}," workshop is dedicated to the exploration of the links between musical ",{"type":21,"tag":91,"props":2585,"children":2586},{},[2587],{"type":26,"value":2546},{"type":26,"value":2589}," and digital ",{"type":21,"tag":91,"props":2591,"children":2592},{},[2593],{"type":26,"value":2594},"technologies",{"type":26,"value":47},{"type":21,"tag":22,"props":2597,"children":2598},{},[2599,2601,2606,2608,2613,2615,2620],{"type":26,"value":2600},"Gathering researchers and artists from both research & creation scenes, it favors the idea of using ",{"type":21,"tag":91,"props":2602,"children":2603},{},[2604],{"type":26,"value":2605},"digital intelligence",{"type":26,"value":2607}," as a source of continuous and sophisticated ",{"type":21,"tag":91,"props":2609,"children":2610},{},[2611],{"type":26,"value":2612},"creation",{"type":26,"value":2614},", in a ",{"type":21,"tag":91,"props":2616,"children":2617},{},[2618],{"type":26,"value":2619},"complex interaction",{"type":26,"value":2621}," with live musicians, as opposed to mere decorative digital effects.",{"type":21,"tag":22,"props":2623,"children":2624},{},[2625],{"type":26,"value":2626},"My academic training is as a composer; my Master's degree was in Electronic/Computer Music, and this was an area where I did some (now very primitive) work. Every few years I pick that project back up and restart it based on what I've learned as a developer since the last time I worked on it, then get distracted by some other project and let it go into hibernation for a while again. I wasn't able to get to either of the concerts or the second day of workshops, but the one day I did attend was a day well spent.",{"type":21,"tag":22,"props":2628,"children":2629},{},[2630],{"type":21,"tag":91,"props":2631,"children":2632},{},[2633],{"type":26,"value":2634},"Some highlights for me:",{"type":21,"tag":22,"props":2636,"children":2637},{},[2638,2645,2647,2654],{"type":21,"tag":29,"props":2639,"children":2642},{"href":2640,"rel":2641},"http://en.wikipedia.org/wiki/George_Lewis_%28trombonist%29",[33],[2643],{"type":26,"value":2644},"George Lewis",{"type":26,"value":2646}," gave a brief keynote for the event, touching on a number of themes that would recur throughout the day, including a bit of history. His 1993 piece/software ",{"type":21,"tag":29,"props":2648,"children":2651},{"href":2649,"rel":2650},"http://www.ubu.com/sound/lewis.html",[33],[2652],{"type":26,"value":2653},"Voyager",{"type":26,"value":2655}," is a classic in the field, and the rest of the day found other presenters citing his work.",{"type":21,"tag":22,"props":2657,"children":2658},{},[2659,2661,2668,2670,2677],{"type":26,"value":2660},"The French philosopher ",{"type":21,"tag":29,"props":2662,"children":2665},{"href":2663,"rel":2664},"http://ens-lyon.academia.edu/PierreSaintGermier",[33],[2666],{"type":26,"value":2667},"Pierre Saint Germier",{"type":26,"value":2669}," spent an hour discussing the queestion of whether it's even possible for computers to improvise. He started the discussion from the 'By Definition Objection' -- since all computers are able to do is deterministically execute the instructions they are programmed with, even in the presence of randomness, you cannot say that they are improvising. Eventually, he worked his way around to what he referred to as a 'retreat position' -- maybe computers can't replicate improvisation, but perhaps they can simulate it, \"and maybe that's good enough for you.\" I'm also having a difficult time reconciling these arguments with the writings of others (like neuroscientist Sam Harris, who has ",{"type":21,"tag":29,"props":2671,"children":2674},{"href":2672,"rel":2673},"http://www.samharris.org/free-will",[33],[2675],{"type":26,"value":2676},"developed a position",{"type":26,"value":2678}," that what we perceive as our own free will is an illusion that's not compatible with the laws of physics).",{"type":21,"tag":22,"props":2680,"children":2681},{},[2682],{"type":26,"value":2683},"After ruminating for a while, I've decided that retreat position is good enough for me, and I don't accept that it's much of a retreat, and that the whole argument depends too much on playing with definitions and semantics. Perhaps the most important lesson I learned is that I don't think I'd make a great philosopher. Also: setting the tone for the rest of the day -- even though the only technology his presentation depended on was a PDF slideshow on a USB drive, it took about 10 minutes for issues with the projector to be worked out.",{"type":21,"tag":22,"props":2685,"children":2686},{},[2687,2694,2696,2703],{"type":21,"tag":29,"props":2688,"children":2691},{"href":2689,"rel":2690},"http://imtr.ircam.fr/imtr/Fr%C3%A9d%C3%A9ric_Bevilacqua",[33],[2692],{"type":26,"value":2693},"Frédéric Bevilacqua",{"type":26,"value":2695}," and ",{"type":21,"tag":29,"props":2697,"children":2700},{"href":2698,"rel":2699},"http://imtr.ircam.fr/imtr/Norbert_Schnell",[33],[2701],{"type":26,"value":2702},"Norbert Schnell",{"type":26,"value":2704},", both from IRCAM, showed work they've been doing with their \"MO: Modular Musical Objects\"  project, providing a gestural interface to sound production.",{"type":21,"tag":22,"props":2706,"children":2707},{},[2708,2710,2717],{"type":26,"value":2709},"[youtube=",{"type":21,"tag":29,"props":2711,"children":2714},{"href":2712,"rel":2713},"http://www.youtube.com/watch?feature=player%5C_embedded&v=Uhps%5C_U2E9OM%5C",[33],[2715],{"type":26,"value":2716},"http://www.youtube.com/watch?feature=player\\_embedded&v=Uhps\\_U2E9OM\\",{"type":26,"value":2718},"]",{"type":21,"tag":22,"props":2720,"children":2721},{},[2722,2724,2731],{"type":26,"value":2723},"[vimeo ",{"type":21,"tag":29,"props":2725,"children":2728},{"href":2726,"rel":2727},"http://vimeo.com/22120867%5C",[33],[2729],{"type":26,"value":2730},"http://vimeo.com/22120867\\",{"type":26,"value":2718},{"type":21,"tag":22,"props":2733,"children":2734},{},[2735],{"type":26,"value":2736},"As part of their presentation, they trained the soccer ball shown in the above \"Urban Musical Game\" Vimeo clip with some new gesture/sound combinations, and tossed it out into the audience. For me, it raised a number of questions on the role of skill and virtuosity in systems like this. I'm not sure to what extent those questions are important, at least at this stage in the development of these systems. I was just proud that as the soccer ball made its way to me in the audience, I represented my 15-year old soccer playing son by using my head, not my hands on the ball.",{"type":21,"tag":22,"props":2738,"children":2739},{},[2740,2742,2750],{"type":26,"value":2741},"After ",{"type":21,"tag":29,"props":2743,"children":2747},{"href":2744,"rel":2745,"title":2746},"http://instagr.am/p/KvGyigxXwr/",[33],"Lunch break!",[2748],{"type":26,"value":2749},"lunch",{"type":26,"value":2751},", the presentations were more music than talk.",{"type":21,"tag":22,"props":2753,"children":2754},{},[2755,2757,2764],{"type":26,"value":2756},"Violinist ",{"type":21,"tag":29,"props":2758,"children":2761},{"href":2759,"rel":2760},"http://www.marikimura.com/Site_2/main.html",[33],[2762],{"type":26,"value":2763},"Mari Kimura",{"type":26,"value":2765}," demonstrated some of her recent work using an augmented violin system that's been developed for her -- sensors on her bow hand track its position and movement and that data is used inside patches running in Max. She emphasized several times how important it is for her as a violinist to not have additional pieces of hardware or controllers onstage with her -- the easy answer to many of these issues would be to put a foot pedal or two on stage, but she refuses to do that. The hand-tracking system is a very elegant (and essentially invisible) solution to the problem. You can get a taste of it here:",{"type":21,"tag":22,"props":2767,"children":2768},{},[2769,2770,2777],{"type":26,"value":2709},{"type":21,"tag":29,"props":2771,"children":2774},{"href":2772,"rel":2773},"http://www.youtube.com/watch?feature=player%5C_embedded&v=Uf7IxTD19eg%5C",[33],[2775],{"type":26,"value":2776},"http://www.youtube.com/watch?feature=player\\_embedded&v=Uf7IxTD19eg\\",{"type":26,"value":2718},{"type":21,"tag":22,"props":2779,"children":2780},{},[2781,2783,2790,2792,2799],{"type":26,"value":2782},"Do check out more of her videos; I especially like ",{"type":21,"tag":29,"props":2784,"children":2787},{"href":2785,"rel":2786},"http://www.youtube.com/watch?v=-9I4ra4B-yg",[33],[2788],{"type":26,"value":2789},"one featuring a duet",{"type":26,"value":2791}," with the ",{"type":21,"tag":29,"props":2793,"children":2796},{"href":2794,"rel":2795},"http://lemurbots.org/about.html",[33],[2797],{"type":26,"value":2798},"LEMUR",{"type":26,"value":2800}," guitarbot that I last saw on Pat Metheny's Orchestrion tour.",{"type":21,"tag":22,"props":2802,"children":2803},{},[2804,2806,2813,2815],{"type":26,"value":2805},"Saxophonist ",{"type":21,"tag":29,"props":2807,"children":2811},{"href":2808,"rel":2809,"title":2810},"http://www.stevelehman.com/html/news.php",[33],"Steve Lehman",[2812],{"type":26,"value":2810},{"type":26,"value":2814}," did a performance of his piece Manifold for Alto Sax and a trio of 'virtual instrumentalists, running in Max/MSP. One of the things I've always liked about his music is his use of meter and tempo to create a wonderfully elastic sense of time, and that was very much present in this piece (modulo some technical problems he spoke about after the performance -- even virtual players can have an off day). Here's a different performance with two additional human performers from the ",{"type":21,"tag":29,"props":2816,"children":2820},{"href":2817,"rel":2818,"title":2819},"http://iceorg.org/",[33],"ICE",[2821],{"type":26,"value":2822},"International Contemporary Ensemble.",{"type":21,"tag":22,"props":2824,"children":2825},{},[2826,2827,2834],{"type":26,"value":2709},{"type":21,"tag":29,"props":2828,"children":2831},{"href":2829,"rel":2830},"http://www.youtube.com/watch?v=ra3flQolnL8&feature=player%5C_embedded%5C",[33],[2832],{"type":26,"value":2833},"http://www.youtube.com/watch?v=ra3flQolnL8&feature=player\\_embedded\\",{"type":26,"value":2718},{"type":21,"tag":22,"props":2836,"children":2837},{},[2838,2845],{"type":21,"tag":29,"props":2839,"children":2842},{"href":2840,"rel":2841},"http://www.m-base.com/",[33],[2843],{"type":26,"value":2844},"Steve Coleman",{"type":26,"value":2846}," (also on alto sax; I've been a huge fan of his writing and playing back to the late 80s) and Gilbert Nouno explained some details of a piece \"Musical Arrythmias\" for sax and electronics that they had performed at the opening night concert the previous night. I wish that I had been able to hear the piece in its entirety, because the fragments were compelling.",{"type":21,"tag":22,"props":2848,"children":2849},{},[2850,2857],{"type":21,"tag":29,"props":2851,"children":2854},{"href":2852,"rel":2853},"http://www.jaimeoliver.pe/",[33],[2855],{"type":26,"value":2856},"Jaime Oliver",{"type":26,"value":2858}," showed a computer vision based instrument developed as an exploration of the space and intersections between instrument design and composition. In his brief talk preceding his demo he outlined the idea of 'Open Scores', where the capabilites and limitations of a system define a space within which a set of musical possibilites may be explored and realized by the human performer who completes the piece by performing it. He showed some video of an earlier system called the Silent Drum:",{"type":21,"tag":22,"props":2860,"children":2861},{},[2862,2863,2870],{"type":26,"value":2709},{"type":21,"tag":29,"props":2864,"children":2867},{"href":2865,"rel":2866},"http://www.youtube.com/watch?v=2kLVqgUMGSU&feature=player%5C_embedded#!%5C",[33],[2868],{"type":26,"value":2869},"http://www.youtube.com/watch?v=2kLVqgUMGSU&feature=player\\_embedded#!\\",{"type":26,"value":2718},{"type":21,"tag":22,"props":2872,"children":2873},{},[2874],{"type":26,"value":2875},"...before doing a live demo of his more recent \"MANO\" instrument.",{"type":21,"tag":54,"props":2877,"children":2878},{},[2879,2890,2895,2900],{"type":21,"tag":22,"props":2880,"children":2881},{},[2882,2883,2888],{"type":26,"value":1026},{"type":21,"tag":321,"props":2884,"children":2885},{},[2886],{"type":26,"value":2887},"MANO C__ontroller",{"type":26,"value":2889}," consists of a black rectangular surface, which is sensed with a video camera. The computer algorithm analyzes the image obtained from the video camera, looking for hands and extracting from them the most relevant parameters, which are then used to control sound.",{"type":21,"tag":22,"props":2891,"children":2892},{},[2893],{"type":26,"value":2894},"One of the most interesting features of the MANO Controller is that it recognizes from which side a hand is entering the rectangle and is able to classify it as a finger or as a hand and to interpolate between them. Any gesture then is classified in terms of the side where it originates (left, right, bottom) and in terms of its size (as a finger or a hand).",{"type":21,"tag":22,"props":2896,"children":2897},{},[2898],{"type":26,"value":2899},"Since a different mapping can be assigned to each combination of side and size (eg. left-finger or bottom-hand) at any given moment there can be 6 different sound mappings. Furthermore, combinations of these (eg. left-finger AND bottom-hand) might lead to a new mapping altogether. The use of these classifications of side and size allow the composer to use them combinatorially, controlling the movement through the score. This allows the performer to change and interpolate between mappings through continuous gestures without the need of using buttons.",{"type":21,"tag":22,"props":2901,"children":2902},{},[2903],{"type":26,"value":2904},"For each hand or finger, multiple parameters are obtained. Most parameters are interdependent, that is, if one parameter changes it usually changes another parameter as well. This is an important feature since it allows for organic behavior of sounds.",{"type":21,"tag":22,"props":2906,"children":2907},{},[2908,2909,2916],{"type":26,"value":2723},{"type":21,"tag":29,"props":2910,"children":2913},{"href":2911,"rel":2912},"http://vimeo.com/10907372%5C",[33],[2914],{"type":26,"value":2915},"http://vimeo.com/10907372\\",{"type":26,"value":2718},{"type":21,"tag":22,"props":2918,"children":2919},{},[2920,2922,2929],{"type":26,"value":2921},"Finally, ",{"type":21,"tag":29,"props":2923,"children":2926},{"href":2924,"rel":2925},"http://marl.smusic.nyu.edu/people/robert-rowe",[33],[2927],{"type":26,"value":2928},"Robert Rowe",{"type":26,"value":2930}," form NYU's Music and Audio Research Lab, whose facility hosted the workshop did a presentation discussing the MARL program and its faculty, all of which were extremely impressive. When the workshops were done, he offered to take anyone interested on a tour of the facility, an offer a few of us took him up on. I had no expectation that he'd remember, but 20 years ago or so I was touring the MIT Media Lab when considering doing PhD work there, and he took me on a similar tour of that facility (including showing me their first NeXT machine, which had just arrived).",{"type":21,"tag":22,"props":2932,"children":2933},{},[2934],{"type":26,"value":2935},"A much better day than I would have had at the office.",{"title":8,"searchDepth":374,"depth":374,"links":2937},[],"content:bporter:2012-5:improtech.md","bporter/2012-5/improtech.md","bporter/2012-5/improtech",{"user":387,"name":388},{"_path":2943,"_dir":2541,"_draft":7,"_partial":7,"_locale":8,"title":2944,"description":2945,"publishDate":2946,"tags":2947,"excerpt":2945,"body":2949,"_type":380,"_id":3081,"_source":382,"_file":3082,"_stem":3083,"_extension":385,"author":3084},"/bporter/2012-5/learntocode","Yes, Do Learn To Code!","My usual pre-work routine is to walk the dog (working at home, this is my counterpart to a commute), pour my first cup of coffee, and then curl up for a little while with Google Reader. I don't know if it's because I've selected feeds that are too closely aligned with my values and personal agenda, but it's really rare that I'll read a post that is just so wrong that it makes me angry. Jeff Atwood wrote a post like that: Please Don't Learn To Code","2012-05-15",[2948],"learn-to-code",{"type":18,"children":2950,"toc":3079},[2951,2963,3005,3010,3015,3020,3035,3040,3045,3062],{"type":21,"tag":22,"props":2952,"children":2953},{},[2954,2956],{"type":26,"value":2955},"My usual pre-work routine is to walk the dog (working at home, this is my counterpart to a commute), pour my first cup of coffee, and then curl up for a little while with Google Reader. I don't know if it's because I've selected feeds that are too closely aligned with my values and personal agenda, but it's really rare that I'll read a post that is just so wrong that it makes me angry. Jeff Atwood wrote a post like that: ",{"type":21,"tag":29,"props":2957,"children":2961},{"href":2958,"rel":2959,"title":2960},"http://www.codinghorror.com/blog/2012/05/please-dont-learn-to-code.html",[33],"Please Don't Learn To Code",[2962],{"type":26,"value":2960},{"type":21,"tag":54,"props":2964,"children":2965},{},[2966,2981],{"type":21,"tag":22,"props":2967,"children":2968},{},[2969],{"type":21,"tag":321,"props":2970,"children":2971},{},[2972,2974,2979],{"type":26,"value":2973},"To those who argue programming is an essential skill we should be teaching our children, right up there with reading, writing, and arithmetic: ",{"type":21,"tag":91,"props":2975,"children":2976},{},[2977],{"type":26,"value":2978},"can you explain to me how Michael Bloomberg would be better at his day to day job of leading the largest city in the USA if he woke up one morning as a crack Java coder?",{"type":26,"value":2980}," It is obvious to me how being a skilled reader, a skilled writer, and at least high school level math are fundamental to performing the job of a politician. Or at any job, for that matter. But understanding variables and functions, pointers and recursion? I can't see it.",{"type":21,"tag":22,"props":2982,"children":2983},{},[2984],{"type":21,"tag":321,"props":2985,"children":2986},{},[2987,2989,2996,2998],{"type":26,"value":2988},"Look, ",{"type":21,"tag":29,"props":2990,"children":2993},{"href":2991,"rel":2992},"http://www.codinghorror.com/blog/2008/12/programming-love-it-or-leave-it.html",[33],[2994],{"type":26,"value":2995},"I love programming",{"type":26,"value":2997},". I also believe programming is important … in the right context, for some people. But so are a lot of skills. I would no more urge everyone to learn programming than I would urge everyone to learn plumbing. ",{"type":21,"tag":29,"props":2999,"children":3002},{"href":3000,"rel":3001},"http://codeyear.com/",[33],[3003],{"type":26,"value":3004},"That'd be ridiculous, right?",{"type":21,"tag":22,"props":3006,"children":3007},{},[3008],{"type":26,"value":3009},"On the contrary: being able to think computationally and algorithmically should be a fundamental skill that's possessed by modern humans, whether it's a skill that they use on a professional basis in their lives or not. Every day I have to deal with a world full of people who show little or no ability to think clearly, and some level of being forced to develop some chunk of code to the point where it works correctly has to be a positive thing for people to know how to do, even if they never do it again.",{"type":21,"tag":22,"props":3011,"children":3012},{},[3013],{"type":26,"value":3014},"When she was in graduate school, my wife had to take a class that required homework to be done in a spreadsheet. I did my best (and failed) to teach her how to use formulas and macros, but then I'd walk back into the room and see her summing columns with a calculator and typing the value into a cell.",{"type":21,"tag":22,"props":3016,"children":3017},{},[3018],{"type":26,"value":3019},"Atwood is right that the goal of programming is to solve a problem, but he makes it sound like that's a dirty thing, and the highest goal of a programmer is to duct tape together pre-existing modules and collect a check. Leaving aside the question of where those modules come from in the first place  (coded up by elves, I suppose) too often that approach leads to systems that are limited to the capabilities of those off the shelf modules and even more limited by the duct tape developers who lack the capability, imagination, time, or foresight to go beyond those limitations. We've made a lot of money over the years gutting and replacing these systems, and maybe even more building systems for clients whose in-house developers told them couldn't be built at all.",{"type":21,"tag":22,"props":3021,"children":3022},{},[3023,3025,3033],{"type":26,"value":3024},"I didn't even intend to write software -- I studied composition in college, and had to learn to write code in C for an electronic music class. It was only after I had enough experience as a developer that I was able to build tools that were a perfect solution to problems that I had as a composer and musician. Learning to program made me a better composer by teaching me a different fundamental modality of thinking, and being a composer has made me a better programmer. If you can successfully write a four voice fugue using common practice harmony, I can teach you to write bulletproof multithreaded code (here's ",{"type":21,"tag":29,"props":3026,"children":3030},{"href":3027,"rel":3028,"title":3029},"http://www.radioworld.com/article/dos-headache-driver-solution/16972",[33],"DOS Headache, Driver Solution ",[3031],{"type":26,"value":3032},"an article",{"type":26,"value":3034}," on one of my first real products that was a multithreaded DOS app that had at the time been running 24/7 for a decade).",{"type":21,"tag":22,"props":3036,"children":3037},{},[3038],{"type":26,"value":3039},"I believe that everyone should learn to write a little code, and play an instrument, and make things out of wood, and tend a garden, and cook, and, yes, do a little plumbing, too. They shouldn't learn these things because they'll use them every day to earn a paycheck, they should learn them because it makes them better thinkers, and better able to take care of themselves. On top of that -- if vast empires were being built on top of plumbing the way that they're being built on software, I'd say that anyone who was happy to ignore it as a black art practiced by wizards was making a big mistake. The value of acquiring a new mode of thinking isn't affected by the fact that most people won't need to use pointers or recursion on a daily basis.",{"type":21,"tag":22,"props":3041,"children":3042},{},[3043],{"type":26,"value":3044},"When my wife and I had our first child, my germ-phobic wife had a very hard time with the pediatrician's assurance that it was okay for our baby to put everything in his mouth, and that doing so was part of how he would learn about the world. I think that the way I learn things is by writing code about them. I don't know if telling people to not explore that is being elitist, or condescending, or what, but it definitely strikes me as being very wrong.",{"type":21,"tag":22,"props":3046,"children":3047},{},[3048,3053,3055],{"type":21,"tag":91,"props":3049,"children":3050},{},[3051],{"type":26,"value":3052},"Edit",{"type":26,"value":3054},": There have been many many other similar responses to Atwood's piece. I think that my favorite one is by Al Sweigart: ",{"type":21,"tag":29,"props":3056,"children":3059},{"href":3057,"rel":3058},"http://inventwithpython.com/blog/2012/05/16/a-modest-proposal-please-dont-learn-to-code-because-it-will-damage-your-tiny-brain/",[33],[3060],{"type":26,"value":3061},"A Modest Proposal: Please Don’t Learn to Code Because It Will Damage Your Tiny Brain",{"type":21,"tag":22,"props":3063,"children":3064},{},[3065,3070,3072],{"type":21,"tag":91,"props":3066,"children":3067},{},[3068],{"type":26,"value":3069},"Edit 2",{"type":26,"value":3071},": ...or a much less snarky one that takes us back to the ancient Greeks from Vivek Haldar (always worth reading): ",{"type":21,"tag":29,"props":3073,"children":3077},{"href":3074,"rel":3075,"title":3076},"http://blog.vivekhaldar.com/post/23430363068/executable-thought",[33],"Executable Thought",[3078],{"type":26,"value":3076},{"title":8,"searchDepth":374,"depth":374,"links":3080},[],"content:bporter:2012-5:learntocode.md","bporter/2012-5/learntocode.md","bporter/2012-5/learntocode",{"user":387,"name":388},{"_path":3086,"_dir":2541,"_draft":7,"_partial":7,"_locale":8,"title":3087,"description":3088,"publishDate":3089,"image":3090,"excerpt":3088,"body":3091,"_type":380,"_id":3168,"_source":382,"_file":3169,"_stem":3170,"_extension":385,"author":3171},"/bporter/2012-5/cd_player","My First CD Player","I started college right about the time when the first CD players were coming onto the market -- there weren't many available, and they were all obscenely expensive. At the time, my dad was dong a lot of traveling to Japan for business, and he was able to bring me a really nice Yamaha CD player back from a shop in Akihabara for about 1/4th of what a similar unit would have cost me here in the US.","2012-05-01","/bporter/2012-5/img/cd_player.jpg",{"type":18,"children":3092,"toc":3166},[3093,3097,3102,3107,3136,3141],{"type":21,"tag":22,"props":3094,"children":3095},{},[3096],{"type":26,"value":3088},{"type":21,"tag":22,"props":3098,"children":3099},{},[3100],{"type":26,"value":3101},"At that point, I only owned two CDs, and was very excited to get everything hooked up to start listening. As I was unboxing the unit, I noticed a strange blue cube at the bottom of the box with a note from my dad, explaining that this Japanese unit was built to run on Japanese 100 volt, 50 Hz AC, not America's 120 volt, 60 Hz electricity. The blue cube converted between the two standards so that the player would run correctly. Everything hooked up quickly, I plopped one of my CDs into the player (and in the subsequent 27 years have used that CD as the first thing to be played in any device I've owned that will play CDs) and it served me well as I built my library.",{"type":21,"tag":22,"props":3103,"children":3104},{},[3105],{"type":26,"value":3106},"...except that one day I walked into my room and the CD loading drawer was scratching in and out randomly and frenetically. I shut it off as quickly as I could, but that was it for the drawer. The player was useless, and one of my few discs was locked inside it -- as long as I didn't want to listen to anything else ever, I was set for life. I called a friend studying electrical engineering who said that he wasn't surprised -- for most gear, that standard adapter would be fine, but instead of nice clean alternating current it had been feeding my player grungy noisy electricity, and eventually that just killed the sensitive electronics in the thing.",{"type":21,"tag":22,"props":3108,"children":3109},{},[3110,3112,3120,3122,3127,3129,3134],{"type":26,"value":3111},"I had forgotten all about that player until the other day -- an email hit my desk from a developer who had been considering applying for a job until he saw our ",{"type":21,"tag":29,"props":3113,"children":3117},{"href":3114,"rel":3115,"title":3116},"https://styleguide.artandlogic.com",[33],"Art & Logic Programming Style Guide",[3118],{"type":26,"value":3119},"programming style guide",{"type":26,"value":3121},", the document that explains to our developers the various details of how we want them to write code for us. This developer was so ",{"type":21,"tag":321,"props":3123,"children":3124},{},[3125],{"type":26,"value":3126},"offended",{"type":26,"value":3128}," by something in there that he couldn't just not apply, he had to make his disgust known to us. I've always thought that the important thing about standards isn't even so much that they're ",{"type":21,"tag":321,"props":3130,"children":3131},{},[3132],{"type":26,"value":3133},"right",{"type":26,"value":3135}," (whatever that might mean in any instance), but that they are standard. I don't care whether we drive on the right or left side of the road as long as we all agree to one or the other. I'd hope that when in the UK I could adapt to the other side of the road, and I've had to use other programming standards at other jobs.",{"type":21,"tag":22,"props":3137,"children":3138},{},[3139],{"type":26,"value":3140},"I sent him a few links that explain the reasoning behind the thing that upset him and wished him luck. I don't know--I like to think that humans are adaptable, but maybe there are people who are for some weird reason hardwired at 100 volts/50Hz.",{"type":21,"tag":22,"props":3142,"children":3143},{},[3144],{"type":21,"tag":321,"props":3145,"children":3146},{},[3147,3148,3155,3157,3164],{"type":26,"value":1190},{"type":21,"tag":29,"props":3149,"children":3152},{"href":3150,"rel":3151},"http://www.flickr.com/photos/acampos/3453297387/sizes/m/in/photostream/",[33],[3153],{"type":26,"value":3154},"image",{"type":26,"value":3156}," by ",{"type":21,"tag":29,"props":3158,"children":3161},{"href":3159,"rel":3160},"http://www.flickr.com/photos/acampos/",[33],[3162],{"type":26,"value":3163},"acampos",{"type":26,"value":3165},")",{"title":8,"searchDepth":374,"depth":374,"links":3167},[],"content:bporter:2012-5:cd_player.md","bporter/2012-5/cd_player.md","bporter/2012-5/cd_player",{"user":387,"name":388},1780330276244]