<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/css" href="https://www.aaron-gustafson.com/c/feed.min.css" ?><feed xmlns="http://www.w3.org/2005/Atom"
      xmlns:amg="https://www.aaron-gustafson.com.com/amg-dtd/"><title>Aaron Gustafson: Content tagged animation</title><subtitle>The latest 20 posts and links tagged animation.</subtitle><id>https://www.aaron-gustafson.com</id><link href="https://www.aaron-gustafson.com/feeds/animation.xml" rel="self"/><link href="https://www.aaron-gustafson.com"/><author><name>Aaron Gustafson</name><uri>https://www.aaron-gustafson.com</uri></author><updated>2025-05-01T21:49:27Z</updated><entry><id>https://www.aaron-gustafson.com/notebook/passing-your-css-theme-to-canvas/</id><title type="html"><![CDATA[✍🏻 Passing Your CSS Theme to `canvas`]]></title><link href="https://www.aaron-gustafson.com/notebook/passing-your-css-theme-to-canvas/" rel="alternate" type="text/html" /><published>2025-05-01T21:49:27Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>While working on a recent project I noticed an issue with a <code>canvas</code>-based audio visualization when I toggled between light and dark modes. When I’d originally set it up I was browsing in dark mode and the light visualization stroke showed up perfectly on the dark background, but it was invisible when viewed using the light theme (which I’d neglected to test). I searched around, but didn’t find any articles on easy ways to make <code>canvas</code> respond nicely to user preferences, so I thought I’d share (in brief) how I solved it.</p><h2 id="the-css-setup" tabindex="-1"><a class="header-anchor" href="#the-css-setup" aria-hidden="true">#</a> The CSS Setup</h2><p>The theming of this particular project uses <a href="https://developer.mozilla.org/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties">CSS custom properties</a>. For simplicty I’m going to set up two named colors and then use two theme-specific custom properties to apply them in the default light theme and the dark theme:</p><pre class="language-css" tabindex="0"><code class="language-css"><span class="token selector">:root</span><span class="token punctuation">{</span><span class="token property">–color-dark</span><span class="token punctuation">:</span> #222<span class="token punctuation">;</span><span class="token property">–color-light</span><span class="token punctuation">:</span><span class="token function">rgba</span><span class="token punctuation">(</span>255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> 0.5<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token property">–color-background</span><span class="token punctuation">:</span><span class="token function">var</span><span class="token punctuation">(</span>–color-light<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token property">–color-foreground</span><span class="token punctuation">:</span><span class="token function">var</span><span class="token punctuation">(</span>–color-dark<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token atrule"><span class="token rule">@media</span><span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span><span class="token punctuation">{</span><span class="token selector">:root</span><span class="token punctuation">{</span><span class="token property">–color-background</span><span class="token punctuation">:</span><span class="token function">var</span><span class="token punctuation">(</span>–color-dark<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token property">–color-foreground</span><span class="token punctuation">:</span><span class="token function">var</span><span class="token punctuation">(</span>–color-light<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h2 id="applying-the-theme-to-canvas" tabindex="-1"><a class="header-anchor" href="#applying-the-theme-to-canvas" aria-hidden="true">#</a> Applying the Theme to Canvas</h2><p>To get the theme into my <code>canvas</code>-related code, I set up a <code>theme</code> object to hold the values:</p><pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">const</span> theme <span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre><p>Next, I wrote a function to pull in the theme colors using <a href="https://developer.mozilla.org/docs/Web/API/Window/getComputedStyle"><code>window.getComputedStyle()</code></a>. After defining the function, I call it immediately to populate the <code>theme</code> object:</p><pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">function</span><span class="token function">importTheme</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>theme<span class="token punctuation">.</span>foreground <span class="token operator">=</span>window<span class="token punctuation">.</span><span class="token function">getComputedStyle</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>documentElement<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getPropertyValue</span><span class="token punctuation">(</span><span class="token string">“–color-foreground”</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">||</span><span class="token string">“black”</span><span class="token punctuation">;</span>theme<span class="token punctuation">.</span>background <span class="token operator">=</span>window<span class="token punctuation">.</span><span class="token function">getComputedStyle</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>documentElement<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getPropertyValue</span><span class="token punctuation">(</span><span class="token string">“–color-background”</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">||</span><span class="token string">“white”</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token function">importTheme</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>I set this up with just two theme colors, but you can import as many (or few) as you like. Be sure to set a sensible default or fallback for each color though, just in case your theme’s custom property names change.</p><p>With this in place, I can set my <code>canvas</code> animation’s colors by referencing them from the <code>theme</code> object. For example:</p><pre class="language-js" tabindex="0"><code class="language-js">context<span class="token punctuation">.</span>fillStyle <span class="token operator">=</span> theme<span class="token punctuation">.</span>foreground<span class="token punctuation">;</span></code></pre><h2 id="keeping-things-in-sync" tabindex="-1"><a class="header-anchor" href="#keeping-things-in-sync" aria-hidden="true">#</a> Keeping Things in Sync</h2><p>The final bit of magic comes when you add an event listener to a <code>MediaQueryList</code>:</p><pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">const</span> mediaQuery <span class="token operator">=</span> window<span class="token punctuation">.</span><span class="token function">matchMedia</span><span class="token punctuation">(</span><span class="token string">“(prefers-color-scheme: dark)”</span><span class="token punctuation">)</span><span class="token punctuation">;</span>mediaQuery<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">“change”</span><span class="token punctuation">,</span> importTheme<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>Here I’ve used <code>matchMedia()</code> to get a <code>MediaQueryList</code> object. Typically we use the <code>matches</code> property of this object to establish whether the media query currently matches or not. A lesser-known option, however, is that you can attach an event listener to it that will be triggered whenever the query’s status changes. So cool! With this in place, the <code>canvas</code> contents will update whenever the user’s theme changes. <a href="#fig-2025-05-01-01">Here’s an example of that</a>:</p><figure id="fig-2025-05-01-01" class="media-container"><p><a href="https://www.youtube.com/watch?v=pALIuO5uHUA">https://www.youtube.com/watch?v=pALIuO5uHUA</a></p><figcaption><p>This video demonstrates how a canvas element rendering a dark sine wave against a light background can miraculously transform into a light sine wave against a dark background using CSS custom properties and a bit of JavaScript.</p></figcaption></figure><h1 id="demo" tabindex="-1"><a class="header-anchor" href="#demo" aria-hidden="true">#</a> Demo</h1><p>I put together <a href="https://codepen.io/aarongustafson/pen/LEEQyqg">a quick demo of this</a> in a fork of <a href="https://codepen.io/alvinshaw/pen/mdEKggg">Alvin Shaw’s Canvas Sine Wave Experiment</a>:</p><figure id="fig-2025-05-01-02" class="media-container"><iframe class="codepen" height="331" style="width:100%;" scrolling="no" title="CodePen Embed" src="https://codepen.io/anon/embed/LEEQyqg?height=331&theme-id=dark&default-tab=result" frameborder="0" loading="lazy" allowtransparency="true" allowfullscreen="true"><p><a href="https://codepen.io/aarongustafson/pen/LEEQyqg" target="_blank" rel="noopener">See the Pen</a></p></iframe></figure><hr><p>Hopefully this is helpful to someone out there. Happy theming!</p>]]></content><amg:twitter><![CDATA[Need to pipe your CSS theme into a `canvas` element? Here’s how I did it.]]></amg:twitter><amg:summary><![CDATA[While working on a recent project I noticed an issue with a <code>canvas</code>-based audio visualization when I toggled between light and dark modes. I couldn’t find any articles on to make <code>canvas</code> respond nicely to user preferences, so I thought I’d share (in brief) how I solved it.]]></amg:summary><summary type="html"><![CDATA[<p>While working on a recent project I noticed an issue with a <code>canvas</code>-based audio visualization when I toggled between light and dark modes. I couldn’t find any articles on to make <code>canvas</code> respond nicely to user preferences, so I thought I’d share (in brief) how I solved it.</p>]]></summary><category term="accessibility" /><category term="animation" /><category term="CSS" /><category term="design" /><category term="JavaScript" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/svg-can-do-that/</id><title type="html"><![CDATA[🔗 SVG can do THAT?!]]></title><link href="https://www.aaron-gustafson.com/notebook/links/svg-can-do-that/" rel="alternate" type="text/html" /><link href="https://slides.com/sdrasner/svg-can-do-that" rel="related" type="text/html" /><published>2017-08-25T19:03:11Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>This is an incredible presentation by <a href="https://sarahdrasnerdesign.com/">Sarah Drasner</a> on many of the very cool things you can do with SVG. So much inspiration!</p>]]></content><amg:twitter><![CDATA[Great presentation by @sarah_edo: SVG can do THAT?!]]></amg:twitter><category term="SVG" /><category term="animation" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://media.slid.es/thumbnails/cff6dcef98b71a676eb9d5e4d2198773/thumb.jpg?373511886" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/integrating-animation-into-a-design-system/</id><title type="html"><![CDATA[🔗 Integrating Animation into a Design System]]></title><link href="https://www.aaron-gustafson.com/notebook/links/integrating-animation-into-a-design-system/" rel="alternate" type="text/html" /><link href="https://alistapart.com/article/integrating-animation-into-a-design-system" rel="related" type="text/html" /><published>2017-08-25T18:35:53Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>An excellent (and exhaustive) look at how how animation can be integrated into style guides and pattern libraries. It includes excellent examples from FutureLearn, Google, Marvel, SalesForce.</p><p>Great work <a href="https://twitter.com/craftui">Alla</a>!</p>]]></content><amg:twitter><![CDATA[Integrating Animation into a Design System by @craftui on @alistapart]]></amg:twitter><category term="user experience" /><category term="animation" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://i0.wp.com/alistapart.com/wp-content/uploads/2019/03/cropped-icon_navigation-laurel-512.jpg?fit=512%2C512&amp;ssl=1" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/we-built-a-chrome-app/</id><title type="html"><![CDATA[✍🏻 We Built a Chrome App]]></title><link href="https://www.aaron-gustafson.com/notebook/we-built-a-chrome-app/" rel="alternate" type="text/html" /><published>2010-12-08T21:47:52Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>Yesterday saw the launch of the <a href="http://chrome.google.com/webstore/">Chrome App Store</a> and, along with it, a Chrome app we created called the <a href="https://chrome.google.com/webstore/detail/ickaeddjnhfofihhibhnjemlphjmnchl">wikiHow Survival Kit</a> (<a href="http://apps.wikihow.com/survivalkit/">also available as a web app</a>).</p><figure><img alt="" src="http://farm6.static.flickr.com/5161/5243360557_1bc20d6e93.jpg"/></figure><p>When we were approached to work on this project several months ago, the specs for the creation of a Chrome app were vague at best. We really had no idea what made a “Chrome app” different from a run-of-the-mill web app or even an HTML5 app. All we knew was that the rendering and JavaScript engines were the same for Chrome apps and web apps, but that Chrome would offer some additional “benefits” to apps built for it. What they were, however, remained a mystery.</p><p>Our client knew they wanted to leverage the bits of HTML5 and CSS3 that Chrome had implemented (and some the Chrome dev team had promised to implement soon, like 3D transforms), but hadn’t really come to any decision on what features would be included, or how the content would be presented. They just knew they wanted it to look amazing.</p><p>After throwing around several real-life metaphors, such as page turns and the like, we settled on the idea of dealing content from a magical deck of “survival cards”. Our goal was to do as much of the animation as possible using <span class="caps">HTML</span> and <span class="caps">CSS</span>, relying on JavaScript only when we absolutely necessary, so we could take advantage of the hardware-accelerated animations Google’s Chrome team promised us would also be available in the browser by the time the app store launched.</p><p>In building this app, we ran Chrome through its paces, uncovering a couple new bugs and pushing the limits of the browser. The project incorporates a lot of cutting-edge tech, including: <span class="caps">CSS</span>-based transforms, transitions and animations; web fonts; a client side database; HTML5 semantics; <code class="js">onHashChange</code> events; and an application manifest. Many of these technologies are still in their infancy and finding a reliable, stable way to work with them has proven quite a challenge, but I think we managed to pull it off with only a handful of newly-gray hairs between us.</p><p>One final issue we ran into was that, when we started this project, you could build and even “compile” a Chrome app, but there was no way to install it because a beta of app store hadn’t even been built yet and was required for installation. We had no way of seeing how a Chrome app would behave differently from a web app. Our questions abounded, but there were few answers to be had. <em>Would there be a location bar? Would there be browser chrome? How would links outside the app function?</em></p><p>We had to bide our time and build the app based on how we <em>thought</em> it would work and hope for the best until the app store was ready and we could actually install the app and test it out. Thankfully, as it turned out, installing the Chrome app didn’t really make it all that different from the web app. The only real difference was that, as a Chrome app, the Survival Kit was given a larger offline cache. Oh, and a smaller tab.</p><p>After the announcement and unveiling of the store yesterday, the interwebs were aflutter with opinions about the significance (or lack thereof) of Google’s choice to create such a store. Sure, the creation of a Chrome app was the impetus for this project, but for us the creation process was exactly the same as we’d use with any project: we built an amazing web app. In truth, I wish we’d had the time and budget to make it usable in any modern browser (unfortunately, that was beyond the scope of our contract), but I am encouraged by the fact that it is available on the web as well, which means you can visit it in any other modern Webkit browser.</p><p>Daniel will be posting a technical round-up of the project in the coming week and he’ll dig into the details of the project a bit more.</p>]]></content><amg:summary><![CDATA[Yesterday saw the launch of the Chrome App Store and, along with it, a Chrome app we created called the wikiHow Survival Kit ( also available as a web app ).]]></amg:summary><summary type="html"><![CDATA[<p>Yesterday saw the launch of the Chrome App Store and, along with it, a Chrome app we created called the wikiHow Survival Kit ( also available as a web app ).</p>]]></summary><category term="browsers" /><category term="CSS" /><category term="animation" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/scroll-and-flash/</id><title type="html"><![CDATA[✍🏻 Scroll and Flash]]></title><link href="https://www.aaron-gustafson.com/notebook/scroll-and-flash/" rel="alternate" type="text/html" /><published>2006-04-28T02:49:28Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>At SXSW, I gave a sneak peek at the <a href="http://www.bizhubpro.com/">new bizhub Pro site I built for Konica Minolta</a> and, in particular, the “scroll and flash” usability enhancement I added to the product pages. I have gotten a lot of questions about it and the technique even generated <a href="http://web.archive.org/web/20080120011442/nubyonrails.com/articles/2006/03/22/yet-another-realigned-theme">some discussion over on Geoffrey’s site</a>. Well, the site finally launched and you can now see the “scroll and flash” for yourself.</p><p><img alt=" " class="focal" src="http://static.flickr.com/51/135882899_26ce7cf8ff_o.png" style="width: 300px;"/></p><p>To check it out, go to a product page (the <a href="http://web.archive.org/web/20071218122253/www.bizhubpro.com/products/920/">bizhub PRO 920</a>, for instance) and click one of the links on the upper right of the focal image and watch the show (or you can <a href="http://web.archive.org/web/20071218122253/www.bizhubpro.com/products/920/">go directly to a bookmark</a>). <abbr title="Asynchronus JavaScript and XML">AJAX</abbr> is used to refresh the page content (with bookmarkable links) and then the “scroll and flash” takes over. Feel free to take a gander at <a href="http://web.archive.org/web/20070406095027/www.bizhubpro.com/scripts/product-pages.js">the <abbr title="JavaScript">JS</abbr> file</a> to see how it’s done.</p><p>I have to give it up to <a href="http://www.shauninman.com">Shaun Inman</a> and <a href="http://script.aculo.us/">Thomas Fuchs</a> as it was their hard work that made this easy for me to do.</p><p><strong>Update:</strong> It looks like someone has not taken proper care in managing these pages since <a href="/notebook/leap/">I left Cronin and Company</a> (where I had built the site), so not all of the links appear to be working (because their anchors have been removed… tsk, tsk). I’ve let Cronin know and hopefully that will be fixed soon.</p>]]></content><amg:summary><![CDATA[At SXSW , I gave a sneak peek at the new bizhub Pro site I built for Konica Minolta and, in particular, the “scroll and flash” usability enhancement I added to the product pages. I have gotten a lot of questions about it and the…]]></amg:summary><summary type="html"><![CDATA[<p>At SXSW , I gave a sneak peek at the new bizhub Pro site I built for Konica Minolta and, in particular, the “scroll and flash” usability enhancement I added to the product pages. I have gotten a lot of questions about it and the…</p>]]></summary><category term="JavaScript" /><category term="animation" /><category term="user experience" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/holiday-greetings-games/</id><title type="html"><![CDATA[✍🏻 Holiday Greetings & Games]]></title><link href="https://www.aaron-gustafson.com/notebook/holiday-greetings-games/" rel="alternate" type="text/html" /><published>2005-12-19T11:20:14Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>This has been one crazy Fall work-wise, so I apologize for the scarcity of posts, but I do have a few holiday treats for you.</p><p>From my day job at <a href="http://www.cronin-co.com">Cronin and Company</a>, we’ve got Cronin’s “<a href="http://www.croninholiday.com">Grab Bag of Goodness</a>.” As with most internal projects, this was a major rush job. I take no credit for the design (which was handed to me with no wiggle room), but when it comes to the CSS and DOM Scripting, that I’ll proudly take credit for. Use the code “9301″ to get in. Of particular note in this piece:</p><ul><li>Taking a page from Dan’s <a href="http://www.simplebits.com/notebook/2005/10/05/bplogos.html">Bulletproof Logos</a>, most all of the text is in (shock) images. Toss in the text as an <code>alt</code> attribute and with images and CSS off, you’re still golden. As this was a one-off, sIFR seemed like overkill.</li><li>Ooh, check out that marquee. Brings back memories, doesn’t it. Well, this one’s a little different. The markup is an <code>ul</code> and each item is a <code>li</code>. CSS makes it all <code>display: inline;</code> and then JavaScript keeps reducing the <code>margin-left</code> of the first <code>li</code> by 2px until the absolute value of it’s <code>margin-left</code> is greater than the <code>li</code>’s width. That <code>li</code> is then plucked from the front of the list and appended to the end. Though I am not a big fan of scrolling marquees, this was a pretty fun experiment. </li><li>Those animated icons you can click to make a donation are actually form controls. Originally, I had made them into custom submit <code>input</code>s, but Safari’s inability to customize certain form controls made me abandon that element in favor of <code>button</code>. It’s a great effect too (<abbr title="in my humble opinion">IMHO</abbr><abbr>).</abbr></li></ul><p>Then there’s the <a href="http://www.easy-designs.net">Easy Designs</a> holiday card. I will spare the commentary on this one with the exception of giving major props to Dave for building the game in a day. I’m pretty darn proud of it, especially since we pretty much went from concept to execution in a matter of days (yeah, procrastination’s a bitch). If you’re interested, you can <a href="http://www.easy-designs.net/holiday/2005/email.html">see a rough approximation of the email that went out</a> (our first <a href="http://www.campaignmonitor.com">Campaign Monitor</a> mailing) or simply <a href="http://www.easy-designs.net/holiday/2005/">play the game</a>.</p>]]></content><amg:summary><![CDATA[This has been one crazy Fall work-wise, so I apologize for the scarcity of posts, but I do have a few holiday treats for you.]]></amg:summary><summary type="html"><![CDATA[<p>This has been one crazy Fall work-wise, so I apologize for the scarcity of posts, but I do have a few holiday treats for you.</p>]]></summary><category term="CSS" /><category term="JavaScript" /><category term="animation" /></entry></feed>