<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Trung. Do Duc</title>
    <atom:link href="https://2dtrung.site/feed.xml" rel="self" type="application/rss+xml" />
    <description>Trung. Do Duc’s Thoughts on Design and the Web</description>
    <language>en-US</language>
    <link>https://2dtrung.site</link>

    <item>
      <title>The nbsp; was breaking after all</title>
      <description><![CDATA[<p>I’d been meaning to migrate <a href="https://2dtrungblog.com">my blog</a> off <a href="https://wordpress.com">wordpress.com</a> for a long time. I set it up in 2009 and while I still love the ease of not having to maintain a Wordpress install, lots of little things were nudging me to move to something else.</p><p>I didn’t have much control over the code, which became less of a positive the more my skills and competing tech advanced. To make the changes I could, I had to pay for a plan and a custom CSS upgrade. It wasn’t a ton of money, but enough to make me question things each time renewal rolled around. And occasionally the theme I was using would get deprecated and I’d need to choose and customize a different one. But moving over a decade of posts was enough work for me to stay put.</p><p>The thing that tipped it ended up being a non-breaking space. It’s always something tiny, right?</p><p>For a long time, Wordpress has injected a <code>&amp;nbsp;</code> between the last two words of longer headlines to avoid a widow if the headline wraps. Not sure for how long or if isolated to wordpress.com, but Wordpress was also injecting the <code>&amp;nbsp;</code> into the <code>&lt;meta name=&quot;twitter:text:title&quot;&gt;</code> for social previews.</p><p>This doesn’t seem to affect things on Twitter, but I’ve moved from Twitter to Mastodon and it does affect things there. The social preview for a recent post was rendering like this on pretty much every Mastodon app I checked:</p><img src='https://2dtrung.site/assets/images/thoughts/nbsp-noooo.jpg' width='1200' height='467' alt='screenshot with social image and the title says “My favorite movies of&nbsp;2022”' /><p>I talked with wordpress.com customer support and a few Wordpress devs on Mastodon. It wasn’t something I could fix on my own, so a bug was filed. I didn’t expect it to be a priority. I really didn’t want my social previews to look like this and it made me not want to post. So that felt like enough reason to move things, at least temporarily.</p><h2>Choosing Eleventy</h2><p>I’d also been meaning to try out <a href="https://www.11ty.dev/">Eleventy (11ty)</a> on a personal project. <a href="https://www.zachleat.com/">Zach Leatherman</a> is the coolest and so many folks I admire sing Eleventy’s praises. Besides not injecting an unremovable <code>&amp;nbsp;</code> into my social previews, Eleventy had some nice benefits:</p><ul><li>Full control over the code and templates</li><li>A static site that will ship way less code to the browser</li><li>Eliminate the additional costs I was paying</li></ul><p>There were a few downsides:</p><ul><li>I’d lose years of comments I didn’t plan to move over (probably fine and I could potentially add Webmentions in the future)</li><li>A bit more friction for posting (Wordpress GUI is nice)</li><li>I’d lose search (more on this later)</li></ul><p>I decided to go for it! <em>/me fist pumping</em></p><h2>The process</h2><p>First I exported my blog content from wordpress.com. They give you a giant XML file. I used <a href="https://daext.com/blog/convert-wordpress-articles-to-markdown/">this article</a> and <a href="https://github.com/lonekorean/wordpress-export-to-markdown">this script</a> to convert the XML to Markdown. Worked great!</p><p>I then started moving the content into <a href="https://github.com/11ty/eleventy-base-blog">eleventy-base-blog</a>. I tried to make it match as closely as possible to my Wordpress template. Wordpress has a bit of a unique vibe so there were a few challenges.</p><h3>URL generation</h3><p>Wordpress generates post URLs with the date and then post title like this <code>/2023/02/23/this-is-the-post-title/</code>. I didn’t want to structure my post directory like this, so I decided to use <a href="https://www.11ty.dev/docs/permalinks/">permalink</a>. The data export did give me a <code>&lt;link&gt;</code> with the full post URL, but I wanted to try and set things up so old and new posts could use the same stuff and I didn’t have to duplicate data in the front matter. I created an Eleventy filter that formatted the <code>date</code> this way:</p>
<pre><code>eleventyConfig.addFilter(&quot;pathDate&quot;, dateObj =&gt; {
  return DateTime.fromJSDate(dateObj, {zone: 'utc'}).toFormat(&quot;yyyy/LL/dd&quot;);
})
</code></pre><p>And then set each post’s front matter like this:</p>
<pre><code>title: This is the post title
date: 2023-02-23
permalink: /{{ date | pathDate }}/{{ title | slug }}/
</code></pre><p>Another thing Wordpress does is make unique slugs for posts with the same titles even if they are posted on different dates. So a post titled <em>Howdy partner</em> might get a URL like <code>/2022/05/06/howdy-partner/</code>. If I published another post a month later also titled <em>Howdy partner</em>, the URL would look like this <code>/2022/06/12/howdy-partner-2/</code>. So I had to manually make sure those posts were accounted for. Something like this:</p><pre><code>permalink: /{{ date | pathDate }}/{{ title | slug }}-2/</code></pre><p>A bit tedious but I got everything working ok.</p><h3>Tags and categories</h3><p>My Wordpress theme was using tags and categories. At one point I think I understood why I made things one or the other. 😅 I ended up consolidating those into just tags and did some cleanup to make things more consistent.</p><h3>YouTube and other embeds</h3><p>The Wordpress data export included YouTube embeds with Wordpress-specific syntax like this: <code>[youtube=http://youtu.be/VGsRedwDK40]</code>. I had to change those to the proper YouTube embeds (and Vimeo, Instagram, etc). Also some of the videos were no longer available so I found some replacements mostly for my own sake.</p><h3>Full post preview</h3><p>I liked the era of Wordpress where the blog index pages showed the entire post content so you didn’t have to click into each post. I got that working in Eleventy by using <a href="https://www.11ty.dev/docs/data-frontmatter-customize/#example-parse-excerpts-from-content">excerpt</a> and just making the entire post the excerpt? Probably a better way to do that but it worked.</p><h3>Dates</h3><p>I ran into the <a href="https://www.11ty.dev/docs/dates/#dates-off-by-one-day">dates off by one day</a> issue in a few places. I do not understand timezones! I ended up setting a date and time value separately in the front matter for new posts (with a 9am my time default) and just left off the time for older posts. That seemed to work for what I was doing. Not sure if I’ll run into any issues later, but so far so good.</p><h3>Moved images</h3><p>This isn’t a Wordpress or Eleventy thing, but another task was moving my images from being hosted on <a href="https://2dtrung.site">my portfolio</a> to being hosted with the blog itself. I had originally set it up that way because I was using FTP at the time (ah, memories) and that was easier than using the Wordpress image uploader. This was a helpful decision years later because I just did a nice file move and path replacement locally and didn’t need to do a big download from wordpress.com.</p><h3>Search</h3><p>Remember when I said I would lose search when I moved to a static site? Well say hello to <a href="https://pagefind.app/">Pagefind</a>! I followed <a href="https://rknight.me/using-pagefind-with-eleventy-for-search/">this handy tutorial by Robb Knight</a> to add Pagefind search to my Eleventy site. Really nice! I tend to think I was the only one using search on my blog but I used it a lot, so happy to have it back in there.</p><h2>What Next?</h2><p>I think I’m going to start moving my portfolio into Eleventy soon. It’s a bit more complicated and has its own decade-long baggage. I’m excited to dig in more and to learn how I could have done things better on the blog. My <a href="https://github.com/2dtrung/2dtrungblog">blog code is on Github</a> if you want to take a peek for whatever reason! Shout at me if anything is wonky.</p><p>Overall things went really well with the blog though. I’m liking the setup and the control it offers and I’m doing the blogging I set out to do. Even if wordpress.com does end up fixing that <code>&amp;nbsp;</code> issue, I don’t think I’ll go back for now. Big thanks to <a href="https://wordpress.com">wordpress.com</a> for serving my blog for so many years! And thanks to <a href="https://www.11ty.dev/">Eleventy</a> and the 11ty community for the great docs and tutorials!</p><p>Check out <a href="https://2dtrungblog.com">my blog</a>, yo! It’s got an <a href="https://2dtrungblog.com/feed/feed.xml">RSS feed</a> too.</p>]]></description>
      <pubDate>Fri, 24 Feb 2023 15:30:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/the-nbsp-was-breaking-after-all/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/the-nbsp-was-breaking-after-all/</guid>
    </item>

    <item>
      <title>Put your name on it</title>
      <description><![CDATA[<p><a href="https://bradfrost.com/blog/post/on-personal-branding/">This 2012 post</a> by Brad Frost was making the rounds and got me thinking about personal branding. I’m someone who gets pretty anxious thinking about how others  P E R C E I V E  me, so it’s been difficult to follow advice on this topic. The thing that worked pretty well for me was this little bit of direction: Put your name on it.</p><p>A small question to ask myself whenever I decide to work on a project or to publish some words: Do I want my name on this? I love how Brad promotes consistency not in what you talk about but in <em>being yourself</em>. This basic yes/no question helps me to sidestep the existential question of “Who am I though?” and to focus on making one decision. It’s a pretty good gut check.</p><p>It’s helped me to not send an unkind tweet or twenty and to say “No” to clients and jobs that made me feel sheepish. It helped push me to be weird and ambitious with my work and—as Brad encouraged—to consistently be myself. And after many years, “a Trung. Do Duc project” started to mean something in my corner of the web and with teams I worked with. My work started to walk me through doors.</p><p>But it doesn’t end there. None of that would matter if I was horrible to work with. “Put your name on it” applies even more to how you treat people. And maybe that’s all a personal brand is anyway: a different term for your reputation.</p><p>There are definitely projects and interactions—especially from early in my career—I wish I could remove my name from. I’ll make mistakes. I’ll change. Each new project, job, and relationship lets me decide what it means to put my name on it.</p>]]></description>
      <pubDate>Tue, 21 Feb 2023 16:45:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/put-your-name-on-it/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/put-your-name-on-it/</guid>
    </item>

    <item>
      <title>Unordered, incomplete list of things I want from a job</title>
      <description><![CDATA[<p>In the last three years I’ve worked for three very different companies. This year the tech industry is laying off thousands. I’ve been thinking a lot about jobs. In rougher times it feels risky to ask a lot from your job, but we should. Especially now. So here’s an unordered, incomplete list of things I want from a job.</p><ul><li>Work that benefits from my specific skills and ideas.</li><li>Work that benefits the people who receive it.</li><li>A salary that enables me to live a comfortable life, to be generous, and to save for retirement.</li><li>The ability to work from the sunny spot of my couch with my dog.</li><li>The ability to take a nap, run errands, or go to the cinema during the workday if I need/want to.</li><li>The flexibility to work in the way I work best and with the tools I choose.</li><li>A team small enough to know everyone personally.</li><li>A team that has fun.</li><li>A team that ships work often.</li><li>The autonomy to make small and big decisions about my work.</li><li>The ability and opportunity to share my work publicly.</li><li>Strategic leadership whose financial decisions I trust.</li><li>Courageous leadership who does the right thing.</li><li>Empathetic leadership who treats people well, even (especially) when it costs the business.</li><li>Good health insurance.</li><li>No implied requirement that I have Opinions™ about specific web technologies or companies.</li><li>Very few meetings, used effectively.</li><li>Encouragement.</li><li>Generosity.</li><li>Perks that enable me to do more with my time.</li><li>The space to be a vulnerable, flawed human.</li><li>Work that requires creativity.</li><li>Work that offers variety.</li><li>Work that makes me come alive.</li></ul>]]></description>
      <pubDate>Wed, 16 Feb 2023 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/unordered-incomplete-list-of-things-i-want-from-a-job/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/unordered-incomplete-list-of-things-i-want-from-a-job/</guid>
    </item>

    <item>
      <title>Case Study: 2dtrung.site 2022 refresh</title>
      <description><![CDATA[<p>For a bit there I wasn’t sure if the refresh was going to happen. Honestly things just weren’t flowing for me and every idea I tried fell flat. Feeling stuck is just the worst, but a nice thing about a deadline is it forces me to make decisions.</p><p>So I decided to pick a couple new CSS features I’ve been meaning to try and focus on those. It feels like we’ve been wanting container queries forever and <code>:has()</code> is the parent selector we’ve wanted even longer. Easy choices.</p><p>To play around with <code>:has()</code>, I wanted there to be some dynamic aspect so containers could <em>sometimes</em> have a child element. Drag and drop felt like a natural mechanism here. I ran through a lot of ideas where maybe you navigate the site by dropping items onto specific containers. Maybe more content or clues/treasures could be revealed that way. What if the website was an escape room?</p><p>I started playing around with a few drag and drop libraries and <a href="https://bevacqua.github.io/dragula/">Dragula</a> seemed like it could do all that I needed. I essentially wanted an inventory of items you could drag and drop onto specific sections of the site to make things happen. I got a small CodePen demo working with the help of my friend Jason (thanks!).</p><p class="codepen" data-height="300" data-slug-hash="zYaJbbv" data-preview="true" data-user="2dtrung" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;"><span>See the Pen <a href="https://codepen.io/2dtrung/pen/zYaJbbv">Drag and drop test</a> by Trung. Do Duc (<a href="https://codepen.io/2dtrung">@2dtrung</a>) on <a href="https://codepen.io">CodePen</a>.</span></p><script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script><p>It was about here that I ran into a pretty big snag. Accessibility-wise drag and drop can be a bit of a nightmare. There’s options for making the interactions usable for screen readers and keyboard-only users but for what I was planning, it would have been <em>rough</em>.</p><p>I didn’t want major navigational and content pieces to be totally inaccessible, so I reduced scope a whole bunch. I decided to make the drag and drop more of an Easter egg, fun enhancement kind of a feature. Content and navigation would stay pretty straightforward. With more time I think I could explore doing something more ambitious and maybe I still will.</p><h2>So what can we do with <code>:has()</code>?</h2><p>Real quick, <code>:has()</code> is a CSS pseudo-class which allows you to select a parent element based on the children it has. So in this example…</p>
<pre><code class="language-html">&lt;section id=&quot;one&quot;&gt;&lt;h2&gt;Hello&lt;/h2&gt;&lt;/section&gt;
&lt;section id=&quot;two&quot;&gt;&lt;h3&gt;Bonjour&lt;/h3&gt;&lt;/section&gt;
</code></pre>
<pre><code class="language-css">section:has(h2) {
  background-color: red;
}
</code></pre><p>…only the first <code>&lt;section&gt;</code> will get a background color of red because it contains an <code>&lt;h2&gt;</code>.</p><p>I still marvel at how dang simple that is now with <code>:has()</code>. Just a gift!</p><p>So with a basic drag and drop, I could selectively give an element a child element. This interaction would allow me to change the parent container or the child’s siblings however I wanted.</p><p>I thought a lot about video games where you collect items and thought it would be fun to bring some ✨magic✨ in the way Super Mario powers up with a mushroom, flower, or leaf.</p><figure><img src='https://2dtrung.site/assets/images/thoughts/case-study-2022-super-mario-power-ups.svg' width='1200' height='600' loading='lazy' class='wide' alt='Super Mario in various stages of transformation' /><figcaption class='footnote'>Super Mario power-ups</figcaption></figure><p>A mushroom felt like a fun option to make things get bigger and oh hey, kind of a great interaction to pair with container queries. Drop a mushroom, the container grows, things change.</p><p>I went through a lot of other ideas like maybe you could drop a key to unlock something or drop a coin like into an arcade cabinet or drop a slice of pizza for whatever reason. With 10-20 drop zones I had planned, the amount of changes I would need to account for started to make me sweat. So I simplified (the theme of this year I think) to a general “magic potion” idea that could affect sections in different ways.</p><figure><img src='https://2dtrung.site/assets/images/thoughts/case-study-2022-icons.svg' width='550' height='100' loading='lazy' class='wide' alt='group of icons: mushroom, potion, eraser, coin, leaf, gem, key, pizza' style='width: 100%' /><figcaption class='footnote'>Some of the icons I started with.</figcaption></figure><h2>Let’s set up Dragula</h2><p><a href="https://bevacqua.github.io/dragula/">Dragula</a> is really nice and was easy for me, a forever JS noob, to get running quickly. I won’t go into too much depth on how Dragula works since their <a href="https://bevacqua.github.io/dragula/">demo</a> and <a href="https://github.com/bevacqua/dragula">README</a> are pretty detailed, but let’s look at the major things I needed to set up.</p><p>One section would be your inventory of drag and drop items and various other sections of the site would be “drop zones” that can accept those items. I called the inventory “loot” and gave it classes <code>container</code> and <code>source</code>. Each item in <code>loot</code> got a class of <code>draggable</code>.</p>
<pre><code class="language-html">&lt;div class=&quot;loot container source&quot; id=&quot;loot&quot;&gt;
  &lt;i class=&quot;draggable mushroom&quot; data-id=&quot;mushroom&quot;&gt;
    &lt;svg/&gt;
  &lt;/i&gt;
  &lt;i class=&quot;draggable potion&quot; data-id=&quot;potion&quot;&gt;
    &lt;svg/&gt;
  &lt;/i&gt;
&lt;/div&gt;
</code></pre><p>(By the way, the code in this case study is simplified a bit for clarity, but you can always look at the code in its complicated glory <a href="https://github.com/2dtrung/2dtrung.site">on GitHub</a>. Also I probably shouldn’t use an <code>&lt;i&gt;</code> here but I that was an artifact of a previous attempt at something I ended up not using and I did not change it!)</p><p>So then every drop zone would get a class of <code>container</code> and <code>dropzone</code>:</p>
<pre><code class="language-html">&lt;nav class=&quot;container dropzone&quot; id=&quot;nav&quot;&gt;
  &lt;!-- nav content --&gt;
&lt;/nav&gt;
&lt;header class=&quot;container dropzone&quot; id=&quot;header&quot;&gt;
  &lt;!-- header content --&gt;
&lt;/header&gt;
</code></pre><p>In the JavaScript, I’d set up Dragula like this:</p>
<pre><code>// page elements that are interactive
var loot = '#loot';
var nav = '#nav';
var header = '#header';

// variable
var containers = [
  document.querySelector(loot),
  document.querySelector(nav),
  document.querySelector(header)
];

// Dragula
var drake = dragula({
  containers: containers,
  removeOnSpill: true,
  direction: 'vertical',
  // loot is the source of draggable items
  moves: function (el, source) {
    return source === document.querySelector(loot)
  },
  // when you drag an item, a copy is made
  copy: function (el, source) {
    return source === document.querySelector(loot)
  },
  // any container will accept items except loot
  accepts: function (el, target) {
    return target !== document.querySelector(loot)
  }
});
</code></pre><p>Two significant settings here are <code>copy</code> which makes it so you never run out of mushrooms or potions in your loot, and <code>accepts</code> which makes it so <code>loot</code> is not a drop zone.</p><p>Now we can drag and drop our items. Again here is a <a href="https://codepen.io/2dtrung/pen/zYaJbbv">CodePen demo</a> and I’ll go into some specific UX details in a bit.</p><h2>Growing in size</h2><p>To start, let’s make the homepage hero illustration grow. The markup for that header looks like this:</p>
<pre><code class="language-html">&lt;header class=&quot;header container dropzone&quot;&gt;
  &lt;div class=&quot;svg&quot;&gt;
    &lt;svg /&gt;
  &lt;/div&gt;
&lt;/header&gt;
</code></pre><p>(The <code>&lt;div class=&quot;svg&quot;&gt;</code> helped to isolate the SVG code from having siblings, which was causing some layout issues for me.)</p><p>I set up the CSS so the height of the SVG is set by a variable.</p>
<pre><code class="language-css">.header {
  --header-height: 410px;
}
.header svg {
  width: auto;
  height: var(--header-height);
}
</code></pre><p>So once we’ve dropped the mushroom into the header:</p>
<pre><code class="language-html">&lt;header class=&quot;header container dropzone&quot;&gt;
  &lt;div class=&quot;svg&quot;&gt;
    &lt;svg /&gt;
  &lt;/div&gt;
  &lt;i class=&quot;draggable mushroom&quot; data-id=&quot;mushroom&quot; /&gt;
&lt;/header&gt;
</code></pre><p>We can change the height of the SVG by using <code>:has()</code>:</p>
<pre><code class="language-css">.header:has(.mushroom:not(.gu-transit)) {
  --header-height: 500px;
}
</code></pre><p>Dragula gives the mushroom a class of <code>gu-transit</code> while it’s being dragged and removes it once it’s been dropped. So this makes the header <code>500px</code> tall when the header has a mushroom and it’s no longer in transit.</p><p>This has the effect of the header zooming in size.</p><video class="wide" width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.site/assets/images/thoughts/case-study-2022-mushroom-header-poster.jpg"><source src="https://2dtrung.site/assets/images/thoughts/case-study-2022-mushroom-header.mp4" type="video/mp4">Sorry, your browser doesn’t support embedded videos.</video><p>Now, what if you drop <em>another</em> mushroom? Would it just grow bigger and bigger forever with every new mushroom? I liked that idea, but also didn’t want the site to ever look too wonky. I decided to account for each drop zone accepting two mushrooms and two potions max.</p><p>So knowing we’ll only have two mushrooms ever in the header, we can use <code>:has()</code> with the general sibling combinator to do that:</p>
<pre><code class="language-css">.header:has(.mushroom ~ .mushroom:not(.gu-transit)) {
  --header-height: 600px;
}
</code></pre><p>This makes the SVG <code>600px</code> tall when the header has two mushrooms that are siblings (again, not in transit).</p><p>To add a bit more fun here, I also set up the illustration to have the Diet Dr. Pepper “grow” as the header grows too. I gave IDs to the artwork layers in the SVG and swap opacity in the same way I set the header height.</p>
<pre><code class="language-css">  .header #soda-can {
    opacity: 1;
  }
  .header #soda-bottle,
  .header #soda-cup {
    opacity: 0;
  }
  .header:has(.mushroom:not(.gu-transit)) #soda-can {
    opacity: 0;
  }
  .header:has(.mushroom:not(.gu-transit)) #soda-bottle {
    opacity: 1;
  }
  .header:has(.mushroom ~ .mushroom:not(.gu-transit)) #soda-bottle {
    opacity: 0;
  }
  .header:has(.mushroom ~ .mushroom:not(.gu-transit)) #soda-cup {
    opacity: 1;
  }
</code></pre>
<img src='https://2dtrung.site/assets/images/thoughts/case-study-2022-sodas.jpg' width='1000' height='476' loading='lazy' alt='a Diet Dr. Pepper soda can, bottle, and Big Gulp' /><p>A few other sections of the site do some growing with mushrooms and I also had fun making my noggin grow on the <a href="https://2dtrung.site/about">about page</a>:</p><video class="wide" width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.site/assets/images/thoughts/case-study-2022-about-poster.jpg"><source src="https://2dtrung.site/assets/images/thoughts/case-study-2022-about.mp4" type="video/mp4">Sorry, your browser doesn’t support embedded videos.</video><h2>Add some container queries</h2><p>Container queries! The loves of my life. With container queries we can make style changes dependent on an element’s dimensions instead of the entire viewport’s. I was excited to try them finally.</p><p>On desktop, the projects on the homepage are laid out in 3-columns. When a project gets a mushroom, it changes to take up 2 columns. With another mushroom, it takes up the whole browser width.</p>
<pre><code class="language-css">.projects {
  display: flex;
  flex-wrap: wrap;
}
.project {
  flex-basis: calc(100% / 3);
}
.project:has(.mushroom:not(.gu-transit)) {
  flex-basis: calc((100% / 3) * 2);
}
.project:has(.mushroom ~ .mushroom:not(.gu-transit)) {
  flex-basis: 100%;
}
</code></pre><p>(I’m using flexbox here so projects grow/shrink as the ones around them grow/shrink.)</p><p>I set up the SVG artwork to have groups that I can show/hide dependent on which containers queries are active. So a group in the SVG would look like this:</p>
<pre><code class="language-svg">&lt;g id=&quot;david7&quot; class=&quot;reveal&quot;&gt;
  &lt;!-- paths here --&gt;
&lt;/g&gt;
</code></pre><p>So for the David Rose project, we can do something like this:</p>
<pre><code class="language-css">.david-rose {
  container-type: inline-size;
}
.reveal {
  opacity: 0;
  transition: opacity 200ms ease-in-out;
}
@container (min-width: 470px) {
  .david-rose #david3,
  .david-rose #david5 {
    opacity: 1;
  }
}
@container (min-width: 750px) {
  .david-rose #david2,
  .david-rose #david6 {
    opacity: 1;
  }
}
@container (min-width: 1100px) {
  .david-rose #david1,
  .david-rose #david {
    opacity: 1;
  }
}
</code></pre><p>And that ends up with this:</p><video class="wide" width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.site/assets/images/thoughts/case-study-2022-david-rose-poster.jpg"><source src="https://2dtrung.site/assets/images/thoughts/case-study-2022-david-rose.mp4" type="video/mp4">Sorry, your browser doesn’t support embedded videos.</video><p>Pretty fun! Each project gets a different treatment, so check ’em out.</p><h2>Fun and color with magic potion</h2><p>The draggable potion works in the same way as the mushroom. Instead of scaling things, the potion brings the illustrations to life with colorful details. There’s a lot happening, but the main technique is setting variables for things like <code>background-color</code> and text <code>color</code> and resetting those values with <code>:has()</code>. Here’s a simplified example:</p>
<pre><code class="language-css">.header {
  --bg-color: #ebecf0;
  --text-color: #14303f;
  color: var(--text-color);
  background-color: var(--bg-color);
}
.header:has(.potion:not(.gu-transit)) {
  --bg-color: #ff5f5f;
  --text-color: white;
}
</code></pre><video class="wide" width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.site/assets/images/thoughts/case-study-2022-header-potion-poster.jpg"><source src="https://2dtrung.site/assets/images/thoughts/case-study-2022-header-potion.mp4" type="video/mp4">Sorry, your browser doesn’t support embedded videos.</video><p>For sections with artwork, I’ve set up the SVG with various classes like <code>fill-blue</code> and <code>fill-yellow</code> depending on what color they should be when the potion is dropped.</p>
<pre><code class="language-css">:root {
  --yellow: #fabb19;
  --blue: #5d73a3;
  --turquoise: #00ced4;
}
.dropzone:has(.potion:not(.gu-transit)) .fill-yellow {
  fill: var(--yellow);
}
.dropzone:has(.potion:not(.gu-transit)) .fill-blue {
  fill: var(--blue);
}
.dropzone:has(.potion:not(.gu-transit)) .fill-turquoise {
  fill: var(--turquoise);
}
</code></pre><p>A few paths get class <code>fill-swap</code> which receives different colors as the background changes with a second potion. Others get special colors depending on whether light or dark mode are active. And there’s also a couple sections (like the homepage hero) that change a bit more. Here’s a quick look at how a few sections change:</p><video class="wide" width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.site/assets/images/thoughts/case-study-2022-home-potions-poster.jpg"><source src="https://2dtrung.site/assets/images/thoughts/case-study-2022-home-potions.mp4" type="video/mp4">Sorry, your browser doesn’t support embedded videos.</video><p>The about page illustration is also a fun one:</p><video class="wide" width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.site/assets/images/thoughts/case-study-2022-about-potion-poster.jpg"><source src="https://2dtrung.site/assets/images/thoughts/case-study-2022-about-potion.mp4" type="video/mp4">Sorry, your browser doesn’t support embedded videos.</video><h2>A few UX details</h2><p>Besides the major drag and drop interactions, there are a few UX considerations needed to polish things:</p><ul><li>When you drag a loot item, you get an outline to indicate where you can drop it. When it’s full (two mushrooms or two potions), you don’t get the outline anymore.</li><li>Mushrooms and potions are restyled as little status dots to show you how many things you’ve dropped.</li></ul><img src="https://2dtrung.site/assets/images/thoughts/case-study-2022-dots.jpg" alt="arrow pointinga at a row of dots in the upper right corner of a section" width="810" height="390" /><ul><li>You can remove loot from a section by dragging and dropping the eraser. You can remove all loot by hitting the reset button in the footer.</li><li>Your dropped loot should retain from visit to visit (using local storage).</li><li>When this refresh was released, <code>:has()</code> and container queries were not supported by all major browsers. The <code>:has()</code> styles are within an <code>@supports</code> at-rule. The container queries simply do not trigger for browsers that don’t support them.</li><li>Because Dragula requires JavaScript, the loot section is removed when you have JavaScript disabled.</li><li>There’s also some subtle style changes between light and dark mode, including different themes for code snippets. I think this might be the first time I like the dark mode theme better.</li></ul><h2>Anything else?</h2><p>I ultimately had a lot of fun with the refresh this year, but gosh I was struggling early on. Probably a few lessons here, but I do appreciate setting deadlines that push me to ship work (even if it’s not quite what I was hoping for).</p><p>I ran into some issues with my Grunt setup this time around and I may do a mid-year update and move things around. I recently moved my <a href="https://2dtrungblog.com/">ancient Wordpress blog</a> I’m trying to revive into <a href="https://www.11ty.dev/">11ty</a> and it was a nice experience.</p><p>I just love the web and I’m really excited to see renewed energy around personal sites this year.</p><p>Thanks for reading! 👋 See you next year.</p>]]></description>
      <pubDate>Tue, 24 Jan 2023 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/case-study-2022-refresh/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/case-study-2022-refresh/</guid>
    </item>

    <item>
      <title>Some things I worked on at Netlify</title>
      <description><![CDATA[<p>I worked at Netlify for just over a year. I had a pretty unique role on the brand team: making creative web projects developers will love. That part was a lot of fun. Netlify ended up not being the place for me longterm, but it was a privilege to work with many talented and caring people there.</p><p>With my memory and Twitter getting worse by the day, I wanted to keep a record here of some Netlify projects I worked on.</p><h2>Dusty Domains</h2><a href="https://dusty.domains"><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/netlify-dusty-domains.png" width="1200" height="630" alt="Dusty Domains: Dust off that unused domain for good"></a><p>For December 2021, the team wanted to challenge developers to make something new and deploy to Netlify. Previous planning centered around the weird web (right up my alley), but they needed a hook.</p><p>I brought the idea of encouraging developers to use those domains they’ve purchased that are sitting around collecting dust. Lauren Sell added the idea of each site contributing some money to charity.</p><p>Nine other companies matched Netlify’s $10k donation and we raised $100k for Code2040, Resilient Coders, STEMTank, and Black Girls Code.</p><p>Visit <a href="https://dusty.domains">dusty.domains</a> to see the sites folks made. And visit <a href="https://thedusting.zone/">thedusting.zone</a> to see the one I made!</p><small>Collaborators: Jason Lengstorf, Charlie Gerard, Phil Hawksworth, Tegan Berry, Lauren Sell,  Prince Wilson, Tara Z. Manicsic</small><hr><h2>Your Year on Netlify</h2><a href="https://your-year-on.netlify.com/"><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/netlify-your-year.png" width="1200" height="630" alt="Your Year on Netlify 2021" loading="lazy"></a><p>Your Year on Netlify is an end-of-year recap. Developers can log in and see their stats for the year (like total number of builds or how many times they deployed on Friday). I designed the UI to mimic the command line to make it a bit more interactive and did some fun ASCII art to support each section.</p><p>Zach Leatherman was really the brains of this operation both coming up with the project idea and developing an open source web component called <a href="https://github.com/zachleat/squirminal/">Squirminal</a> to produce the command line printing effect. And Laurie Voss did a lot of the heavy lifting in gathering and interpreting a huge amount of data.</p><p>Check it out at <a href="https://your-year-on.netlify.com/">your-year-on.netlify.com</a>. You can experience it with or without logging in.</p><small>Collaborators: Zach Leatherman, Laurie Voss, Tegan Berry, Kelly Tenn, Nino Medina, Justin Chuan, Phil Hawksworth</small><hr><h2>Open source, Open hearts</h2><a href="https://oss.love"><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/netlify-oss-love.png" width="1200" height="630" alt="Open Source, Open Hearts: Send a token of appreciation to your favorite OSS developers" loading="lazy"></a><p>For Valentine’s Day 2022, we made <a href="https://oss.love">oss.love</a>: a way to tell open source developers you appreciate them. A Jason Lengstorf idea with Phil Hawksworth execution made for a really fun project.</p><p>I designed the site and created a bunch of valentine cards featuring the cheesiest developer puns I could think of.</p><p>Visit <a href="https://oss.love">oss.love</a> to check them all out—and send one to your fave open source folks.</p><small>Collaborators: Phil Hawksworth, Tegan Berry, Jason Lengstorf</small><hr><h2>New Netlify Drop</h2><a href="https://netlify.com/drop"><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/netlify-drop-og.png" width="1200" height="630" alt="Netlify Drop: Quickly publish your website. Drag &amp; Drop. It’s online." loading="lazy"></a><p>In a cross-team effort, marketing and engineering pushed out a refresh of Netlify Drop. I was especially excited to work on this feature because it’s a super approachable way to publish a website. Drag and drop makes it so easy and feels like magic.</p><p>I worked on bringing the page closer in line with current branding and enhancing the interactions with some fun visuals and CSS animations.</p><p>Try out <a href="https://netlify.com/drop">netlify.com/drop</a>.</p><small>Collaborators: Drew Teller, Visakan Jayakumar, Ryan Bonial, Jen Kagan, Kamilah Jenkins, Jack Brewer</small><hr><h2>Matterday</h2><a href="https://matterday.netlify.com/"><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/netlify-matterday.png" width="1200" height="630" alt="What could you do with an extra day a week? Matterday is the new someday." loading="lazy"></a><p>Research showed that switching to Netlify saved teams a day per week. Jon Meyers from Supabase and I teamed up to make Matterday: a site that asks people to think about and share what they would do with more time.</p><p>I wrote the copy and designed the site with some scrollytelling effects which I wrote about here: <a href="https://2dtrung.site/thoughts/entries/fun-css-only-scrolling-effects-for-matterday">Fun CSS-only scrolling effects for Matterday</a>. Jon built the submission flow and sharing gallery, including an approval process for submissions. He’s awesome.</p><p>Check out <a href="https://matterday.netlify.com/">matterday.netlify.com</a>.</p><small>Collaborators: Jon Meyers (Supabase), Tegan Berry, Stephanie Chung, Netlify Marketing</small><hr><h2>Loading animation</h2><p>For an internal hack day, I created a new loading animation for the Netlify app. The previous version was a spinning logo. It worked, but could be better. With guidance and input from both brand and product design teams, I made this new loader using SVG and CSS animations.</p><p>After it launched a few folks mentioned it was the first time they wished the app loaded slower so they could see more of it.</p><p>I put it on CodePen so folks could watch it loop. 👇</p><p class='codepen' data-height='300' data-default-tab='result' data-slug-hash='oNEjOgW' data-preview='true' data-user='2dtrung' style='height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;'><span>See the Pen <a href='https://codepen.io/2dtrung/pen/oNEjOgW'><Netlify>loading animation prototype</a> by Trung. Do Duc (<a href='https://codepen.io/2dtrung'>@2dtrung</a>)</Netlify><on><a href='https://codepen.io'>CodePen</a>.</span></on></p><script async src='https://cpwebassets.codepen.iohttps://2dtrung.site/assets/embed/ei.js'></script><small>Collaborators: Kristy Marcinova, Diana Perkins, Nathan Rodman, Jason Santa Maria</small><hr><h2>Jamstack Conf</h2><a href="https://jamstack.org/conf"><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/netlify-jamstack-conf.png" width="1200" height="630" alt="Jamstack Conf, 7-8 November 2022, San Francisco and online" loading="lazy"></a><p>A lot of people worked on this project, but I was responsible for the evolution of the site as event details finalized and creating visual pieces ranging from social images to event signange. I also got to work with <a href="http://www.hellophia.com/">Sophia Foster-Dimino</a> who did the amazing illustration work.</p><p>Wish I could have been at the event, but it was cool to see it all come together from afar.</p><p>Visit <a href="https://jamstack.org/conf">jamstack.org/conf</a>.</p><small>Collaborators: Janet Feldman, Amy Prince, Phil Hawksworth, Jason Lengstorf, Ryan Mulligan, Sophia Foster-Dimino (illustration), Netlify Marketing</small><hr><h2>Swag</h2><p>I also occasionally got to work on some swag! Here’s a few.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/netlify-remix-conf-shirt.jpg" width="1200" height="810" alt="navy shirt with a 3x4 grid of diamonds: most are line drawings of CDs, one is the Netlify gem logo, and one is the RemixConf logo" loading="lazy"><figcaption class="footnote">t-shirt for Remix Conf 2022</figcaption><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/netlify-jif-shirt.jpg" width="1200" height="810" alt="navy shirt with the phrase [&amp; array we go]" loading="lazy"><figcaption class="footnote">t-shirt for Jamstack Innovation Fund</figcaption><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/netlify-jamhack-shirt.jpg" width="1200" height="810" alt="dark blue shirt with a geometric logo that says Jamhack 2022" loading="lazy"><figcaption class="footnote">logo &amp; t-shirt for Jamhack week</figcaption><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/netlify-jamstack-shirt.jpg" width="1200" height="810" alt="pink shirt with a riff on famous Thank You grocery bag design: the outlined word Jamstack is repeated down the front with one instance filled in, below it says “Have a nice deploy”" loading="lazy"><figcaption class="footnote">t-shirt for Jamstack Conf</figcaption><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/netlify-jamstack-pins.jpg" width="1200" height="810" alt="mockup of enamel pins and stickers with Netlify and Jamstack themes" loading="lazy"><figcaption class="footnote">pins &amp; stickers for Jamstack Conf</figcaption>]]></description>
      <pubDate>Tue, 22 Nov 2022 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/some-things-i-worked-on-at-netlify/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/some-things-i-worked-on-at-netlify/</guid>
    </item>

    <item>
      <title>Fun CSS-only scrolling effects for Matterday</title>
      <description><![CDATA[<p>Last week my team launched a li’l project called <a href="https://matterday.netlify.com/">Matterday</a>. Turns out switching to Netlify saves development teams one day a week <em>per developer</em>. That’s a lot of time! And we hope folks can spend that time on things that matter to them.</p>
<p>The narrative portion of the site encourages folks to imagine what they could do with that time — whether it be small changes to daily routines or taking big swings. As you know, a narrative-heavy website is just begging for some fun scrolling effects. And since I’m me, I wanted to see what I could do with just CSS.</p>
<p>I started with a concept I used for <a href="https://web.archive.org/web/20200423144745/https://andyet.com/">a previous version of andyet.com</a> that utilized fixed positioning and z-index to create layered scrolling artwork.</p>
<video width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/andyet-yeti-video-poster.jpg">
  <source src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/andyet-yeti-optimized.mp4" type="video/mp4">
  Sorry, your browser doesn’t support embedded videos.
</video>
<p>This time around I wanted to explore the idea of layers obscuring and revealing things to create different illusions and to experiment with scroll speeds.</p>
<h2>Creating HTML and CSS layers</h2>
<p>With CSS alone you can’t inform the page where you are with things like scroll position and triggers (not yet anyway). Elements can’t be told how to change; they are effectively in one state forever. You could technically have elements animating on a loop, but you wouldn’t be able to control <em>when</em> in the sequence someone might have it visible in their viewport. So creative layering is the path I took to try and bring some additional interest to static visuals.</p>
<p>The structure of the page can be simplified down to three main layers: <code>.background</code>, <code>.overlay</code>, and <code>.foreground</code> layers. The overlay layer includes the rounded rectangle “viewport” on the left. The background layer includes the patterned backgrounds that show through the viewport layer plus the copy on the right. And finally the foreground includes the pieces of artwork that scroll on top of both previous layers.</p>
<figure>
  <img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/diagram-layers.jpg' width='1385' height='695' alt='an annotation labeling the background, overlay, and foreground layers' loading='lazy' />
</figure>
<figure>
  <img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/diagram-layers2.jpg' width='1385' height='695' alt='an isomorphic diagram of the layers' loading='lazy' />
</figure>
<p>The background layer is split into two halves, with the background artwork on the left and copy on the right. The markup looks like this:</p>
<pre><code class="language-html">&lt;section class=&quot;the-office&quot;&gt;
  &lt;div class=&quot;background&quot;&gt;
    &lt;div class=&quot;background-container&quot;&gt;
      &lt;div class=&quot;background-artwork&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;content&quot;&gt;
      &lt;h3&gt;Watch all 9 seasons of &lt;em&gt;The Office&lt;/em&gt; four times through.&lt;/h3&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/section&gt;
</code></pre>
<p>And is rendered like this (shown here with overlay and foreground hidden):</p>
<figure>
  <img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/diagram-background.jpg' width='1385' height='695' alt='the site divided in two halves, image on left and text on right' loading='lazy' />
</figure>
<p>I keep adding sections and they create a long page you can scroll through like you would expect:</p>
<video width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/stacked-sections-video-poster.jpg">
  <source src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/stacked-sections-optimized.mp4" type="video/mp4">
  Sorry, your browser doesn’t support embedded videos.
</video>
<p>The overlay is made of two nested <code>&lt;div&gt;</code>s. The <code>.overlay</code> container has a <code>position: sticky</code> so it stays fixed to the top even as its container scrolls. It uses <code>linear-gradient</code> (shown in the screenshot in red) to obscure the areas above and below the “viewport” and the <code>&lt;div&gt;</code> inside is transparent (to show the background layer beneath). A <code>border-radius</code> and <code>box-shadow</code> provide the viewport’s rounded rectangle shape.</p>
<figure>
  <img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/diagram-overlay.jpg' width='1385' height='695' alt='diagram showing the placement of the overlay' loading='lazy' />
</figure>
<pre><code class="language-html">&lt;div class=&quot;overlay&quot;&gt;
  &lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
</code></pre>
<pre><code class="language-css">.overlay {
  --body-bg: #0f6a80;
  --bg-position: calc(50% - 30vh);
  --overlay-w: 35vw;
  --overlay-h: 60vh;
  width: 50%;
  height: 100vh;
  position: sticky;
  top: 0;
  left: 0;
  display: grid;
  place-content: center;
  z-index: 1;
  background-image: linear-gradient(to bottom, var(--body-bg) var(--bg-position),
                                               transparent    var(--bg-position)),
                    linear-gradient(   to top, var(--body-bg) var(--bg-position),
                                               transparent    var(--bg-position));
}
.overlay div {
  width:  var(--overlay-w);
  height: var(--overlay-h);
  border-radius: 1em;
  box-shadow: 0 0 0 .5em var(--body-bg);
}
</code></pre>
<p>We’ve created a little “window” for the backgrounds to pass beneath to the left of the content. The fixed background gradient and dot pattern, despite being only on the right side of the page, help the two sides feel cohesive.</p>
<p>So here’s how the background and content sections scroll before we add in the foreground layers.</p>
<video width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/overlay-sections-video-poster.jpg">
  <source src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/overlay-sections-optimized.mp4" type="video/mp4">
  Sorry, your browser doesn’t support embedded videos.
</video>
<h2>Parallax visuals</h2>
<p>Now let’s look at the foreground pieces. The majority of the sections are using a CSS parallax technique using a combination of <code>position</code>, <code>perspective</code>, and 3D <code>transform</code>. This is a pretty tried and true way to have different elements on a page scroll at different speeds. This <a href="https://keithclark.co.uk/articles/pure-css-parallax-websites/">article by Keith Clark</a> and the <a href="https://keithclark.co.uk/articles/pure-css-parallax-websites/demo3/">accompanying demo</a> are super great for dissecting how this works.</p>
<p>I don’t intend to duplicate Keith’s tutorial here, so at a high level, what the CSS is doing is moving layers forward and backward in space (with <code>translateZ</code>). This creates visual parallax, where things farther in the distance move slower than those up close to you (like looking at scenery go by outside a car window).</p>
<figure>
  <img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/diagram-parallax.jpg' width='1385' height='695' alt='isomorphic diagram showing scale and depth for parallax layers, with layer-3 appearing closer to the viewer and moving faster' loading='lazy' />
</figure>
<p>The parallax structure setup looks something like this (again, I encourage you to read <a href="https://keithclark.co.uk/articles/pure-css-parallax-websites/">Keith’s awesome tutorial</a>):</p>
<pre><code class="language-html">&lt;div class=&quot;parallax&quot;&gt;
  &lt;section class=&quot;parallax-group&quot;&gt;
    &lt;div class=&quot;parallax-layer&quot;&gt;
      &lt;img /&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;
</code></pre>
<pre><code class="language-css">.parallax {
  height: 100vh;
  perspective: 300px;
}
.parallax-group {
  height: 100vh;
  transform-style: preserve-3d;
}
.parallax-layer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
</code></pre>
<p>After each background/content section, a foreground section is added with class <code>.pieces</code>. That full markup ends up looking something like this:</p>
<pre><code class="language-html">&lt;section class=&quot;parallax-group the-office&quot;&gt;
  &lt;div class=&quot;parallax-layer background&quot;&gt;
    &lt;div class=&quot;background-container&quot;&gt;
      &lt;div class=&quot;background-artwork&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;content&quot;&gt;
      &lt;h3&gt;Watch all 9 seasons of &lt;em&gt;The Office&lt;/em&gt; four times through.&lt;/h3&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;parallax-group pieces the-office-pieces&quot;&gt;
  &lt;div class=&quot;parallax-layer foreground layer-1&quot;&gt;
    &lt;img src=&quot;/images/the-office-jello.svg&quot; width=&quot;237&quot; height=&quot;148&quot; alt=&quot;a stapler stuck in a Jello mold&quot; class=&quot;jello&quot; /&gt;
  &lt;/div&gt;
  &lt;div class=&quot;parallax-layer foreground layer-2&quot;&gt;
    &lt;img src=&quot;/images/paper-airplane.svg&quot; width=&quot;173&quot; height=&quot;215&quot; alt=&quot;paper airplane&quot; class=&quot;airplane&quot; /&gt;
  &lt;/div&gt;
  &lt;div class=&quot;parallax-layer foreground layer-3&quot;&gt;
    &lt;img src=&quot;/images/the-office-mug.svg&quot; width=&quot;160&quot; height=&quot;145&quot; alt=&quot;World’s Best Boss mug&quot; class=&quot;mug&quot; /&gt;
  &lt;/div&gt;
  &lt;div class=&quot;parallax-layer foreground layer-2&quot;&gt;
    &lt;img src=&quot;/images/the-office-beet.svg&quot; width=&quot;200&quot; height=&quot;274&quot; alt=&quot;a beet&quot; class=&quot;beet&quot; /&gt;
  &lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;parallax-group space-mountain&quot;&gt;
  ...
&lt;/section&gt;
</code></pre>
<p>The demo (and lots of examples you may see) uses the parallax effect on full-width sections which creates a lot of movement. The Matterday site applies the parallax to individual artwork pieces to give them a floating feeling relative to each other. Each of the images is given a “depth” by setting a different <code>translateZ</code> value. To keep things manageable, I have three values set and assigned to classes that I can apply to individual elements.</p>
<pre><code class="language-css">.parallax-layer.layer-1 {
  transform: translateZ(100px) scale(.71);
}
.parallax-layer.layer-2 {
  transform: translateZ(175px) scale(.5);
}
.parallax-layer.layer-3 {
  transform: translateZ(200px) scale(.5);
}
</code></pre>
<p>To place the artwork next to the content section it supports (the one right above it in the page flow), I add a negative margin to those sections.</p>
<pre><code class="language-css">.parallax-group.pieces {
  margin-top: -100vh;
}
</code></pre>
<p>And then each individual piece is tweaked and positioned within its parent.</p>
<pre><code class="language-css">.the-office-pieces .mug {
  width: 20vw;
  transform: rotate(2deg);
  margin-left: 25vw;
  bottom: -10%;
}
</code></pre>
<p>When layering elements like this, you want to be careful you aren’t making any content inaccessible. The copy on the page should still be selectable with a mouse. You could add <code>pointer-events: none</code> to the artwork so you can still access the layer below it, but I opted to make the foreground sections half the width of the viewport so they aren’t overlapping the content at all.</p>
<pre><code class="language-css">.parallax-group.pieces {
  width: 50%;
}
</code></pre>
<figure>
  <img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/diagram-foreground-width.jpg' width='1385' height='695' alt='screenshot showing imagery doesn’t overlap text' loading='lazy' />
</figure>
<p>So in the end, the parallax creates an effect like this:</p>
<video width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/foreground-parallax-video-poster.jpg">
  <source src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/foreground-parallax-optimized.mp4" type="video/mp4">
  Sorry, your browser doesn’t support embedded videos.
</video>
<p>It creates some nice, subtle movement without feeling like it’s overwhelming or intense scrolljacking. Next I’ll talk through a few of the specific effects (and some tradeoffs).</p>
<h2>Re-stacking CSS layers for the “focus” effect</h2>
<p>For the section of the narrative “You could sharpen your focus,” I wanted to do a looking glass kind of effect where an element could scroll over a blurry image and focus it. I thought maybe I could lean on CSS <code>filter</code> here or <code>mix-blend-mode</code> or some combination. But because the background and foreground are split up, I had to think about it a bit differently.</p>
<p>The background is set up as normal, but with a handy <code>filter: blur()</code> on it. I also had to <code>scale()</code> it up a wee bit to avoid the feathered edges that CSS blur can cause.</p>
<pre><code class="language-css">.focus .background-artwork .focus-shapes {
  background-image: url('/images/shapes.svg');
  background-size: 130% auto;
  background-position: center center;
  filter: blur(.6em);
  transform: scale(1.3);
}
</code></pre>
<p>The circle effect is made with two foreground layers. The first contains the same background image but not blurred and the second has the teal outline. The effect I wanted was for the circle to pass over the background and “focus” only while it’s over the viewport. To achieve this, I applied a lower <code>z-index</code> to the first circle so it sits below the overlay but still above the background layer. Here is the code (simplified a bit):</p>
<pre><code class="language-html">&lt;section class=&quot;parallax-group pieces focus-pieces&quot;&gt;
  &lt;div class=&quot;parallax-layer foreground layer-1&quot;&gt;
    ...
  &lt;/div&gt;
&lt;/section&gt;
</code></pre>
<pre><code class="language-css">.parallax-group.focus-pieces {
  z-index: 0;
}
/* Remember that the .layer-1 child will have this transform */
.parallax-layer.foreground.layer-1 {
  transform: translateZ(100px) scale(.71);
}
</code></pre>
<p>Both foreground layers are on the same parallax depth (that <code>translateZ</code>) so they move at the same rate and create the illusion of interacting with the background layer.</p>
<video width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/focus-parallax-video-poster.jpg">
  <source src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/focus-parallax-optimized.mp4" type="video/mp4">
  Sorry, your browser doesn’t support embedded videos.
</video>
<p>One small hiccup here. Safari doesn’t like this <code>z-index</code> trick. Because of the <code>translateZ</code> on the foreground layers, it won’t allow for the container to sit below the overlay. A bit of a bummer (but also I get why it behaves that way). Resetting the <code>translateZ</code> does the trick, but then you lose the parallax that makes it feel a tiny bit nicer. So I opted to reset the <code>translateZ</code> only for Safari in this case (you can <a href="https://github.com/netlify/matterday.netlify.com/blob/main/styles/section-focus.css#L96-L117">see the code here</a>, not the nicest CSS I know sorry!).</p>
<h2>Using the CSS parallax speed variations for the receipt printing effect</h2>
<p>The “Time really adds up” section has a similar thing happening. To make it look like the calculator is printing the receipt, it requires the receipt to “grow” out from behind the calculator’s body (farther away) but to move faster (closer). So the receipt gets <code>.layer-2</code> and the calculator front gets <code>.layer-1</code>, but will they layer like we want?</p>
<pre><code class="language-html">&lt;!-- receipt --&gt;
&lt;section class=&quot;parallax-group pieces&quot;&gt;
  &lt;div class=&quot;parallax-layer layer-2&quot;&gt;
    &lt;div class=&quot;addition-receipt&quot;&gt;
      &lt;span&gt;60 min&lt;/span&gt;
      &lt;span&gt;+ 60 min&lt;/span&gt;
      &lt;span class=&quot;total&quot;&gt;120 min&lt;/span&gt;
      ...
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/section&gt;
&lt;!-- calculator front --&gt;
&lt;section class=&quot;parallax-group pieces&quot;&gt;
  &lt;div class=&quot;parallax-layer layer-1&quot;&gt;
    &lt;img src=&quot;/images/addition-front.svg&quot; width=&quot;330&quot; height=&quot;374&quot; alt=&quot;addition machine&quot; /&gt;
  &lt;/div&gt;
&lt;/section&gt;
</code></pre>
<p>Yes! Mostly. Luckily because the <code>.layer-2</code> receipt comes first in the markup before the <code>.layer-1</code>, the receipt sits behind the calculator front (except for in Safari which again requires <a href="https://github.com/netlify/matterday.netlify.com/blob/main/styles/section-adds-up.css#L98-L108">some specific fixes</a>).</p>
<video width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/calculator-parallax-video-poster.jpg">
  <source src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/calculator-parallax-optimized.mp4" type="video/mp4">
  Sorry, your browser doesn’t support embedded videos.
</video>
<p>The gradient trails below the calculator serve the purpose of obscuring the long receipt when needed. Because the artwork is using <code>vw</code> units to scale depending on the width of the browser, if the window is taller than it is wide, the receipt would sometimes show.</p>
<figure>
  <img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/diagram-receipt.jpg' width='1284' height='695' alt='bottom of receipt can be seen below calculator and a label says “Noooo”' loading='lazy' />
</figure>
<p>There’s probably better ways to deal with this, but just gotta ship sometimes. Turns out responsive design can be tricky! So many conditions to consider. 😅</p>
<h2>Using cutout images for the “Someday” list effect</h2>
<p>Finally, a pretty simple but fun detail from the “You could take items off the backburner” section. It features a Trello-like list of items with pill labels that appear empty at first. As you scroll, each pill turns teal with a “Ready” label.</p>
<video width="100%" preload="metadata" loop controls playsinline poster="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/someday-list-video-poster.jpg">
  <source src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/videos/someday-list-optimized.mp4" type="video/mp4">
  Sorry, your browser doesn’t support embedded videos.
</video>
<p>This is achieved with some artwork prep. The pill shapes are cut out from the list “container” so it reveals whatever is behind it. The “Ready” text is the same color as the dark background so you can’t see it until the artwork is above the teal. No CSS needed, the image is doing the lifting here.</p>
<figure>
  <img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/matterday/diagram-someday-list.jpg' width='1385' height='695' alt='the “Ready” label is only visible with a light background color' loading='lazy' />
</figure>
<h2>But why use CSS instead of JavaScript?</h2>
<p>Why do it like this? I love trying new things with CSS. It’s powerful and there are so many cool techniques to experiment with. For most animated scroll experiences, <a href="https://greensock.com/">Green Sock</a> really is king and we recently used the heck out of it for the <a href="https://www.netlify.com/">Netlify homepage</a> (shoutout to <a href="https://justinchuan.com/">Justin</a>, <a href="https://ryanmulligan.dev/">Ryan</a>, and <a href="https://samtan.dev/">Sam</a> for amazing work there). So I figured, why not take a stab at something different? It’s just really fun.</p>
<h2>More related to Matterday</h2>
<ul>
<li>Check out how the CSS parallax scrolling works for yourself! The code is <a href="https://github.com/netlify/matterday.netlify.com">public on GitHub</a>.</li>
<li><a href="https://matterday.netlify.com/#share">Share what you would do with your Matterday.</a></li>
<li>We collaborated with the team at <a href="https://supabase.com">Supabase</a> on this project (which was just delightful), and <a href="https://twitter.com/jonmeyers_io">Jon Meyers</a> published a <a href="https://jonmeyers.io/blog/how-i-built-the-back-end-for-netlify's-matterday-project-with-supabase">write-up on how the back-end of Matterday works</a>. Check it out!</li>
<li>You can also calculate the value of your team’s savings with Netlify’s <a href="https://www.netlify.com/roi-calculator/">new ROI calculator</a>!</li>
</ul>
<p>Thanks for reading! 👋</p>
<p>···</p>
<small>This was originally published on <a href="https://netlify.com/blog/fun-parallax-scrolling-css-for-matterday">netlify.com/blog</a>.</small>]]></description>
      <pubDate>Wed, 15 Jun 2022 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/fun-css-only-scrolling-effects-for-matterday/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/fun-css-only-scrolling-effects-for-matterday/</guid>
    </item>

    <item>
      <title>Case Study: 2dtrung.site 2021 refresh</title>
      <description><![CDATA[<p>For this year’s refresh, I really wanted to tackle an idea I’ve been trying to do for years. In my <a href="https://2dtrung.site/thoughts/entries/case-study-2018-refresh/">2018</a> and <a href="https://2dtrung.site/thoughts/entries/case-study-2019-refresh/">2019</a> case studies, I talked about an experience that feels like you’re traveling through physical space. I imagined a mix between walking forward in a first person video game and the layered, parallax effect Disney innovated (as seen in the <a href="https://youtu.be/x2rDrKUb6bM">intro of Beauty and Beast</a>). And as with years past, I wanted you to experience this by resizing the browser window.</p><p>Spoiler: I finally made it work. Here’s a screen recording from <a href="https://twitter.com/ericvanholtz">Eric Van Holtz</a> that shows the final resizing experience (plus a few extra interactions):</p><blockquote class="twitter-tweet" data-dnt="true"><p lang="en" dir="ltr">&quot;Wonderful Weirdos of the Web&quot; are welcomed to resize their browsers in another epic <a href="https://twitter.com/2dtrung?ref_src=twsrc%5Etfw">@2dtrung</a> portfolio redesign.<a href="https://t.co/008ze5ojvi">https://t.co/008ze5ojvi</a> 🤯 <a href="https://t.co/5YvhccjFDa">pic.twitter.com/5YvhccjFDa</a></p>&mdash; Eric Van Holtz (@ericvanholtz) <a href="https://twitter.com/ericvanholtz/status/1471580258893799430?ref_src=twsrc%5Etfw">December 16, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><h2>How it works</h2><p>This effect is ultimately created by “stacking” a bunch of SVGs on top of each other and then scaling and showing/hiding them in sequence as you resize the browser.</p><figure><img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2021-layers.svg' width='1200' height='720' alt='a diagram of four stacked layers labeled scenes 1-4 and an arrow that passes through the layers via cutouts' loading='lazy' /><figcaption>Transitions between scenes happen through cutouts.</figcaption></figure><p>I always hoped I could achieve this experience with CSS alone, but every time I attempted it I ran into big performance issues. To make the artwork scale inversely to the browser width, I could set something like: <code>height: calc(1200px - 100vw)</code>.</p><p>This works <em>mostly</em> fine on its own, but as the artwork became more layered and complicated, the more the effect broke down. As you resized, the browser would stop rendering the changes. Then once you stopped resizing, it would “catch up” and render the final state. Because the experience relies on things changing as smoothly and as real-time as possible, this just wasn’t going to work.</p><p>This was even before I started experimenting with blur effects. To make the effect feel more real, I wanted objects to blur and focus as they moved closer/farther away. I could do this with something like <code>filter: blur(1vw)</code> but this made browsers actually crash once I started resizing. Whoopsies.</p><p>I tried a few other things like using <code>clamp</code> (which worked ok for scaling but didn’t provide the level of control I needed) and setting tons of media queries in sequence (which has worked in the past for me, but would become very unwieldy with this one).</p><p>So I was about ready to throw in the towel until <a href="https://twitter.com/ScottKellum/status/1462644662099853318">Scott Kellum tweeted at me</a> and asked if something like <a href="https://typetura.com/">Typetura</a> could help. And it was like the clouds parting and I could finally feel the warm sun on my weary face. 🙏</p><p>Typetura uses a bit of JavaScript and makes flexible, responsive web typography a breeze (and as it turns out, zooming animations too). It was an especially nice solution here because I was still able to do all of my work in the CSS.</p><p>It allows you to set a <code>max-width</code> plus CSS animation <code>keyframes</code> and will interpolate between them as you resize the browser. So for the scaling of a layer of artwork, I could do something like this:</p>
<pre><code>svg {
  --tt-max: 3000;
  --tt-key: scene0;
  --tt-ease: cubic-bezier(.17,.67,.24,.97);
  height: 300vh;
}
  
@keyframes scene0 {
  0% {
    height: 2400vh;
  }
  43%, 100% {
    height: 5vh;
  }
}
</code></pre>
<p>I’m setting three Typetura custom properties for the <code>svg</code>:</p><ul><li><code>--tt-max</code> sets a <code>max-width</code> of 3000px here (which serves as the endpoint for the animation)</li><li><code>--tt-key</code> associates the selector with the keyframe animation</li><li><code>--tt-ease</code> sets the <code>animation-timing-function</code></li></ul><p>The animation for <code>scene0</code> sets two height values at different keyframes for Typetura to animate between. At 0% (0px wide), the artwork will be 2400vh tall and as you scale the browser window wider, the artwork will shrink to 5vh tall around 1290px browser width (43% of the 3000px max-width).</p><figure><img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2021-timeline.svg' width='1200' height='439' alt='a timeline that plots scene0, showing it as 2400vh tall at 0px browser width and 5vh at 1290px browser width' loading='lazy' /><figcaption>Scaling duration for scene0.</figcaption></figure><p>You might be wondering why I didn’t set <code>--tt-max</code> to 1290px then? I started things that way (with each scene having its own max-width), but soon found it difficult to quickly grok when things were happening. 50% meant something different for each scene. It was much easier to wrap my head around the entire sequence as one long timeline where any keyframe could be compared to another.</p><p>So I set the <code>--tt-max</code> just once (I dropped it under the body class <code>.home</code> in case I wanted to change it for different pages).</p>
<pre><code>  .home {
    --tt-max: 3000;
  }
</code></pre>
<p>This allowed me to easily “place” and stagger transitions along the main timeline spread across different elements. Here’s a simplified example of the door in the desert scene and the timing for when the scene appears and when the window pane becomes opaque (two separate layers):</p>
<pre><code>  @keyframes window {
    0%, 37.5% {
      opacity: 0;
    }
    39.5% {
      opacity: 1;
    }
  }

  @keyframes scene2 {
    0%, 37% {
      opacity: 0;
    }
    37.6% {
      opacity: 1;
    }
  }
</code></pre>
<p>And here’s a visualization of what the staggered animations look like along the global timeline:</p><figure><img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2021-timeline2.svg' width='1200' height='439' alt='a timeline that shows the staggered animation keyframes for window and scene2' loading='lazy' /></figure><p>So from here, any animatable CSS property became fair game, so I was able to use <code>opacity</code> to fade things, <code>transform</code> to move things (like opening and closing the elevator doors), and <code>filter</code> to create blur effects like I mentioned earlier:</p>
<pre><code>@keyframes scene1 {
  20% {
    filter: blur(0);
  }
  25% {
    filter: blur(22em);
  }
  28% {
    filter: blur(0);
  }
}
</code></pre>
<p>Or especially fun was one transition that animates between color and grayscale:</p>
<pre><code>@keyframes scene3 {
  45.6% {
    filter: grayscale(0);
  }
  50%, 100% {
    filter: grayscale(100%);
  }
}
</code></pre>
<p>Here’s what that looks like in action:</p><blockquote class="twitter-tweet" data-conversation="none" data-dnt="true"><p lang="en" dir="ltr">That transition from color to black and white. *chef’s kiss* Incredible! <a href="https://t.co/BTXpj8GNOj">pic.twitter.com/BTXpj8GNOj</a></p>&mdash; Scott Kellum (@ScottKellum) <a href="https://twitter.com/ScottKellum/status/1471537900512677888?ref_src=twsrc%5Etfw">December 16, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><p>Typetura made the calculations and animations so easy to manage that I was able to spend most of my time illustrating and working out the small details with each scene transition. (Also big hat tip to <a href="https://lea.verou.me/">Lea Verou</a> for her <a href="https://cubic-bezier.com/">cubic bezier tool</a> which I used a bunch.)</p><h2>Creating the artwork sequence</h2><p>So I’ve jumped ahead a wee bit. Once I figured out I <em>could</em> do this, I actually spent a lot of time figuring out what <em>this</em> even was. I had about 2500px of browser width to account for and I wasn’t sure how many different scenes and transitions I would need.</p><p>My initial thought was to have three scenes starting with a super wide view of an outdoor landscape zooming into a building far off in the distance and then into a computer screen inside that room. But with some initial tests, zooming a “far distance” felt like it took <em>forever</em> and not enough was changing to make it interesting.</p><p>So I shifted to one-point perspective “rooms” you could move through quickly. The living room zooming out through a window was the first transition I figured out. You should have seen the cheering I did once it worked.</p><div><video controls preload='none' poster='https://2dtrung.site/assets/images/thoughts/case-study-2021-window-placeholder.png'><source src='https://2dtrung.site/assets/images/thoughts/case-study-2021-window.mp4' type='video/mp4'><p>Sorry, your browser doesn't support embedded videos.</p></video></div><p>And from there I figured out the next scene and then the next and the next. I probably should have made a storyboard but I didn’t!</p><p>I did make a list of ideas and inspiration which included surrealism, <em>Centaurworld</em>, Wes Anderson films, the Marvel series <em>Loki</em> and <em>WandaVision</em>, and <em>The Scary Door</em> (the <em>Futurama</em> parody of <em>The Twilight Zone</em>).</p><figure><img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2021-inspiration.png' width='1200' height='634' alt='screenshots from Centaurworld, The Grand Budapest Hotel, The French Disptach, Loki, WandaVision, The Scary Door, and a surrealist painting' loading='lazy' /></figure><p>It was fun coming up with the different rooms to visit and various “windows” you would travel through (like a television screen or elevator). A few ideas and transitions that didn’t make it in:</p><ul><li>room of clouds</li><li>TRON-like virtual room</li><li>room where everything is upside down</li><li>snowglobe transition</li><li>Stargate or Dr. Strange portal transition</li><li>“through the looking glass” transition</li></ul><p>Maybe for another time. 😉</p><h2>Challenges</h2><p>As easy as Typetura made this process, I still ran into some weird behavior and gotchas.</p><p><strong>Scenes needed to be top level, inline SVG.</strong> <br>If the SVGs were <code>&lt;img&gt;</code>s, some browers would rasterize them when scaling. This helps a ton with performance, but was exactly the opposite of what I wanted to happen! So inline they went.</p><p>I also found if I wrapped the SVG with a containing <code>&lt;div&gt;</code> (for namespacing purposes) and applied transforms to the <code>&lt;div&gt;</code> instead, the scaling and transitions started to choke again. So that was out. I guess I could have still applied the transforms to the SVG and left the <code>&lt;div&gt;</code> there solely for the organizational benefit but that felt weird!</p><p>If anyone was digging into my CSS for this (which you can do on <a href="https://github.com/2dtrung/2dtrung.site/blob/main/_styl/pages/home.styl">GitHub</a>), this is why I’m using <code>svg:nth-of-type(5)</code> instead of class names for many of the scenes. This is not great but it allowed me to import the SVG into my <code>index.pug</code> file like this:</p>
<pre><code>  main
    include ../_assets/images/scene0-stars.svg
    include ../_assets/images/scene0.svg
    .airplanes
      include ../_assets/images/scene0-airplane.svg
      include ../_assets/images/scene0-airplane2.svg
    .reflection
    include ../_assets/images/scene1.svg
    .window
    include ../_assets/images/scene2.svg
    ...
</code></pre>
<p>This is definitely a <em>me</em> problem. I wanted to use the SVG directly exported from Illustrator without needing to move or edit any code or having to reorganize my Illustrator layers (yikes 😱). This way I could make changes, export, and preview really quickly which I needed to do many, many times.</p><p><strong>Balancing visual interest and file size.</strong> <br>I wanted the illustrations to feel fun, whimsical, and detailed while maintaining a reasonable file size. To minimize points and reduce complexity, I tried to stick with rectangles, ellipses, efficient lines, basic strokes, and solid blocks of color everywhere possible. Brushes and textures were off limits. A good, but challenging constraint.</p><figure><img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2021-visuals.png' width='1200' height='1123' alt='screenshots of illustrations from the site including a slice of pizze under a cloche in space, a living room, a surrealist door in a desert, and an elevator lobby' loading='lazy' /></figure><p><strong>So many screen sizes.</strong> <br>When you actively encourage people to resize your website you better prepare for the weird dimensions! Throughout this process, I had multiple windows open on my laptop and monitor, making sure each scene and transition made sense for narrow, wide, short, and tall windows. The one place where things really started to break is really wide + super short: a very special aspect ratio where you can start to see the edges of the artwork. I did a wee bit of extending widths for some scenes, but for the most part let it ride.</p><figure><img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2021-short-screen.png' width='1200' height='431' alt='browser that is very wide but very short: artwork of an elevator lobbby doesn’t fill the entire view and the blue background is showing at the right and left edges; arrows and sad emoji label those areas' loading='lazy' /><figcaption>~1425px by 345px browser size</figcaption></figure><p><strong>Mobile. Confusion.</strong> <br>As with past years, you need a browser that can resize to experience the fun. So the site on a phone isn’t <em>broken</em>, but it can be confusing if you got there by word of mouth. (I am exploring a way for you to watch the sequence without resizing your browser, stay tuned.)</p><p>This version of the site also has a really high chance you land on a weird inbetween state. My friend Kate arrived at the site to see a Pop-Tart against a black background. She suggested I add a little note to encourage folks to resize their browser, which does help. But! I also don’t mind a little bit of initial confusion in this case.</p><figure><img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2021-pop-tart.png' width='1200' height='668' alt='screenshot of a website that’s just a black background and a random Pop-Tart' loading='lazy' /><figcaption>Very cool website ya got there.</figcaption></figure><p>A few other things I considered:</p><ul><li>With Typetura, I needed to be ok with the experience requiring JavaScript. I love a CSS-only effect, but this one benefited so much from the JS assist that it felt worth it. Also, if <a href="https://css.oddbird.net/rwd/interpolation/">interpolated values</a> made it into the CSS spec that would be extremely cool.</li><li>Screenreaders felt like a bit of an unknown for me on this one. I ended up including a visually-hidden step-by-step description of the sequence.</li><li>I also thought a lot about motion. Is this a scenario that needs a motion warning? Or should I be using a <code>prefers-reduced-motion</code> query? The animations are all triggered by resizing the browser where you control the speed and duration. I wasn’t sure and I’m still not?</li></ul><h2>Anything else?</h2><p>The monitor scene at the largest width has a few fun Easter eggs. These were a last minute addition and I’m glad they made it in! It helped me learn a bit more about fine tuning exports from Illustrator and using JavaScript inside SVG.</p><figure><img src='https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2021-desktop.jpg' width='1200' height='634' alt='illustration of a monitor on a desktop with various windows open, some prints are taped to the wall behind' loading='lazy' /><figcaption>A scene with some hidden gems.</figcaption></figure><p>It was fun dusting off my timeline animation skills I haven’t used much since the ol’ Flash days. I still don’t think I <em>totally</em> understand bezier curves, but I got much better at predicting how they would behave.</p><p>With the end of year deadline looming, the rest of the site got a new coat of paint but not much else changed structurally. I did get to try out variable fonts and do some small optimizations where I could, so that feels like a win too.</p><p>At the end of the day I’m still tickled I was able to achieve the landing page I’ve been thinking about for years. I’m again reminded of how the web is such a cool medium and I just love building for it.</p><p>As always, previous versions of the site are still viewable in <a href="https://2dtrung.site/archive">the archive</a>.</p><p>Until next year’s refresh. 👋 Thanks for reading!</p>]]></description>
      <pubDate>Tue, 11 Jan 2022 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/case-study-2021-refresh/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/case-study-2021-refresh/</guid>
    </item>

    <item>
      <title>Fixing a design flaw that’s also an industry standard</title>
      <description><![CDATA[<p>We recently replaced the countertops in our kitchen and so naturally, we also installed a new sink. After some research, we went with a ledge workstation sink from <a href="https://www.creategoodsinks.com/">Create Good Sinks</a>.</p><figure class="wide"><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/creategoodsinks-product.jpg" width="1200" height="498" alt="a stainless steel undermount kitchen sink with a built-in ledge that holds a cutting board"><figcaption class="footnote">Not my sink, but you get the gist!</figcaption></figure><p>They’re pricey! But your kitchen sink is something you will likely never replace again (especially if it’s undermount) <em>and</em> it’s the tool in your kitchen you use the most. So we splurged.</p><p>The ledge workstation features are nice, but what made it worth the extra money is it fixes an almost universal kitchen sink design flaw (at least in the US).</p><p>Chris Coyier actually describes this design flaw nicely in <a href="https://chriscoyier.net/2021/06/04/40-for-40/">a recent blog post</a>:</p><blockquote><p>It shouldn’t be so hard to replace the rubber splash guard on sink garbage disposals. You need to be a friggin master plumber to get at that thing, and yet it’s the thing that gets gross and needs replacing the most. It’s a conspiracy.</p></blockquote><p>It’s true! But it’s also <em>the standard</em>.</p><p>Our new sink was designed to eliminate the permanently-puttied sink ring that catches all the gunk.</p><figure class="wide"><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/creategoodsinks-drain.jpg" width="1200" height="408" alt="comparison shot of typical, gunky sink drain and a clean, seamless design" loading="lazy"></figure><p>And it makes the splash guard easily removable so you can wash it by hand or put it in the dishwasher. 🙀😻</p><picture><source srcset="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/creategoodsinks-fallback.jpg" media="(prefers-reduced-motion: reduce)"><img srcset="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/creategoodsinks.gif" alt="person removes splash guard from sink and rinses it under faucet"></picture><p>Believe me when I say I sometimes just stand in my kitchen to admire this. It’s a perfect example of asking “Why the heck is it like this?” and making a much needed improvement.</p><p>But changing an industry standard has consequences!</p><p>The sink comes with a special drain kit that enables attachment to the most popular brands of garbage disposals. The plumber we hired (a lifelong tradesman) had to read instructions to install our disposal. This is something he could normally do with his eyes closed. He said he appreciated the challenge, but I can imagine not everyone would.</p><p>There’s also the problem of future problems. If something goes wrong or breaks, I can’t roll down to Home Depot and pick up a replacement. It’ll take a special order from this specific company and what if they eventually go out of business? What then?</p><p>And if I ever sell this house, the next person won’t know the sink’s features (and potential issues) unless I leave them some documentation.</p><p>Fixing this design flaw (and changing the standard) affects the people who interact with it and the other tools that integrate with it. There’s absolutely risk in moving away from what people have been trained to expect.</p><p>For this decision, the ripple of influence felt small as I weighed the tradeoffs. Can I convince a plumber to try a new technique or am I prepared to do this myself? Am I willing to bet on the future of a random sink company in Ohio or to buy extra parts in anticipation of needing them?</p><p>In the end I was ready to risk these things. Popping that splash guard out to clean it is so nice. And the seamless drain pleases my design sensibilities every single day.</p><p>Ideally this design fix and selling point <em>becomes</em> the standard. Kitchen sink users, we deserve better. Kitchen sink designers, it’s not too late to improve a lasting design.</p>]]></description>
      <pubDate>Mon, 07 Jun 2021 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/fixing-a-design-flaw-thats-also-an-industry-standard/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/fixing-a-design-flaw-thats-also-an-industry-standard/</guid>
    </item>

    <item>
      <title>Case Study: 2dtrung.site 2020 refresh</title>
      <description><![CDATA[<p>This is a long one, so here’s some jump links if you’re looking for something specific:</p><ul><li><a href="#proof-of-concept">Folding header proof of concept</a></li><li><a href="#creating-the-artwork">Creating the header artwork</a></li><li><a href="#details">Details make the illusion</a></li><li><a href="#pull-tabs">Pull-tabs</a></li><li><a href="#changing-portraits">About page changing portraits</a></li></ul></small><hr><p>Over the past few years, my portfolio’s homepage has served as a playground where I can experiment with using the browser in creative ways.</p><p>In 2017, I explored the idea that a site doesn’t need to look the same on every device or for every person by giving it <a href="https://2dtrung.site/thoughts/entries/case-study-2017-refresh/">a new layout every 100 pixels</a>. In 2018, I tried using the browser as <a href="https://2dtrung.site/thoughts/entries/case-study-2018-refresh/">an animation compiler</a>. And in 2019, I treated the browser as a physical space, <a href="https://2dtrung.site/thoughts/entries/case-study-2019-refresh/">able to contain more and more as it grows</a>.</p><p>This time around I knew I wanted to continue this exploration, but I also wanted to reunify the homepage with the rest of the site for a more cohesive experience. I decided to use more expected layout conventions like a decorative header, full-width but separated content sections, and regular old scrolling.</p><p>But how to make that exciting (both to design/build and to ultimately view)?</p><h2 id="inspirtion">Some inspiration</h2><p>Earlier this year, I’d been experimenting with paper effects. I created a handful of pens on CodePen that (with a containing <code>&lt;div&gt;</code>  and some styling) could turn an image into <a href="https://codepen.io/2dtrung/pen/PoZpjOr">a folded poster</a>, <a href="https://codepen.io/2dtrung/pen/dyGjvLB">leaning cards</a>, <a href="https://codepen.io/2dtrung/pen/JjGmrBz">a coffee table book</a>, or <a href="https://codepen.io/2dtrung/pen/XWXgwBQ">a trapper keeper</a>.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-paper-effects.jpg" width="1200" height="700" alt="photos of Schitt’s Creek and the Good Place casts with and without photo effects applied"><p>And I contributed to <a href="https://stylestage.dev">Style Stage</a> with a stylesheet that turned the page into a folded paper instruction manual.</p><figure class="wide"><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-style-stage.jpg" width="1200" height="683" alt="website styled like a folded paper manual" loading="lazy"><figcaption class="footnote"><a href="https://stylestage.dev/styles/manual/">Manual</a> on Style Stage</figcaption></figure><p>I liked the idea of treating page elements like paper: light but rigid, foldable, and layered to make cool effect. In the physical world, this is most magically realized in pop-up books.</p><p>So I went down a rabbit hole of pop-up folding techniques and paper construction. I watched tons of videos on <a href="https://www.youtube.com/channel/UCx2M2bGHtXBszG6tuR_NIbQ">The Pop-Up Channel</a> on YouTube where Duncan Birmingham talks through and demonstrates every pop-up technique you can imagine. It’s amazing.</p><figure><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-the-pop-up-channel.jpg" width="800" height="450" alt="Duncan Birminham holding a pop-up card of a lion’s face" loading="lazy"><figcaption class="footnote">Duncan Birmingham, pop-up badass.</figcaption></figure><p>I immediately knew I wanted to do pull-tabs. The dissolve technique seemed like a fun challenge to accomplish with code (more on that later). The header felt like a good spot to recreate folding pop-up mechanics. So I dug in.</p><p>After some frustrated blank-stare-at-the-screen days, I remembered those cool Al Jaffee fold-ins from Mad Magazine and then remembered a cool demo from developer Thomas Park who <a href="https://thomaspark.co/2020/06/the-mad-magazine-fold-in-effect-in-css/">recreated the fold-in effect in CSS</a>. So neat.</p><figure><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-mad-magazine.jpg" width="800" height="708" alt="Mad Magazine illustration of a butterfly that becomes Elvis when the edge is folded into the center" loading="lazy"><figcaption class="footnote">An Al Jaffee fold-in plus <a href="https://13thdimension.com/13-mad-fold-ins-an-al-jaffee-celebration/">twelve others</a>.</figcaption></figure><p>Thomas’s technique uses 3D transforms on hover, but I wanted the fold to happen slowly as you resize the browser window. So there were two things to figure out: how to make the fold feel realistic and writing a sentence that made sense as words disappeared at two separate fold points.</p><h2 id="proof-of-concept">A proof of concept</h2><p>I started in CodePen, using some same-sized images to figure out the fold mechanics. Here’s the original pen if you want to tinker, but I’ll describe what’s happening here.</p><div class="wide"><p class="codepen" data-height="450" data-theme-id="dark" data-default-tab="result" data-user="2dtrung" data-slug-hash="2d891f02e444c86b13e7448a3ef10242" data-preview="true" style="height: 336px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="2d891f02e444c86b13e7448a3ef10242"><span>See the Pen <a href="https://codepen.io/2dtrung/pen/2d891f02e444c86b13e7448a3ef10242">2d891f02e444c86b13e7448a3ef10242</a> by Trung. Do Duc (<a href="https://codepen.io/2dtrung">@2dtrung</a>)on <a href="https://codepen.io">CodePen</a>.</span></p><script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script></div><p>Because I wanted the header to fold two separate times, there are three <code>.panel</code> containers with <code>.left</code> and <code>.right</code> children, each containing an image. The markup looks like this:</p>
<pre><code class="language-html">  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;panel&quot;&gt;
      &lt;div class=&quot;left&quot;&gt;
        &lt;img src=&quot;tahani.jpg&quot; /&gt;
      &lt;/div&gt;
      &lt;div class=&quot;right&quot;&gt;
        &lt;img src=&quot;jason.jpg&quot; /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;panel&quot;&gt;
      &lt;div class=&quot;left&quot;&gt;
        &lt;img src=&quot;michael.jpg&quot; /&gt;
      &lt;/div&gt;
      &lt;div class=&quot;right&quot;&gt;
        &lt;img src=&quot;eleanor.jpg&quot; /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;panel&quot;&gt;
      &lt;div class=&quot;left&quot;&gt;
        &lt;img src=&quot;chidi.jpg&quot; /&gt;
      &lt;/div&gt;
      &lt;div class=&quot;right&quot;&gt;
        &lt;img src=&quot;janet.jpg&quot; /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
</code></pre>
<p>This uses the technique from my <a href="href='https://2dtrung.site/thoughts/entries/case-study-2019-refresh/">2019 refresh</a> with a few modifications. I originally thought I could use flexbox alone for this (which got things about 97% of the way there), but to eliminate small but unacceptable-to-me differences cross-browser, using positioning worked best.</p><p>For the first <code>.panel</code>, the <code>.left</code> and <code>.right</code> are given a width and positioned absolutely to the left and right of the container.</p>
<pre><code class="language-css">  .panel:first-child {
    .left,
    .right {
      width: 210px
      position: absolute;
    }
    .left {
      left: 0;
    }
    .right {
      right: 0;
    }
  }
</code></pre>
<p>For the next <code>.panel</code>, we want the <code>.left</code> and <code>.right</code> to be positioned adjacent to but inbetween the first set. That looks like this:</p>
<pre><code class="language-css">  .panel:nth-child(2) {
    .left {
      left: 210px;
    }
    .right {
      right: 210px;
    }
  }
</code></pre>
<p>In the 2019 version, each image kept its width and created an overlapping effect. But here, I want the images to squish/stretch to simulate folding. So the <code>.left</code> and <code>.right</code> should fill the availabile space until they reach their full width. We can do this by using <code>calc()</code>.</p><p>The calculation takes 100% width of the container, subtracts the width of the first two panels (210px * 2 = 420px), and then divides the space by two (since we have a <code>.left</code> and a <code>.right</code> to account for).</p><p>I’m using <code>&lt;img&gt;</code> in this example, but in the site I’m using inline SVG. So each of those need <code>preserveAspectRatio=&quot;none&quot;</code> added to make sure they scale with their container.</p>
<pre><code class="language-css">  .panel:nth-child(2) {
    .left,
    .right {
      width: calc((100% - 420px) / 2);
      max-width: 210px;
    }
  }
</code></pre>
<p>Here’s a diagram that might help visualize what’s going on.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-poc-breakdown.jpg" width="1200" height="900" alt="a diagram outlining the widths and positions for placement of the illustrations within the container" loading="lazy"><p>This same treatment is applied to the third panel and its children.</p><p>(You might be thinking that the <code>.panel</code> containers aren’t really needed, and you’re right! But the organizational clarity for me felt worth this extra bit of markup.)</p><p>To make it feel more “foldy”, the panels are skewed using <code>transform: skewY()</code>. Setting <code>transform-origin</code> and a bit of <code>translate</code> helps ensure the edges connect at the right places.</p>
<pre><code class="language-css">  .panel:first-child {
    .left {
      transform: skewY(-2deg);
      transform-origin: right bottom;
    }
    .right {
      transform: skewY(2deg);
      transform-origin: left bottom;
    }
  }
  .panel:nth-child(2) {
    .left {
      transform: skewY(-5deg);
      transform-origin: left bottom;
    }
    .right {
      transform: skewY(5deg);
      transform-origin: right bottom;
    }
  }
  .panel:nth-child(3) {
    .left {
      transform: skewY(-5deg) translateY(18px);
      transform-origin: left bottom;
    }
    .right {
      transform: skewY(5deg) translateY(18px);
      transform-origin: right bottom;
    }
  }
</code></pre>
<p>It ultimately creates this effect:</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-poc-full.jpg" width="1200" height="327" alt="six The Good Place portraits chained together to look like a long folded piece" loading="lazy"><p>It seems like <code>perspective</code> or 3D transforms make sense here, but they were much more dynamic on resize than I wanted. <code>skew</code> provides the dimensional illusion without shifting as the width changes.</p><h2 id="creating-the-artwork">Creating the artwork</h2><p>So once I got the basics of the header figured out, I jumped into making text and artwork that could fold and unfold, creating a complete picture at each folding point. This was a challenge!</p><p>I tried big text, small text, splitting words in the middle (and then doing lots of searches like “words that end with -ign”), and was finally able to land on something that worked.</p><p>It was a process of trial and error, but what really helped was laying out the panels in Illustrator like this:</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-panels-setup.jpg" width="1200" height="520" alt="two panels with text across them; then the previous text panels split with two new blank panels in between; the blank space between has an arrow and “Fill in words here so it makes sense still”" loading="lazy"><p>I would create the first panels (smallest fold) and then insert the next panels in between. And then do it again for the final fold:</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-panels-setup2.jpg" width="1200" height="520" alt="similar image to the one previous, but with two new blank panels in between" loading="lazy"><p>The illustrations worked similarly, splitting the panels and then making sure the edges meet to create a complete image. Here’s what the final artwork looks like:</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-header-home.jpg" width="1200" height="713" alt="sequence of panels showing the homepage header in various states" loading="lazy"><p>After a happy dance of finally figuring it out, I made folding artwork for the <a href="https://2dtrung.site/web">/web</a> and <a href="https://2dtrung.site/art">/art</a> pages too. (The art page header has a bit of a different treatment, which I’ll describe in the next section.)</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-header-web.jpg" width="1200" height="713" alt="sequence of panels showing the web header in various states" loading="lazy"><h2 id="details">Adding details</h2><p>With any illusion, the details make or break it. With the folding header, the skew (as mentioned earlier) and some shading do the heavy lifting.</p><p>Each panel section gets an <code>:after</code> pseudo-element that controls how much “shadow” it gets as the browser resizes. It is first sized and positioned directly on top of its parent.</p>
<pre><code class="language-css">  .left:after,
  .right:after {
    content: '';
    width: 100%;
    height: 100%;
    display: block;
    position: absolute;
    left: 0;
    top: 0;
  }
</code></pre>
<p>Then each panel gets some background treatment. The top gradient creates a “fold” highlight at the edge and the following two provide some shadowing on either side of the panel. Here’s an example for one section:</p>
<pre><code class="language-css">  .left:after {
    background-color: rgba(0,0,0,.7);
    background-image: linear-gradient(to right, rgba(255,255,255,.2) 2px,
                                                rgba(255,255,255,0)  2px),
                      linear-gradient(to right, rgba(0,0,0,0)  2px,
                                                rgba(0,0,0,.9) 2px,
                                                rgba(0,0,0,0)  40%),
                      linear-gradient(to left,  rgba(0,0,0,.9),
                                                rgba(0,0,0,0) 40%);
  }
</code></pre>
<p>With similar styling applied to all the panels, we get something like this:</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-header-shadows.jpg" width="1200" height="438" alt="the folded header but with shading that makes it look more realistic" loading="lazy"><p>To mimic the changing light as it folds, I set a bunch of media queries in quick succession to adjust the opacity of the <code>:after</code> and transition between them.</p>
<pre><code class="language-css">  .left:after {
    transition: opacity 150ms ease-out;
  }
  @media screen and (min-width: 501px) {
    .left:after { opacity: 1; }
  }
  @media screen and (min-width: 550px) {
    .left:after { opacity: .9; }
  }
  @media screen and (min-width: 600px) {
    .left:after { opacity: .8; }
  }
  @media screen and (min-width: 650px) {
    .left:after { opacity: .7; }
  }
  @media screen and (min-width: 700px) {
    .left:after { opacity: .6; }
  }
  @media screen and (min-width: 750px) {
    .left:after { opacity: .5; }
  }
  @media screen and (min-width: 800px) {
    .left:after { opacity: .4; }
  }
  @media screen and (min-width: 850px) {
    .left:after { opacity: .3; }
  }
  @media screen and (min-width: 900px) {
    .left:after { opacity: .2; }
  }
</code></pre>
<p>Best seen <a href="https://2dtrung.site">on the landing page</a> where you can interact with it, but here’s a screenshot of what that looks like at different widths:</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-header-shadows-resize.jpg" width="1200" height="452" alt="the homepage header in various stages of folding, showing darker shadows when almost completely folded away" loading="lazy"><p>One last detail I’ll mention is the header on the <a href="https://2dtrung.site/art">/art</a> page, which incorporates one additional panel section that “pops” up at full width. A sharper <code>transform: skewY()</code> angle makes this work and is the closest I could get to recreating a pop-up page without making my brain melt.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-header-art-resize.jpg" width="1200" height="452" alt="the art header with popup panels" loading="lazy"><h2 id="pull-tabs">Pull-tabs</h2><p>Pull-tabs in pop-up books are a really neat technique of layering paper images that move and change soley from movement of the tab along a single axis. To accomplish this with code, I wanted to keep that constraint. The only thing that could trigger an effect was moving the pull-tab to the left/right or up/down.</p><figure><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-the-pop-up-channel-2.jpg" width="800" height="450" alt="Duncan Birminham holding a dissolve pull-tab card" loading="lazy"><figcaption class="footnote">Duncan Birmingham, showing a <a href="https://youtu.be/kC6_mBdrMaE">dissolve pull-tab card</a>.</figcaption></figure><p>Of course I hoped I could do this with CSS only, so I tried using <code>resize</code> as the pull mechanism. It worked in some ways, but with limitations on how much I could change the resize handle, it didn’t quite work.</p><p>So next I tried using an <code>&lt;input type=&quot;range&quot;&gt;</code> slider. I was delighted to see you could style things pretty well (as seen in <a href="https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/">this CSS-Tricks article</a>). This was <em>very</em> close to what I wanted to do. In the end though, it didn’t allow for the flexibility I needed. It also had a default behavior when clicking and dragging, where the browser shifts the handle to be exactly center under the cursor. You can see that happening <a href="https://codepen.io/2dtrung/pen/54c2bffb562b6ac524758928618a1922">here on CodePen</a>. Not a <em>huge</em> deal, but not the experince I wanted.</p><p>At this point I started looking for some drag and drop JavScript help. After trying a few libraries, I landed on David DeSandro’s <a href="https://draggabilly.desandro.com/">Draggabilly</a> which was a breeze to implement for me and offered single axis movement and containment. Perfecto.</p><p>There are three pull-tab techniques I’m using on the homepage: basic (David Rose and Lynn’s sunglasses), straight dissolve (A Single Div), and angled dissolve (Airport Codes).</p><h2>Basic pull-tab</h2><p>The basic pull-tab technique relies on “windowed” layers revealing a moving layer underneath. In the case of David Rose, I’m using a handful of images layered below and on top of the draggable layer (the sweater designs). Here’s a visual of the four layers, with David’s sweater transparent and the surrounding area solid. I changed some colors to hopefully make it more clear.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-david.jpg" width="1200" height="948" alt="diagram showing the different layers that go into the David Rose pull-tab" loading="lazy"><p>The solid color surrounding areas obscure the sweater design outside of the transparent window. They also leave an unobstructed area so the tab can be grabbed and dragged. Here’s the movement of the draggable layer with the top layers at lower opacity:</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-david.gif" width="600" height="403" alt="animation showing the David pull-tab moving the artwork behind transparent layers" loading="lazy"><p>The imagery is positioned absolutely one on top of the other. It’s a mix of inline SVG, <code>&lt;img&gt;</code>, and CSS <code>background-image</code> (which I’ll get to later). The draggable layer needs a containing element:</p>
<pre><code class="language-html">  &lt;div class=&quot;david-wrapper&quot;&gt;
    &lt;div class=&quot;david-pull draggable&quot;&gt;
      &lt;img src=&quot;david-pull.svg&quot; alt=&quot;David’s sweaters&quot; /&gt;
    &lt;/div&gt;
  &lt;/div&gt;
</code></pre>
<p>Then with Draggabilly, I can do this:</p>
<pre><code class="language-javascript">  var david = new Draggabilly( '.david-pull', {
    axis: 'x',
    containment: '.david-wrapper'
  });
</code></pre>
<p>The width of <code>.david-wrapper</code> limits how far the pull-tab can be pulled, serving as the stopping tab you’d build into a paper pull-tab.</p><h2>Straight dissolve pull-tab</h2><p>This technique creates a dissolve transition between one image and another. It works by cutting each image into equal strips and layering them in an alternating stack. It seemed like this could be recreated with <code>z-index</code>.</p><p>Here’s a pen that shows how this works. You can grab the turquoise layers on the right and drag down.</p>
<div class="wide"><p class="codepen" data-height="510" data-theme-id="dark" data-default-tab="result" data-user="2dtrung" data-slug-hash="6844b6efbce82ef7a42ce76e184c6f70" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Dragging z-index issue"><span>See the Pen <a href="https://codepen.io/2dtrung/pen/6844b6efbce82ef7a42ce76e184c6f70">Dissolve transition proof of concept</a> by Trung. Do Duc (<a href="https://codepen.io/2dtrung">@2dtrung</a>) on <a href="https://codepen.io">CodePen</a>.</span></p><script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script></div><p>The markup looks like this, with each <code>&lt;div&gt;</code> numbered for where it sits in the stack.</p>
<pre><code class="language-html">  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;one&quot;&gt;1&lt;/div&gt;
    &lt;div class=&quot;three&quot;&gt;3&lt;/div&gt;
    &lt;div class=&quot;five&quot;&gt;5&lt;/div&gt;
    &lt;div class=&quot;draggable&quot;&gt;
      &lt;div class=&quot;two&quot;&gt;2&lt;/div&gt;
      &lt;div class=&quot;four&quot;&gt;4&lt;/div&gt;
      &lt;div class=&quot;six&quot;&gt;6&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
</code></pre>
<p>Then we position the layers and assign <code>z-index</code> values that correspond with each layer.</p>
<pre><code class="language-css">  .one {
    bottom: 0;
    z-index: 1;
  }
  .three {
    top: 33.33%;
    z-index: 3;
  }
  .five {
    top: 0;
    z-index: 5;
  }
  .two {
    bottom: 0;
    z-index: 2;
  }
  .four {
    top: 33.33%;
    z-index: 4;
  }
  .six {
    top: 0;
    z-index: 6;
  }

</code></pre>
<p>It’s using the same Draggabilly setup.</p>
<pre><code class="language-javascript">  var dissolve = new Draggabilly( '.draggable', {
    axis: 'y'
  });
</code></pre>
<p>Except I ran into an issue. Draggabilly by default is moving the draggable element with a CSS <code>transform</code> and this creates a new <code>z-index</code> stacking context. So I ended up losing the nice layered effect I had while the element was moving.</p><p>A quick fix was to move the element based on its <code>top</code> value instead of a <code>transform</code>. Not the best for performance normally, but it’s such a small interaction I figured it was just fine. (Thanks to <a href="https://twitter.com/SansThesis">Jason Rose</a> for helping me with this one.)</p>
<pre><code class="language-javascript">  dissolve.positionDrag = function() {
    this.setLeftTop();
  };
</code></pre>
<p>In the CodePen example, you can see top layer #6 sitting above the others. On the homepage, I’m using some artwork plus some strategically placed <code>:before</code> and <code>:after</code> pseudo-elements to cover up any pieces I don’t want you to see. Here‘s how it looks in the end:</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-single-div-sm.gif" width="400" height="435" alt="animation showing a dissolve pull-tab effect changing a text editor into an illustration" loading="lazy"><h2>Angled dissolve pull-tab</h2><p>The angled dissolve works in exactly the same way as the straight dissolve, but the layers of the draggable image are masked with angled transparent PNGs.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-phx.jpg" width="1200" height="891" alt="PHX lettering and the same image masked with three different angled shapes" loading="lazy"><p>Why not use CSS <code>clip-path</code>? I wanted to! But <code>clip-path</code> made the image edges aliased, creating a thin line between layers and breaking the illusion. PNGs provided anti-aliasing to give me the smooth edges I wanted.</p><p>Here’s how the final effect looks:</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-phx-sm.gif" width="400" height="377" alt="animation showing an angled dissolve pull-tab effect changing PHX to Phoenix Sky Harbor" loading="lazy"><h2 id="changing-portraits">Changing portraits</h2><p>Whew. Still with me? 😅</p><p>In lieu of a folding header on the <a href="https://2dtrung.site/about">/about</a> page, I illustrated a series of self-portraits dressed as some of my favorite characters. Thanks to <a href="https://twitter.com/adamavenir">Adam Avenir</a> for the idea! As you resize the page smaller, you’ll be able to catch them.</p><p>This is accomplished with a big sprite that shifts the <code>background-position</code> for each media query (similar technique I used for the <a href="https://2dtrung.site/thoughts/entries/case-study-2018-refresh/">2018 Bob’s Burgers animation</a>).</p><p>It starts with this base image.</p>
<pre><code class="language-css">  .avatar {
    width: 452px;
    height: 550px;
    position: relative;
    background-image: url('avatar-lynn-base.svg');
  }
</code></pre>
<img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/avatar-lynn-base.svg" width="400" height="487" alt="a picture frame and a partial portrait of Lynn’s face with body and mouth missing" loading="lazy"><p>And then layers a sprite on top with an <code>:after</code> pseudo-element.</p>
<pre><code class="language-css">  .avatar:after {
    content: '';
    width: 100%;
    height: 100%;
    position: absolute;
    background-repeat: no-repeat;
    background-image: url('avatar-lynn-costumes.svg');
    background-position: 0 0;
  }
</code></pre>
<p>A sample from the costume sprite:</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/avatar-lynn-costumes.jpg" width="900" height="761" alt="grid of costume illustrations without a face including Leia Organa, David Rose, and others" loading="lazy"><p>Then I can shift the <code>background-position</code> at each media query to show a different costume.</p>
<pre><code class="language-css">  @media screen and (min-width: 501px) {
    .avatar:after {
      background-position-x: -452px;
    }
  }
  @media screen and (min-width: 551px) {
    .avatar:after {
      background-position-x: -904px;
    }
  }
  @media screen and (min-width: 601px) {
    .avatar:after {
      background-position-x: 0;
      background-position-y: -550px;
    }
  }
  ... and so on
</code></pre>
<p>And it creates this fun effect when you resize the browser:</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-avatars.gif" width="400" height="474" alt="animation showing Lynn’s avatar changing costumes" loading="lazy"><h2>Aything else?</h2><p>There’s a couple other easter eggs to discover, but that covers most of it!</p><p>Last year I tried out a dark mode theme for <code>prefers-color-scheme</code> and this year I followed Andy Bell’s <a href="https://hankchizljaw.com/wrote/create-a-user-controlled-dark-or-light-mode/">user-controlled dark mode tutorial</a> which is just wonderful. It uses CSS custom properties in a way I haven’t before and that was cool to learn.</p><p>Remember how I mentioned that some of the pull-tabs use a mix of inline SVG, <code>&lt;img&gt;</code>, and <code>background-image</code>? Because of the solid color backgrounds that obscure layers beneath them, I needed to swap those colors for the light and dark theme. Adding a class to SVG paths and changing the <code>fill</code> color with custom properties made that no big lift at all.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/thoughts/case-study-2020-svg-background.jpg" width="400" height="440" alt="solid color background is white when it should be grey; label says “gotta change this”" loading="lazy" style="max-width:300px"><p>Like with every refresh I learned more about cross-browser CSS behavior, SVG quirks, and different ways to lay things out with grid and flexbox. And I learned more than I ever imagined about pop-up books.</p><p>There’s a lot of reasons to do this refresh every year, but one downside is that I don’t code things for long-term maintenance. If it changes in a year, there’s not much pressure to try. But this year I did some intentional cleanup, consolidating, and creating of templates that I should have years ago. Felt really good!</p><p>I’ll end this with my usual reminder that previous versions of the site are still viewable in <a href="https://2dtrung.site/archive">the archive</a>.</p><p>Until next year’s refresh. 👋 Thanks for reading!</p>]]></description>
      <pubDate>Mon, 14 Dec 2020 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/case-study-2020-refresh/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/case-study-2020-refresh/</guid>
    </item>

    <item>
      <title>Cookies and a year of learning a new skill</title>
      <description><![CDATA[<p>In December of 2018 I tried my hand at decorating sugar cookies with royal icing. It was my first time using piping bags and different consistencies of icing. Dear reader, it was <em>fun</em>.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2018.jpg" alt="an assortment of decorated Christmas cookies"><small class="footnote">first batch of cookies from December 2018</small><p>Soon after I went down a rabbit hole of blogs and Instagram videos and holy cow people are making some amazing edible artwork. In my spirit of trying all the things, I made my 2019 resolution to get better at decorating cookies.</p><p>I spent a year baking and decorating, trying to make a batch or two each month. I experimented with different recipes and techniques, tried my hand at custom cookie cutters, and ended the year with two big orders for paying customers.</p><p>You can jump to <a href="#recipes">the recipes I landed on</a> or see <a href="#timeline">a timeline of all the cookies</a> I made this year, but I also wanted to share some of the things I learned (which are super relevant to design/development or learning any new skill, really).</p><h2>Utilize shared experience from the community</h2><p>The cookie decorating world is very open source. Recipes, tips and tricks, and how-to videos are <em>everywhere</em>. We joke a lot about the stories you have to scroll through to get to a recipe, but I read through a lot and found a ton of helpful information.</p><p>I watched a bunch of <a href="https://www.instagram.com/explore/tags/cookiedecorating/">Instagram videos</a> and took a class at <a href="https://smitholator.com/">Smith-o-lator Cookie Shop</a> in Mesa. Watching experienced folks do their thing helped me level up quickly. It’s very similar in the design and dev world. We like to say we’re self-taught, but a lot of us truly are community-taught.</p><h2>Map it out</h2><p>I’m usually a “let’s wing it and see what happens” kind of designer, but with cookies I really did better with a plan. Buying ingredients, chilling, baking, and mixing icing is a process that takes hours and was usually spread across a few days. There’s almost no ‘undo’ or ‘reset’ equivalent here. Makes you appreciate digital work for sure.</p><p>I’d make lists of what cookies to make, what icing colors I’d need, and, with some more complicated cookies, I drew things out to provide myself a guide. This was so effective, my husband (with no decorating experience) was able to make a pretty decent Baby Yoda cookie on his own.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-guide-yoda.jpg"><small class="footnote">Baby Yoda guide, my husband’s version, and my version</small><h2>Slow down</h2><p>Icing videos are super sped up and the rare realtime one still shows an experienced hand. It took me a while to find the right pace for me, which always ended up being “slower than you think.” If things started to feel difficult, it always helped to slow down and take my time.</p><p>A few icing behaviors I’m still trying to figure out are craters forming as the icing dries and icing colors bleeding into one another.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-craters-bleed.jpg"><small class="footnote">small icing indentations and color bleeding</small><p>Research and experimentation tells me it’s a combination of the chemistry of the icing recipe, how viscous you mix the icing, humidity (or in my case, lack thereof), and especially not waiting long enough for things to dry before adding another color. Patience is key!</p><h2>Cookies are meant to be eaten</h2><p>Cookie decorating is a decent developer experience vs. user experience analogy. Lots of people were surprised when my cookies tasted good. They’d say, “Pretty sugar cookies never taste good.” It makes sense to me now: almost every technique I found to make the cookies easier to work with or better looking made them taste worse.</p><p>Reducing the amount of butter made the cookies easier to cut, held shapes better, and reduced butter bleed (small amounts of grease seeping into the icing), but made them less delicious. Using meringue powder instead of egg whites made the icing <em>so smooth</em> to pipe but dried with a crispier, less pleasant texture. And surprisingly, lots of cookie decorators add corn syrup to their icing. If you see cookie icing that’s got a gorgeous sheen, it likely has corn syrup.</p><p>I decided to optimize for taste with the most natural ingredients I could. It made the decorating processs a bit more difficult, but is worth it!</p><h2>Make all the mistakes</h2><p>As with learning anything, I made so many mistakes. A cool thing about royal icing is it starts to dry immediately so you have a pretty small window of time to fix a mistake. After that, trying to fix it tends to make it <em>worse</em>. A nice built-in reminder to just accept mistakes and continue on.</p><p>This is a skill that requires a lot of hands-on practice and luckily every mistake or ugly cookie you make still tastes just as good.</p><h2>Tips and tricks</h2><p>Here’s the advice I can boil down to quick tips and tricks:</p><ul><li>Roll out the dough between two pieces of plastic wrap before chilling. It’s much easier to roll and then can be cut immediately from the fridge.</li></ul><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-dough.jpg" alt="sheets of rolled cookie dough pressed between plastic wrap"><ul><li>Put your piping bag in a glass for easy loading.</li></ul><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-piping-bag.jpg" alt="a plastic piping bag inside a glass"><ul><li>When using a piping bag with tip and coupler, use a tipless piping bag of icing <em>inside</em> it for easier loading and cleanup.</li><li>If your icing consistency isn’t quite right, stop and adjust it. Don’t power through.</li><li>Make more flood icing than you think you need.</li><li>Make less piping icing than you think you need.</li><li>If using a tipless bag, cut the hole smaller than you think you need.</li><li>Use gel food coloring.</li><li>Add some white gel coloring to icing before mixing colors in.</li><li>Use a cookie swivel for easy turning.</li><li>Buy pre-cut parchment paper (so convenient omg).</li></ul><h3 id="timeline">A year of progress</h2><p>Here’s all the cookies I made this year. I can see steady improvement and where I took a few steps backward. I had a lot of fun and I think my friends and family liked this hobby too. Excited for all the cookies and progress I’ll make in 2020!</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-02.jpg"><small class="footnote">February 2019 - footballs, pretzels, ice cream</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-03.jpg"><small class="footnote">March 2019 - basketballs, cactus, hearts</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-04-1.jpg"><small class="footnote">April 2019 - skateboards, Xbox controllers</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-04-2.jpg"><small class="footnote">April 2019 - Pop Tarts, paint palettes, unicorns</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-05.jpg"><small class="footnote">May 2019 - graduation caps and gowns, balloons, stars</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-06-1.jpg"><small class="footnote">June 2019 - elven lembas bread</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-06-2.jpg"><small class="footnote">June 2019 - yarn and goldfish</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-06-3.jpg"><small class="footnote">June 2019 - cactus, stars, and lemons</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-07-1.jpg"><small class="footnote">July 2019 - cacti in pots</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-07-2.jpg"><small class="footnote">July 2019 - succulents</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-08.jpg"><small class="footnote">August 2019 - cacti in pots, ice cream</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-10.jpg"><small class="footnote">October 2019 - fall leaves, ghosts, pumpkins, cauldrons</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-12-1.jpg"><small class="footnote">December 2019 - Monomyth logomarks</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-12-2.jpg"><small class="footnote">December 2019 - Christmas gifts</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-12-3.jpg"><small class="footnote">December 2019 - Christmas cacti</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-12-4.jpg"><small class="footnote">December 2019 - computer mouse cursors</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-12-5.jpg"><small class="footnote">December 2019 - meltmedia logomarks</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-12-6.jpg"><small class="footnote">December 2019 - Baby Yodas</small><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/cookie-2019-12-7.jpg"><small class="footnote">December 2019 - snowflakes, assorted Christmas cookies</small><h3 id="recipes">Cookie and icing recipes</h2><p>And finally after a whole bunch of other stuff, here’s the recipes I use.</p><div class="callout"><h3>Sugar cookies</h3><ul class="unstyled"><li>3 cups all-purpose flour</li><li>1 cup sugar</li><li>1 cup butter</li><li>2 tbsp cream cheese</li><li>½ tsp baking powder</li><li>½ tsp salt</li><li>½ tsp cream of tartar</li><li>1 large egg</li><li>1 teaspoon vanilla</li><li>½ tsp almond extract</li></ul><p><strong>Prep dough</strong></p><p>Sift flour and combine with baking powder, salt, and cream of tartar in a large bowl. Set aside.</p><p>Crack egg into small bowl. Add vanilla and almond extracts and lightly beat. Set aside.</p><p>Cream butter and sugar in mixer on low-medium speed.</p><p>Add and mix in cream cheese.</p><p>Add egg mixture to bowl and beat on low-medium speed until combined.</p><p>Gradually add the flour to the bowl on low speed. Continue to mix until the dough starts to pull away form the sides of the bowl.</p><p>Divide dough into thirds. Using a roller, flatten each piece of dough to ¼ inch thick between two pieces of plastic wrap. Chill in the fridge for at least 2 hours.</p><p><strong>Bake</strong></p><p>Preheat oven to 350°F.</p><p>Cut out cookies and place on parchment-lined cookie sheets.</p><p>Chill cut cookies for an additional 5 minutes.</p><p>Bake 8-12 minutes, depending on size and shape of cookie. Remove cookies when you see the slightest hint of golden brown on the bottom edges.</p></div><div class="callout"><h3>Royal icing</h3><ul class="unstyled"><li>4 cups powdered sugar</li><li>½ tsp salt</li><li>¼ tsp cream of tartar</li><li>1 tsp vanilla extract</li><li>¼ cup pasteurized egg whites</li><li>water, as needed</li></ul><p>Sift the powdered sugar into a large bowl. Add the salt and cream of tartar.</p><p>Add the vanilla and egg whites. Mix on low speed and scrape sides of bowl.</p><p>Once combined, continue to mix with increasing speed for 4-5 minutes. The icing should turn more opaque and white, with firm peaks.</p><p>Add more water to make the icing looser. Add more powdered sugar to firm it up.</p></div>]]></description>
      <pubDate>Sun, 29 Dec 2019 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/cookies-and-a-year-of-learning-a-new-skill/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/cookies-and-a-year-of-learning-a-new-skill/</guid>
    </item>

    <item>
      <title>Case Study: 2dtrung.site 2019 refresh</title>
      <description><![CDATA[<p>Last week I released my latest portfolio refresh. Like the previous two years, I wanted to create an experience that was enhanced by resizing the browser window. The 2017 version gave you <a href="https://2dtrung.site/thoughts/entries/case-study-2017-refresh/">a new layout every 100 pixels</a> and the 2018 version created <a href="https://2dtrung.site/thoughts/entries/case-study-2018-refresh/">a frame by frame animation</a>.</p><p>This year I initially set out to do something with the z-axis and explore depth and forward/backward motion. I liked the idea of using layered illustration to simulate traveling through space. Something like the <a href="https://youtu.be/x2rDrKUb6bM">opening of Beauty and the Beast</a>, but maybe you travel through different worlds or through tiny doors like Alice in Wonderland.</p><p>What really got me excited though was the concept of Russian nesting dolls. You open one and something similar, but wholly different exists inside.</p><p>I started with the idea of a self portrait that cracked open revealing new faces as you scaled the browser. Further scaling would zoom in, each outer head becoming blurred and eventually leaving the frame as you moved forward. I hoped it would feel dynamic, as if it existed in 3-dimensional space.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2019-mockup.jpg" alt="three nested faces separated to reveal a skull"><small class="footnote">exploratory sketch</small><p>I started implementing this into HTML and CSS to see if it would feel as I was imagining. I set it up with relative widths and heights so the artwork would fill the entire browser window. Even before I could add in some subtle transforms and transitions, the browsers screamed out in protest. Safari was like, “Nope!” and literally stopped rendering anything.</p><p>Soooo... what now?</p><p>I tried things out with absolute pixel dimensions and things worked much better. Fewer calculations for the browser to make seemed like the way to go. So instead of zooming in, maybe at wider widths you could see <em>every</em> face in a strange, horizontal stack.</p><h2>Preparing the artwork</h2><p>As I was illustrating the different faces, I realized I was constrained by the mostly oval shape of the original portrait. Each subsequent face is hidden behind the one that precedes it, and to maintain the “reveal” they do need to stay obscured until it’s their turn.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2019-heads-overlay.jpg" alt="a portrait of the artist, and the same portrait at lower opacity to reveal a skull underneath"><small class="footnote">the skull is hidden by the face in front</small><p>This constraint did help me move pretty quickly with illustrations. I was able to find inspiration in things I like and art styles I admire. Especially fun were the Lichtenstein and Picasso homages.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2019-faces.jpg" alt="portraits of the artist, one with comedy mustache and false nose glasses, one in Lichtenstein pop art style, and one in Picasso cubist style"><p>Keeping the heads mostly the same size and shape also made the layout calculations so much easier (even though it can look pretty gnarly in my source files). I’ll dive into that more in a bit.</p><h2>Laying things out</h2><p>Each face is made up of a container <code>div</code> and two images (one for each side of the face). The markup looks like this:</p><pre><code>  &lt;div class=&quot;face&quot; id=&quot;blue&quot;&gt;
    &lt;img src=&quot;left-blue.svg&quot;  class=&quot;left&quot;  /&gt;
    &lt;img src=&quot;right-blue.svg&quot; class=&quot;right&quot; /&gt;
  &lt;/div&gt;
</code></pre>
<p>There are three major styles in play to create the opening effect. Each <code>div</code> has a specific <code>min-width</code> and each image is positioned a specific value from the left and right.</p><p>So the initial blue face gets styling like this:</p><pre><code>  .face#blue {
    width: 100vw;
    min-width: 620px;

    .left {
      position: absolute;
      left: 110px;
    }

    .right {
      position: absolute;
      right: 110px;
    }
  }
</code></pre>
<p>Here’s a diagram that might help visualize what that looks like.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2019-face-diagram.jpg" alt="a diagram outlining the widths and margins for placement of illustrations within the site"><p>The next face (the skull) would then have styling that looked something like this:</p><pre><code>  .face#skull {
    width: 100vw;
    min-width: 840px;

    .left {
      position: absolute;
      left: 220px;
    }

    .right {
      position: absolute;
      right: 220px;
    }
  }
</code></pre>
<img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2019-face-diagram2.jpg" alt="a similar diagram outlining widths and margins for another illustration"><p>Each subsequent face would get adjusted <code>min-width</code>, <code>left</code>, and <code>right</code> values so they are positioned correctly to create the reveal as the browser scales.</p><h2>Snap into place</h2><p>A little detail I love is the faces scale and move a wee bit when they open. This creates a “snap” effect that adds some dimension.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2019-face-snap.gif" alt="an animatio showing two sides of a face coming together and moving apart"><p>This is achieved for each face with two media queries in quick succession and CSS transforms.</p><pre><code>  @media screen and (min-width: 621px) {
    .face#blue .left {
      transform: scale(1.07) translate(-6px,0);
    }
    .face#blue .right {
      transform: scale(1.07) translate( 6px,0);
    }
  }

  @media screen and (min-width: 629px) {
    .face#blue .left {
      transform: scale(1.07) translate(-6px,7px);
    }
    .face#blue .right {
      transform: scale(1.07) translate( 6px,7px);
    }
  }
</code></pre>
<p>It might seem like a small thing, but it adds a lot.</p><h2>Shadows and masking</h2><p>One of the most challenging aspects of this concept was getting the shadows to behave the way I wanted.</p><p>With the faces overlapping each other, I wanted each one to cast a shadow on the face below it. CSS masking would make this possible. As you can see in the gif below, the shadow should only show on the skull’s surface, but it needed to be “stuck” to the blue face as things move. I have the full <code>linear-gradient</code> and the mask in orange showing on the left and the effect it creates on the right.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2019-mask.gif" alt="an animation showing the layers of illustration, mask, and shadow"><p>I originally planned to add the mask to each <code>&lt;div class="face"&gt;</code> and use an <code>:after</code> for the shadow, but there’s a fun browser bug I had to work around. In Chrome, <code>position: fixed</code> doesn’t work if that element’s parent has a transform applied (remember that snap?). And <code>position: fixed</code> was required to get the effect I wanted.</p><p>So the markup for each mask ended up like this, as a sibling of the corresponding face.</p><pre><code>  &lt;span class=&quot;mask&quot;&gt;
    &lt;div class=&quot;left&quot; &gt;&lt;/div&gt;
    &lt;div class=&quot;right&quot;&gt;&lt;/div&gt;
  &lt;/span&gt;
  &lt;div class=&quot;face&quot; id=&quot;pizza&quot;&gt;
    ...
  &lt;/div&gt;
</code></pre>
<p>The left and right <code>div</code> have the mask applied. It’s an SVG that is placed at the same left/right values as the face (in this case, the skull). An <code>:after</code> pseudo-element draws the shadow.</p><pre><code>  .mask {
    bottom: 200px;
  }

  .mask .left {
    mask-image: url('left-skull-mask.svg');
    mask-position: left 220px top 0;
    mask-size: auto 400px;
  }
  .mask .right {
    mask-image: url('right-skull-mask.svg');
    mask-position: right 220px top 0;
    mask-size: auto 400px;
  }

  .mask .left:after {
    position: fixed;
    left: 220px;
    background-image: linear-gradient(to right, rgba(0,0,0,.3) 50%, transparent 57%);
  }
  .mask .right:after {
    position: fixed;
    right: 220px;
    background-image: linear-gradient(to left, rgba(0,0,0,.3) 50%, transparent 57%);
  }
</code></pre>
<p>Because of that Chrome bug, I have to do a little bit of manual changing to each mask to account for the snap transform:</p><pre><code>  @media screen and (min-width: 841px) {
    .mask {
      bottom: 186px;
    }
    .mask .left {
      mask-position: left 207px top 0;
      mask-size: auto 428px;
    }
    .mask .right {
      mask-position: right 207px top 0;
      mask-size: auto 428px;
    }
  }
  @media screen and (min-width: 849px) {
    .mask {
      bottom: 178px;
    }
  }
</code></pre>
<p>The shadows working in this way gives some depth and dimension to each layer as it moves in front and behind the others.</p><h2>Pre-processors are wonderful</h2><p>I have the CSS simplified here to show the basics of how things are working. But if you were to look at my <a href="https://github.com/2dtrung/2dtrung.site/blob/master/_styl/pages/home.styl">Stylus file for this page</a>, things are set up a bit differently. I won’t go too deep into it to save all of our brains, but here’s a quick overview.</p><p>Because the calculations were pretty consistent for the different faces, I was able to set variables and create mixins that calculated all the various poitioning values for me. So for the face widths, I set variables like this:</p><pre><code>  $face-1 = 620px
  $face-2 = $face-1 + 220
  $face-3 = $face-2 + 220
  $face-4 = $face-3 + 220
  $face-5 = $face-4 + 220
  ...
</code></pre>
<p>And then my mixin could look like this:</p><pre><code>  face(num,width,width2)
    min-width: width
    bottom: var(--face-y)
    z-index: (32 - (num * 2))

    img.right
      right: (100px * num + 10 * num)
    img.left
      left:  (100px * num + 10 * num)

    @media screen and (min-width: width + 1)
      img.right
        transform: scale(1.07) translate( 6px,0)
      img.left
        transform: scale(1.07) translate(-6px,0)

    @media screen and (min-width: width + 9)
      img.right
        transform: scale(1.07) translate( 6px,7px)
      img.left
        transform: scale(1.07) translate(-6px,7px)

    @media screen and (max-width: width2)
      opacity: 0
</code></pre>
<p>(I’m using a custom property of <code>var(--face-y)</code> here to position the faces from the bottom of the browser for various vertical media queries):</p><pre><code>  :root
    @media screen and (max-height: 550px)
      --face-y: 50px

    @media screen and (min-height: 551px)
      --face-y: 200px

    @media screen and (min-height: 820px)
      --face-y: 400px

    @media screen and (min-height: 1100px)
      --face-y: 570px
</code></pre>
<p>But back to that mixin.</p><p>I was then able to create each face with this short declaration style. Setting things up like this with <code>:nth-of-type</code> allowed me to change the order and remove/add faces in the markup without needing to adjust any CSS. (This is also why the faces and masks are different element types, divs and spans respectively.)</p><pre><code>  .face:nth-of-type(1)
    face(1,$face-1,0)
  .face:nth-of-type(2)
    face(2,$face-2,$face-1)
  .face:nth-of-type(3)
    face(3,$face-3,$face-2)
  .face:nth-of-type(4)
    face(4,$face-4,$face-3)
  .face:nth-of-type(5)
    face(5,$face-5,$face-4)
  ...
</code></pre>
<p>The masks also get a mixin (which is a bit more complicated). Math, amirite?</p><pre><code>  $shadow-h = 428px

  mask(num,name,width,width2)
    min-width: width
    z-index: (32 - (num * 2) + 1)
    bottom: var(--face-y)

    @media screen and (min-width: width + 1)
      bottom: calc(var(--face-y) - 14px)
    @media screen and (min-width: width + 9)
      bottom: calc(var(--face-y) - 22px)

    .left,
    .right
      min-width: width
      @media screen and (min-width: width + 1)
        height: $shadow-h
        mask-size: auto $shadow-h

    .left
      mask-image: url('https://2dtrung.site/assets/images/left-' + name + '-mask.svg')
      mask-position: left (100px * num + 10 * num) top 0
      @media screen and (min-width: width + 1)
        mask-position: left (100px * num + 10 * (num - 1) - 3) top 0
      &amp;:after
        left: (100px * num + 10 * num)

    .right
      mask-image: url('https://2dtrung.site/assets/images/right-' + name + '-mask.svg')
      mask-position: right (100px * num + 10 * num) top 0
      @media screen and (min-width: width + 1)
        mask-position: right (100px * num + 10 * (num - 1) - 3) top 0
      &amp;:after
        right: (100px * num + 10 * num)

    @media screen and (max-width: width2)
      opacity: 0
</code></pre>
<p>With this mixin, I can create each mask with a short declaration (inside a <code>@supports</code> for good measure).</p><pre><code>  @supports(mask-image: url(''))
    .mask:nth-of-type(2)
      mask(2,skull,$face-2,$face-1)
    .mask:nth-of-type(3)
      mask(3,pizza,$face-3,$face-2)
    .mask:nth-of-type(4)
      mask(4,pops,$face-4,$face-3)
    .mask:nth-of-type(5)
      mask(5,mustache,$face-5,$face-4)
    ...
</code></pre>
<p>There’s some more fun Stylus stuff going on that made the process fun and manageable for me. If you want to dig into that, <a href="https://github.com/2dtrung/2dtrung.site/blob/master/_styl/pages/home.styl">take a peek on GitHub</a>.</p><h2>Other details</h2><p>There’s a lot for me to love and for you to discover in this refresh, but I will say one of my favorite parts is the helmet and cyborg faces combo. I knew I wanted to play with transparency somewhere and I love how resizing the helmet reveals even more.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2019-helmet.jpg" alt="illustration of a golden cyborg Lynn and a helmet opening up"><p>And of course, I love tiny stretchy Lynn at the center of it all. The arm stretching was a last minute addition and a brilliant suggestion from <a href="https://twitter.com/richardiii">my friend Richard</a>. The left/right mechanical arms and pulleys couldn’t use my nice mixins, so I had to write <a href="https://github.com/2dtrung/2dtrung.site/blob/master/_styl/pages/home.styl#L128-L175">something extra for those</a>. I realize not everyone has a giant monitor to see this, but I really loved it and wanted to include it.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2019-stretchy.jpg" alt="a tiny Lynn with stretchy arms holds onto ropes and pulleys"><p>Also, vertical media queries + pups. ❤</p><h2>Lots of good stuff learned</h2><p>I always learn something new with these refreshes and this one was no different.</p><p>I got to try out masking and discover all the weird browser issues with it (Edge, why you leave artifacts?). I got pretty good at positioning and made my brain hurt figuring out repeatable calculation patterns.</p><p>I found the limit of what the browser could render while resizing. And I gained a better understanding of when I should use CSS custom properties vs pre-processor variables.</p><p>Plus I got to try out styling the site for dark mode.</p><img class="wide" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2019-darkmode.jpg" alt="a screenshot of the /web page of 2dtrung.site with a dark grey background"><p>I’ll end this with a friendly reminder that previous versions of the site are still viewable in <a href="https://2dtrung.site/archive">the archive</a>.</p><p>Until next year’s refresh. 👋 Thanks for following along!</p>]]></description>
      <pubDate>Tue, 26 Nov 2019 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/case-study-2019-refresh/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/case-study-2019-refresh/</guid>
    </item>

    <item>
      <title>The value of an outside perspective</title>
      <description><![CDATA[<img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/blog-illo-outside-perspective.png" alt="Outside a window, a yeti smiles and waves hello."><small>When is someone on the outside very helpful (and not creepy)?</small><p>I don’t think I need to convince anyone that having another person review your work is a good thing. It’s probably already built into your teams and processes. Programmers pair up and build a feature together, bouncing ideas off one another. Code reviews are required before new work can be merged into our apps. Design teams hold critiques where the work is examined and people provide feedback.</p><p>In most of these cases, the people reviewing the work are our teammates or clients. Let’s say they’re “People who get you.”</p><h2>People who get you</h2><p>These people work with you. Sometimes it feels like your coworkers and clients understand you better than you do. This makes discussing your work super productive. They know what you’re trying to do, they get your communication style, and they see a similar vision for the work. When the feedback is good, it’s <em>really</em> good. You’re collaborating and the work is flowing.</p><p>But are there gaps that can cause the work to suffer? The People who get you are usually like-minded and can be oblivious or ignorant to the same things you are. Have you ever seen a product or marketing campaign that’s just blatantly offensive? You ask yourself, “<em>How</em> could they not see it? No one said anything?” Maybe all the people in the room were missing this crucial information. Or the person who saw it couldn’t speak up or was ignored.</p><p>Keeping feedback inside a project, team, or org can be weighed down by cultural baggage. Teams love to say they’re low on politics, but honestly it’s unavoidable. A higher-up can drop a bomb of feedback and derail a team. Teammates can resist solutions because it’s not how it’s always been done. Sometimes feedback and ideas are <em>actually heard</em> from only specific people or roles, despite how many people are saying them.</p><p>So what then? Ask for feedback from people who don’t know you? That can be risky. They don’t know your history, all the difficult decisions you’ve had to make to get to today. They don’t have an investment in your success. You’ll have to catch them up and answer questions you’ve answered before, turn down ideas you’ve already tried and rejected. It’ll take too much time.</p><p>But there’s an opportunity there, with these People who don’t get you …yet.</p><h2>People who don’t get you …yet</h2><p>The cool thing about getting an outside perspective is it’s a viewpoint that’s impossible for you to have yourself. Seeing things for the first time is insight a person has once.</p><p>We’ve seen the immense value of putting our work and processes in front of a beginner or a brand new teammate and them asking questions and speaking their mind. It can immediately reveal gaps in documentation, process, or our assumptions. It brings a unique clarity that only a Person who doesn’t get you yet can.</p><p>And the time spent “catching them up” is the perfect chance to evaluate how you explain your work. There <em>is</em> only so much time, so what information do you convey and what do you cut? They’ll likely ask questions you’ve already answered, but I’m certain they’ll ask questions you haven’t considered. Often decisions get made without us realizing it and this forces you to examine them and explain why things are as they are.</p><p>People who don’t get you yet can see and evaluate your work without the baggage I mentioned earlier. They can see the work at face value, as it is. They won’t be worried about shareholders or the many years you’ve spent iterating. Does the work reflect the purpose and direction you’re selling?</p><p>And as far as investing in your success, if you find the right People who don’t get you yet, they will approach this important job of giving feedback with support and encouragement in mind. It can absolutely be counterproductive to seek this valuable insight from people who don’t have your back. In our experience, peers and/or consultants who can bring humility, kindness, and expertise to this process are value multipliers.</p><p>--</p><p><em>This was originally published on <a href="https://blog.andyet.com/2019/06/19/the-value-of-an-outside-perspective/">blog.andyet.com</a>.</em></p>]]></description>
      <pubDate>Wed, 20 Jun 2019 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/the-value-of-an-outside-perspective/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/the-value-of-an-outside-perspective/</guid>
    </item>

    <item>
      <title>Five years of A Single Div</title>
      <description><![CDATA[<p>On 22 May 2014, I publish a little camera illustration. It’s drawn with CSS and one HTML element (a div).</p><p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/single-div-camera.png" alt="A CSS drawing of a vintage camera."></p><p>With this, my favorite little side project is born.</p><p>I draw some food, a Captain America shield, and an iPhone battery. CSS solidifies itself as my favorite artistic medium.</p><p>With each drawing, I share a tweet. People seem to really dig it. It encourages me to keep going.</p><p>I give the project a name and buy <a href="https://a.singlediv.com">a domain</a>.</p><p>Mozilla Hacks invites me to <a href="https://hacks.mozilla.org/2014/09/single-div-drawings-with-css/">write a tutorial</a>.</p><p>My web heroes see the project, share it, and praise it. I can’t believe it. I’m positively glowing 😻.</p><p>A Single Div hits Reddit and Hacker News. It’s exciting and horrible at the same time. It inspires my favorite tagline: I specialize in projects that make people say “I don’t get it.”</p><p>The drawings become more complex as I try out new techniques and find new challenges.</p><p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/web-a-single-div.jpg" alt="A selection of drawings from A Single Div."></p><p>A Single Div is featured in Net Magazine. I’m beside myself with joy.</p><p>People holler at me about SVG. This seems to hold even for my projects that follow. Something <a href="https://a.singlediv.com/#svg">I can joke about</a> fondly now. Yes, I’ve heard of SVG.</p><p>I give a talk on <a href="https://2dtrung.site/thoughts/entries/talk-illustration-with-css/">CSS illustration at CSSDay</a>. I share A Single Div and talk about art with a bunch of developers. I’m holding on to this high.</p><p>A Single Div becomes a project I can work on even when I’m feeling stuck. A few hours here or there and the site continues to grow.</p><p>I learn <em>so much</em> about CSS behavior. I grow a deep, mental reference I can pull from for my job and paid projects. “Real” projects as people often say. But truly, what project isn’t real?</p><p>I test the limits of my creativity. The constraints help me to see things differently. And to see <em>myself</em> differently. “Can I draw this?” feels like “Gosh, I don’t think I can.” But with enough thinking, it shifts to “Holy crap, it works.” Honestly I still look back at some of these drawings and wonder how the heck I did that.</p><p>I’ve learned so much from you, little side project. Happy fifth anniversary (I heard the traditional gift is wood 👇).</p><p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/single-div-five.png" alt="A CSS drawing of the word FIVE made of wood logs."></p><small class="footnote">View this latest drawing and more at <a href="https://a.singlediv.com">a.singlediv.com</a>.</small><p>🍻 Cheers to five more years.</p>]]></description>
      <pubDate>Wed, 22 May 2019 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/five-years-of-a-single-div/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/five-years-of-a-single-div/</guid>
    </item>

    <item>
      <title>Sabbaticals and muscle memory</title>
      <description><![CDATA[<p>In the middle of 2018, I took a 3-month sabbatical from work. It was something I’d been wanting to do for over a year, while I was experiencing pretty severe burnout. I’ve previously shared a bit of <a href="https://vimeo.com/248062321">what that felt like</a>. I was able to stabilize myself for a while with significant help from my personal and professional support system. But extended leave was still calling me.</p><p>There were logistical decisions to be made and questions to answer. How long would I need? What kind of financial place would I need to be in? Would &amp;yet hold my job for me? That all felt easy compared to the more nebulous and philosophical questions on my mind. In hindsight, three months isn’t that long, but our country’s culture has a way of punishing those who step away from work. And it encourages us to punish ourselves.</p><p>I had a lot of thoughts. What if taking time off doesn’t help? What if this time away damages my career in some way? What if I forget things, fall behind?</p><p>What if I lose a part of myself?</p><p>…</p><p>While on sabbatical, I went to my local gym early one morning to shoot hoops. I hadn’t played in years and I knew the court would be empty. Turns out dudes at the gym don’t usually want a 5’3” Asian chick with glasses on their pick-up basketball team. Go figure.</p><p>I used to play every day growing up and played on lots of teams. I was actually pretty good. Maybe on this break I could ease my way back into it.</p><p>As I walked toward the hoop something happened. I dribbled, I squared up, and I took a shot. Swoosh. My arm lingered vertically in the air. Follow through. I grabbed the ball and took more shots. Swoosh. Swoosh. The ball met the wood floor and returned to my hand. Over and over.</p><p>It’s the first time I’ve cried at the gym. Muscle memory is a hell of a thing. All the work and the practice and the connections you made are still there. Even years later, you pick back up and it’s still you.</p><p>I’d just spent a year or so feeling unsure of where I was, feeling unlike myself in ways I couldn’t reconcile. And then that morning, shooting hoops in an empty L.A. Fitness, there I was.</p><p>…</p><p>I didn’t do much web work during my break. I unpacked the pile of moving boxes we’d been living out of, tried <a href="https://twitter.com/2dtrung/status/1022871859921006593">making some things out of wood</a>, visited <a href="https://twitter.com/2dtrung/status/1018634691732094976">some cool places in Arizona</a>, and watched a good helping of reality television. I was surprised by how much I loved my time away. Maybe I could do this forever.</p><p>And when I returned to work and to the web, there I was, again. Sometimes the work just flows out of you. Intuition is built from years of practice. Habits. Muscle memory.</p><p>A connection between disparate skills zapped into place in my brain. The feeling of effortlessly sinking free throws and the joy of combining CSS properties to make visual magic.</p><p>I’ve read a lot about specialists and generalists. T-shaped people and comb-shaped people. None of these have felt right to me. Every thing I do and learn and try makes this complex web of knowledge and experience. Each new thing strengthens the web and makes it more entangled.</p><p>Maybe I’m a web-shaped person, a web builder. A spider-person. A friendly neighborhood Spider-Woman.</p><p>I’m also sort of the Queen of getting out of shape and then back into shape in a weird wave pattern that never ends. I’ve accepted it and stopped pushing against it. And this I’ve learned, is how I work too. Being constantly prolific isn’t the norm for a lot of creative people. It’s ok to create seasonally. Some seasons we’re hibernating and others the work bursts from our fingertips without hesitation.</p><p>It’s good to rest when we need it.</p><p>If I’m stuck on a problem, I take a shower. Clean my bathroom or take a nap. When I return, the answer is right there clear as day. I joke that procrastination is part of my process, but I do mean it. Sometimes seeing the answers, connecting the dots, takes a bit of time away.</p><p>So if it’s calling you, take a break. When you come back, you’ll be there.</p><p>--</p><p><em>This was originally published on <a href="https://blog.andyet.com/2019/02/06/sabbaticals-and-muscle-memory">blog.andyet.com</a>.</em></p>]]></description>
      <pubDate>Wed, 06 Feb 2019 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/sabbaticals-and-muscle-memory/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/sabbaticals-and-muscle-memory/</guid>
    </item>


    <item>
      <title>2018 British Arrows Awards</title>
      <description><![CDATA[<p>Last month I visited the <a href="https://walkerart.org/">Walker Art Center</a> in Minneapolis where they were showcasing the 2018 British Arrows Awards, celebrating the UK’s most innovative and best moving image advertising.</p><p>The commercials are all impressive, some funny, some deeply moving, and some were basically short films. I love the extra effort that goes into Super Bowl ads here in the U.S. so this was a lot of fun.</p><p>I’ve been thinking about it ever since, so I collected all of the commercials here. They’re worth checking out.</p><p>Here’s what won Commercial of the Year: an ad about normalizing periods. It’s well done!</p><div class="video-container wide"><iframe width="100%" src="https://www.youtube.com/embed/lm8vCCBaeQw" frameborder="0" allowfullscreen></iframe></div><p><strong>#Bloodnormal</strong> <br><small>Essity, Libresse/Bodyform for AMVBBDO by Somesuch, directed by Daniel Wolfe</small></p><p>And then the rest. Here’s a YouTube playlist of the commercials that won Bronze, Silver, and Gold (except for the Instagram ad <a href="https://vimeo.com/249225909">A day on planet Stories</a> which you can view on Vimeo). See below for each ad’s individual link and details.</p><p>I think my favorites might be <a href="https://youtu.be/Dw2NOE_6VAU">Viewers</a>, <a href="https://youtu.be/Y_iCIISngdI">What Girls Are Made Of</a>, <a href="https://youtu.be/1MJrRvpjB1I">Differences</a>, <a href="https://youtu.be/IZC02EQqcXc">Timeless</a>, and <a href="https://youtu.be/8SI52fWMp_8">The Gene Project</a>.</p><div class="video-container wide"><iframe width="100%" src="https://www.youtube.com/embed/videoseries?list=PLusDsPjWd8nk7SdMXqGF2gIE917xhStSg" frameborder="0" allowfullscreen></iframe></div><h2>Bronze</h2><p><a href="https://youtu.be/XW7zZJSGYgU">Best Friends</a> <br><small>Mars Petcare, Dreamies Deli-Catz for adam&eveDDB by Caviar, directed by Keith Schofield</small></p><p><a href="https://vimeo.com/249225909">A day on planet Stories</a> <br><small>Instagram, Instagram Stories for Wieden+Kennedy Amsterdam by Caviar, directed by Dent De Cuir</small></p><p><a href="https://youtu.be/YCoQwZ9BQ9Q">Comic Relief Safety Video</a> <br><small>British Airways, Comic Relief for BBH by 2AM, directed by Becky Martin</small></p><p><a href="https://youtu.be/JuvqaBqUYw0">The Small Prices</a> <br><small>TK Maxx, Spring Summer for Wieden+Kennedy London by Bold, directed by Adam & Dave</small></p><p><a href="https://youtu.be/Dw2NOE_6VAU">Viewers</a> <br><small>Google, YouTube for AMVBBDO by Pulse Films, directed by ThirtyTwo</small></p><p><a href="https://youtu.be/n8aAaGDNosQ">Mo Farah--Smile</a> <br><small>Nike, Nike Running for Wieden+Kennedy London by Rogue, directed by Mark Zibert</small></p><p><a href="https://youtu.be/h3gkLJhFWEA">Rummager</a> <br><small>VISA, Holiday Money for Saatchi & Saatchi by Somesuch, directed by Sam Hibbard</small></p><p><a href="https://youtu.be/F4I5hhEJtp8">Kovonation Street Opening</a> <br><small>CompareTheMarket.com for VCCP Blue by Passion Animation Studios, directed by Dave Scanlon</small></p><p><a href="https://youtu.be/dRzApWZgeCs">Fall Fashion</a> <br><small>H&M for adam&eveDDB by Caviar, directed by Karim Huu Do</small></p><p><a href="https://youtu.be/LzQhHvdDCig">We Are All One</a> <br><small>On, on-running.com for TheBay 13 Institute by Hungry Man, directed by Richard Bullock</small></p><p><a href="https://youtu.be/IgZ-TGTUyf4">E.ON x Gorillaz: A Solar Collaboration</a> <br><small>E.ON, Solar PV Batteries for WCRS by Blinkink at Blink, directed by Noah Harris</small></p><hr><h2>Silver</h2><p><a href="https://youtu.be/mQqJPAx_ARo">It’s perfectly normal. Until it’s kwiffed. Caught Glas</a> <br><small>Kwiff for Droga5 London by Biscuit Filmworks, directed by Jeff Low</small></p><p><a href="https://youtu.be/t_jZd2MUXbc">Women’s Euros 2017</a> <br><small>Channel 4, made by 4creative, directed by Alex Boutell</small></p><p><a href="https://youtu.be/J2uSGFgFn2Q">Barbers</a> <br><small>Apple, iPhone 7 Plus for Apple by Furlined, directed by Dougal Wilson</small></p><p><a href="https://youtu.be/Z9WYkOGYwv0">Snowed In</a> <br><small>Waitrose for adam&eveDDB by Academy Films, directed by Martin De Thurah</small></p><p><a href="https://youtu.be/9zv884-Smrc">Born Confident</a> <br><small>Volkswagen, T-Roc for adam&eveDDB by Somesuch, directed by Nick Gordon</small></p><p><a href="https://youtu.be/o4ewFdCxd5Y">London Needs You Alive</a> <br><small>Mayor of London, Greater London, Knife Crime for AMVBBDO by Academy Films, by Novemba</small></p><p><a href="https://youtu.be/-PgTjhx1VLw">Epic Lift</a> <br><small>MoneySuperMarket, MoneySuperMarket.com for Mother by Blink Productions, The Bobbsey Twins from Homicide</small></p><p><a href="https://youtu.be/nQk98HV8-AA">Anthony Joshua</a> <br><small>Lucozada, Lucozada Sport for Grey London by Smuggler, directed by Christopher Hewitt</small></p><p><a href="https://youtu.be/RL6Wiiq7sg8">I Love Doing Dishes</a> <br><small>Finish, Dishwater Tablets for Wieden+Kennedy London by FRIEND, directed by Ian Pons Jewell</small></p><p><a href="https://youtu.be/Y_iCIISngdI">What Girls Are Made Of</a> <br><small>Nike for Wieden+Kennedy London by Riff Raff, directed by David Wilson</small></p><p><a href="https://youtu.be/M4X4e_truzI">Atlas</a> <br><small>Squarespace, Build A Website for Media Sages by Biscuit Filmworks, directed by Andreas Nilsson</small></p><p><a href="https://youtu.be/pxHpdEHEaV0">Mother and Daughter</a> <br><small>Sky, Sky Cinema for WCRS by StrangeLove, directed by Ben Liam Jones</small></p><p><a href="https://youtu.be/EyijJV_KUN8">It’s perfectly normal. Until it’s kwiffed. Father & Son</a> <br><small>Kwiff for Droga5 London by Biscuit Filmworks, directed by Jeff Low</small></p><p><a href="https://youtu.be/viRSiBCxlS0">140 Years</a> <br><small>Wimbledon for McCann London by Friends Electric and Craft/McCann, directed by Lucas Zanotto</small></p><hr><h2>Gold</h2><p><a href="https://youtu.be/8PstSiTCk74">The Supporting Act</a> <br><small>BBC, BBC One for BBC Creative by Blinkink at Blink, directed by Elliot Dear</small></p><p><a href="https://youtu.be/UWKdI6qMUNM">Clowns</a> <br><small>Audi for BBH by Rattling Stick, directed by Ringan Ledwidge</small></p><p><a href="https://youtu.be/FTaAXPDvnuM">More Than A Game</a> <br><small>EA Sports, FIFA 18 for adam&eveDDB by Smuggler, directed by Adam Berg</small></p><p><a href="https://youtu.be/1MJrRvpjB1I">Differences</a> <br><small>BBC, CBeebies for Karmarama by Smuggler, directed by Joshua Neale</small></p><p><a href="https://youtu.be/xSJQP_klQYY">Delivering Awesome</a> <br><small>Virgin Media, Fibre Broadband for BBH by Rogue, directed by Sam Brown</small></p><p><a href="https://youtu.be/2Ei_XdwSghQ">Fanfare, White Cliffs, Football</a> <br><small>Channel 4, Channel 4 Idents 2017 for 4creative by Blink Productions, directed by Dougal Wilson</small></p><p><a href="https://youtu.be/UcFlyBN7gxM">Boundaries</a> <br><small>Canon, Cameras for VCCP by Riff Raff, directed by Megaforce</small></p><p><a href="https://youtu.be/CkYUVw9wkQ8">Dream Makers</a> <br><small>Honda, FIlm on Four for Wieden+Kennedy London by Time Based Arts, directed by James Allen and Mike Skrgatic</small></p><p><a href="https://youtu.be/OJ7Jsd0yCLQ">The Great British Bake Off</a> <br><small>Channel 4 for 4creative by Blinkink at Blink, directed by Parabella</small></p><p><a href="https://youtu.be/HbzOkNq8aPE">Alive</a> <br><small>Bose, Bose Headphones for Grey London by Smuggler, directed by Miles Jay</small></p><p><a href="https://youtu.be/6FKNyhwUBY4">The Faith of a Few</a> <br><small>Mini, John Cooper Works for Jung von Matt by ANORAK x Somesuch, directed by Daniel Wolfe</small></p><p><a href="https://youtu.be/4uCeeVl_He4">Pride and Breadjudice</a> <br><small>Warburtons, Seeded Batch for SCRS by Another Film Company, directed by Declan Lowney</small></p><p><a href="https://youtu.be/aFHvWMzG6gE">The Button</a> <br><small>Volkswagen, Golf GTE for adam&eveDDB by Independent Films, directed by Gary Freedman</small></p><p><a href="https://youtu.be/IZC02EQqcXc">Timeless</a> <br><small>Lacoste for BETC Paris by Academy Films and Wanda, directed by Seb Edwards</small></p><p><a href="https://youtu.be/bAdpodJkB9c">The Heist No One Is Talking About</a> <br><small>Oxfam for Don’t Panic by Stink Films, directed by Tom Green<br></small>* Disturbing content warning for this one</p><p><a href="https://youtu.be/SvjT38dsxtU">Youth Can Do It</a> <br><small>Prince’s Trust for The&Partnership London by Park Pictures, directed by Andrea Arnold</small></p><p><a href="https://youtu.be/vEEVu4w5LTE">Ostrich</a> <br><small>Samsung, Samsung Gear VR for Leo Burnett Chicago by MJZ London, directed by Matthijs van Heijningen</small></p><p><a href="https://youtu.be/8SI52fWMp_8">The Gene Project</a> <br><small>Unilever, Marmite for adam&eveDDB by Outsider, directed by James Rouse</small></p><hr><h2>Commercial of the Year</h2><p><a href="https://youtu.be/lm8vCCBaeQw">#Bloodnormal</a> <br><small>Essity, Libresse/Bodyform for AMVBBDO by Somesuch, directed by Daniel Wolfe</small></p>]]></description>
      <pubDate>Tue, 29 Jan 2019 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/2018-british-arrows-awards/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/2018-british-arrows-awards/</guid>
    </item>

    <item>
      <title>Case Study: 2dtrung.site 2018 refresh</title>
      <description><![CDATA[<p>It’s that time of year again where I refresh my portfolio site. The 2017 redesign got a huge response, probably my favorite version of the site ever. If you’re curious, you can <a href="https://2dtrung.site/archive/2017">view the archived 2017 site</a> or <a href="https://2dtrung.site/thoughts/entries/case-study-2017-refresh/">read the case study</a>.</p><p>In sum though, the 2017 redesign featured <a href="https://twitter.com/DannPetty/status/943621861740630017">20 media queries where the site changed drastically every 100px</a>. I knew this year I wanted to build upon that concept.</p><p>In the previous version, the 21 separate layouts each utilized their available space, but their order in sequence wasn’t all that deliberate. I thought it might be interesting if things still changed as you scaled the browser, but the change was <em>meaningful</em> depending on whether you were scaling up or down.</p><p>A few ideas seemed promising: </p><ul><li>Maybe the viewport could zoom in or out on an aerial map or scene. Go from a macro view of something small and zoom out into space.</li><li>Maybe the user could feel like they were moving deeper into a physical space using layered imagery. Like walking through rooms in a first-person video game.</li><li>Maybe things could be “tipped off a table” as the browser edge came into contact or grow in number as the browser grows.</li></ul><p>With all of these, it felt like animation was going to be an important part. I researched and thought a lot about various animation techniques and styles. Should it be CSS-drawn? Should JavaScript lend a hand here? How can I have interesting imagery that changes over many breakpoints without having a massive amount to download? I knew it’d probably be a lot of work, but <em>how much</em> work?</p><p>A good compromise I landed on was animating a single character. I could keep the illustration style pretty simple and possibly show various frames by shifting a <code>background-image</code> sprite in the same way we do for other imagery on our websites.</p><p>So what could be fun with that constraint? I thought about a person moving across the screen as the browser moved or getting more cramped inside a “box” as the browser shrunk. I knew I wanted the animation to work both ways—so you could resize the browser randomly and everything still made sense.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2018-smoosh.jpg" alt="Exploratory illustrations of Lynn’s face smooshed against an implied glass wall."><small class="footnote">some early exploratory sketches</small><p>If anything was going to shrink/grow with the browser, why not clothes? They could shrink teeny tiny and grow huge and baggy. That might be fun. I tried a few illustration styles (including a nod to <em>The Loud House</em>) before settling on paying tribute to the genius <em>Bob’s Burgers</em>.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2018-illo-styles.jpg" alt="Exploratory illustrations of Lynn in different styles."><small class="footnote">more exploratory sketches</small><p>With this style (from the show outro), I could keep things simple and make a fun background that wouldn’t distract from the character animation in the foreground.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/bobs-burgers-credits.gif" alt="An animated gif of Jimmy Pesto Jr. dancing in the Bob’s Burgers outro."><h2>Preparing the artwork</h2><p>I started by drawing three full frames to see if it felt like a good direction to go. All the people I showed laughed when they saw it, so I decided to go all in.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2018-three-frames.jpg" alt="Three illustrations of Lynn, one with tiny, shrunken clothes, one normal, and one with huge, oversized clothes."><p>As I drew all the in-between frames, I realized it would be a lot to download, especially if I was using SVG (so many anchor points). So I continued making every frame for the items that needed it and reusable frames for other pieces.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2018-clothes-sprite.jpg" alt="An image sprite of all the frames for Lynn’s clothing."><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2018-faces.jpg" alt=""><p>The hair, faces, mouths, arms and legs became little reusable libraries. I sprited together as much as made sense to reduce the number of files.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2018-other-sprite.jpg" alt=""><p>And with SVG, every anchor point matters, so I spent some time simplifying and optimizing the artwork in Illustrator. I made small changes to reduce points, like smoothing lines, removing some shadowing, and ditching the ribbed lines on the hoodie’s cuffs.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2018-hoodies.jpg" alt=""><p>I’ll tell you what, I learned a lot of new shortcuts in Illustrator. Nothing quite like extremely tedious tasks to get you streamlining. After export, I ran it through a handful of SVG optimizers until I got a result I felt comfortable with.</p><p>In between all of that, I did dabble with the idea of using PNGs instead. File size was sometimes smaller, but I lost the scaling flexibility I ultimately decided I wanted.</p><h2>Markup and Styling</h2><p>Sorry this isn’t a single div 😂. I set up the background and character with the following markup:</p><pre><code>  &lt;div class=&quot;lynns-burgers&quot;&gt;
    &lt;div class=&quot;lynn&quot;&gt;
      &lt;div class=&quot;other legs&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;other shoes&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;clothes pants&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;other arm arm-left&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;other arm arm-right&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;other hair&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;other shirt&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;clothes hoodie&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;other face&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;other mouth&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
</code></pre>
<p>With regards to the CSS, I’ll start by saying I would not have attempted this without a preprocessor. I’m using Stylus variables and mixins a whole bunch to make everything more manageable (I ultimately needed to write over 220 media queries). This does add a lot of moving pieces and a few layers of abstraction. It made it worlds easier for me to accomplish what I needed but, as I’ve realized trying to write this, it makes things a lot harder to explain.</p><p>So, in the interest of time and all of our brain goo, I’ll go over a couple specific pieces that went into producing the animated sequence. If you want to dig in and see all the weird decisions I made, you can <a href="https://github.com/2dtrung/2dtrung.site">view the source code on GitHub</a>.</p><p>For most of the pieces (like the shoes, legs, clothing, hair), I give the <code>&lt;div&gt;</code> dimensions, declare a background sprite, and position it appropriately. Then its <code>background-position</code> is shifted, giving each media query a new frame of the sequence.</p><img class="wide border" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2018-placement-other.jpg"><p>Let’s say the frames changed every 20px, and the width of each <code>.hair</code> frame is 100px, then the CSS might look something like this:</p><pre><code>  @media screen and (min-width: 501px) and (max-width: 520px) {
    .hair {
      background-position: 0 0;
    }
  }
  @media screen and (min-width: 521px) and (max-width: 540px) {
    .hair {
      background-position: -100px 0;
    }
  }
  @media screen and (min-width: 541px) and (max-width: 560px) {
    .hair {
      background-position: -300px 0;
    }
  }
</code></pre>
<p>Some of the pieces (like arms, mouths, and chin dimples), needed to have their <code>background-position</code> changed with each query, but also to be positioned and sometimes rotated.</p><img class="wide border" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2018-placement-arms.jpg"><p>So a media query for these pieces might look more like this:</p><pre><code>  @media screen and (min-width: 501px) and (max-width: 520px) {
    .arm-left {
      background-position: -50px 0;
      left: 103px;
      top: 56px;
      transform: rotate(14deg);
    }
  }
</code></pre>
<p>This is <em>a lot</em> of CSS to write (44 frames for most character pieces), so Stylus is a huge help here. This might need some closer inspection at the source files to really grok, but here’s a preview of what I was doing.</p><p>I was able to reuse a lot of the media query syntax with variables and mixins:</p><pre><code class="language-css">  /* Set min-width and frame increment */
  $min-w = 412px
  $step = 23

  /* Shift background-position only */
  frame(number, args) {
    @media screen and (min-width: $min-w + $step * number) and (max-width: $min-w + $step * (number + 1) - 1) {
      background-position: args;
    }
  }

  /* Shift position only */
  move(number, left, bottom) {
    @media screen and (min-width: $min-w + $step * number) and (max-width: $min-w + $step * (number + 1) - 1) {
      left: left;
      bottom: bottom;
    }
  }

  /* Shift background-position, position, and rotate */
  place(number, args, left, top, deg) {
    @media screen and (min-width: $min-w + $step * number) and (max-width: $min-w + $step * (number + 1) - 1) {
      background-position: args;
      left: left;
      top: top;
      transform: rotate(deg);
    }
  }
</code></pre>
<p>With a bunch of other <a href="https://github.com/2dtrung/2dtrung.site/blob/master/_styl/pages/home/_variables.styl">variable declarations</a>, I was able to write each of the frames/queries like this:</p><pre><code class="language-css">  .hair
    frame(0, $hair-2)
    frame(1, $hair-3)
    frame(2, $hair-4)
    frame(3, $hair-2)
    frame(4, $hair-5)
    ...

  .arm-left
    place(0, $arm-3, calc(var(--arm-base) * .74), calc(var(--arm-base) * 1.18), 14deg)
    place(1, $arm-5, calc(var(--arm-base) * .72), calc(var(--arm-base) * 1.18), 10deg)
    place(2, $arm-7, calc(var(--arm-base) * .78), calc(var(--arm-base) * 1.22),  9deg)
    place(3, $arm-5, calc(var(--arm-base) * .78), calc(var(--arm-base) * 1.18),  4deg)
    place(4, $arm-5, calc(var(--arm-base) * .76), calc(var(--arm-base) * 1.18),  7deg)
    ...
</code></pre>
<p>I know that <code>place</code> declaration looks a bit scary, but it provided the most clarity for me about what was happening with each query. I’m using <code>calc()</code> and CSS custom properties here which I’ll get to in a bit.</p><h2>Hold up</h2><p>You might be wondering why I didn’t save the entire character for each frame so I’d only have to shift one large image sprite. Why the pain of all these different variables, mixins, and things?</p><p>The practical reason is the sprite would have been a ginormous file, even as a PNG and <em>especially</em> as an SVG. Breaking the illustration into pieces made file sizes more manageable.</p><p>But to be honest, shifting one large sprite just isn’t as fun?</p><p>I wanted to try this and see if I could do it. It was challenging and satisfying figuring out how to organize things, how to piece everything together, and how to work through all the small tweaks to make the animation work. Something something <a href="https://frankchimero.com/blog/2011/the-long-hard-stupid-way/">Frank Chimero, the long, hard, stupid way</a> something something.</p><h2>So what else was involved?</h2><p>There are a few more <a href="https://github.com/2dtrung/2dtrung.site/blob/master/_styl/pages/home/_breakpoints.styl">media query mixins</a> I used for more fine-grain control of what was happening. A ‘range’ query to have a frame show for multiple <code>$step</code> increments, a ‘hide’ query to add <code>display: none</code> to elements when they weren’t needed (like the legs once the pants grew long), and a ‘last’ query with no <code>max-width</code> for the final frame. Those would show up like this:</p><pre><code class="language-css">  .legs
    ...
    frame(        7,     $legs-1)
    frame-range(  8, 12, $legs-5)
    frame-range( 12, 16, $legs-2)
    hide-min(    16)

  .hair
    ...
    frame(       39,     $hair-2)
    frame-range( 40, 42, $hair-3)
    frame(       42,     $hair-2)
    frame-last(  43,     $hair-14)
</code></pre>
<p>There’s two different <code>$step</code> increments being set: 23px for laptop screens and 47px for monitor-sized screens. Most desktop users should get the full sequence without having to move to a larger screen.</p><p>For tall screens, the artwork gets resized which allowed me to dabble with CSS custom properties. With <code>calc()</code> and custom properties, it was easy to swap in new values depending on the user’s context. I know a transform probably would have worked too, but again, not as fun.</p><p>The site also takes advantage of some PostCSS plugins. I have four CSS files compiling from Stylus:</p><pre><code>  📂 css
    📄 generated-home-base.css    /* base styles */
    📄 generated-home-large.css   /* for monitor views, 47px step increment */
    📄 generated-home-small.css   /* for laptop views, 23px step increment */
    📄 generated-post.css         /* for PostCSS processing */
</code></pre>
<p>Note: If it was possible to use a combination of <code>calc()</code> and custom properties <em>inside</em> the media queries, I could have eliminated the need for separate large.css and small.css files.</p><p>PostCSS plugin <a href="https://www.npmjs.com/package/css-mqpacker">css_mqpacker</a> takes the large.css and small.css and consolidates repeated media queries. So the many, many media queries would go from something like this:</p><pre><code>  @media screen and (min-width: 401px) {
    .hair {
      background-position: -100px 0;
    }
  }
  @media screen and (min-width: 401px) {
    .legs {
      background-position: -200px -150px;
    }
  }
</code></pre>
<p>to something like this:</p><pre><code>  @media screen and (min-width: 401px) {
    .hair {
      background-position: -100px 0;
    }
    .legs {
      background-position: -200px -150px;
    }
  }
</code></pre>
<p>Seems small, but saves <em>a lot</em> of characters across 220 media queries.</p><p>Then <a href="https://www.npmjs.com/package/postcss-import">postcss_import</a> compiles the four files into one glorious home.css.</p><h2>Any weird hiccups?</h2><p>I originally had the <code>.lynns-burgers</code> container centered using flexbox. Easy peasy. But when I resized the browser, the artwork would shift left/right slightly every few pixels as it was repositioned. This created a vibrating effect that I did not like one bit.</p><p>Using the ol’ fixed position, then translate pattern did the trick. I’m guessing it’s because the calculation is happening on the width of element instead and the browser is never dividing an uneven number of pixels.</p><pre><code>  .lynns-burgers {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);
  }
</code></pre>
<p>But THEN, the character artwork started doing the vibration thing. Oy. The issue here was position values being calculated as decimals. I needed to make sure each <code>calc()</code> would return a whole pixel value, even as the custom properties changed.</p><p>So that would ultimately end up looking something like this:</p><pre><code class="language-css">  /* set custom properties */
  @media screen and (max-height: 900px) {
    :root {
      --mouth-base: 100px;
    }
  }
  @media screen and (min-height: 901px) {
    :root {
      --mouth-base: 150px;
    }
  }

  /* calculation multipliers should be even */
  .mouth
    place(0, $mouth-2,  calc(var(--mouth-base) * 1.14), calc(var(--mouth-base) * .52), -3deg)
    place(1, $mouth-12, calc(var(--mouth-base) * 1.16), calc(var(--mouth-base) * .52),  5deg)
    place(2, $mouth-14, calc(var(--mouth-base) * 1.18), calc(var(--mouth-base) * .50),  5deg)
    ...
</code></pre>
<h2>That’s it! Sort of.</h2><p>Looking through the final files and writing it all out makes it seem like so. much. (And there’s a lot I didn’t include here.) But it was definitely a process of discovery. I’m certain there are more efficient ways to do this, but that’s for another day.</p><img class="border" src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2018.jpg" alt=""><small class="footnote">The finished site!</small><h2>An Archive</h2><p>Oh! I also added an archive featuring <em>every</em> version of this site dating back to 2007. It was super fun to look back through them. I still love every one of them so much. You can <a href="https://2dtrung.site/archive">view them all in their dated glory here</a>.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-2018-archive.jpg" alt=""><h2>Whew, so… why all that?</h2><p>As usual, I wanted to try some new things and make something that might bring some joy to the web (it’s been a long year). <a href="https://2dtrung.site/thoughts/entries/why-do-work-without-a-practical-purpose/">Here’s a good reminder</a> of why I do work like this.</p><p>I’ve been spending a lot of time in Illustrator lately. I recently redid some <a href="https://css-tricks.com/snippets/css/complete-guide-grid/">CSS grid</a> and <a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/">flexbox diagrams</a> for CSSTricks and I’m working on a top secret illustration project with Heroku. You might say I’ve been in an illustratin’ mood.</p><p>I’ve never done frame animation like this and it was an insightful introduction. Wow, the patience it requires!</p><p>I was also able to gain some experience optimizing my Illustrator workflow, vector artwork, and exported SVGs. I got to dabble with CSS properties (so cool) and with PostCSS (also very cool).</p><p>And best of all I had fun with it. I hope you have fun with it too. Until next year!</p>]]></description>
      <pubDate>Thu, 20 Dec 2018 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/case-study-2018-refresh/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/case-study-2018-refresh/</guid>
    </item>

    <item>
      <title>Thoughts from Phoenix Design Week 2018</title>
      <description><![CDATA[<p>A few thoughts and highlights from this year’s Phoenix Design Week conference <em>Beyond Design</em>. But first, the rad intro video by the folks at <a href="https://magnetry.com/">Magnetry</a> in Phoenix:</p><div class="video-container wide"><iframe width="100%" src="https://player.vimeo.com/video/293427065" frameborder="0" allowfullscreen></iframe></div><p><a href="http://marshallshore.blogspot.com/">Marshall Shore</a>, the hip historian, emceed beautifully and shares my love for Arizona. As someone who usually dresses to blend in, I can appreciate his dramatic sartorial choices. Those jackets! So great.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/phxdw-marshall-shore.png"><hr><h2>Armin Vit, <a href="https://underconsideration.com/">Under Consideration</a>, <a href="https://www.underconsideration.com/brandnew/">Brand New</a></h2><p>The thing I found most fascinating about Armin’s talk was his utilization of unconventional materials. When creating custom conference materials he and his wife, <a href="https://underconsideration.com/about/">Bryony Gomez-Palacio</a>, explored mold-making, <a href="https://www.behance.net/gallery/70707339/2018-Brand-New-Conference-Identity">cement curing</a>, and <a href="https://underconsideration.com/favorite_things_weve_made/2016-brand-new-conference-identity/">screen printing on vinyl records</a> and <a href="https://underconsideration.com/favorite_things_weve_made/2017-brand-new-conference-identity/">highly reflective materials</a>. They made a lot of their materials tirelessly by hand. My favorite quote by Penn Jillette comes to mind here. He even admitted it can be hard to collaborate with others (besides his wife) because not many can match their pace and obsession.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/phxdw-armin-vit.png"><p>Process-wise, he’s not a great sketcher. He moves quickly from a “shitty” sketch into the domain he’s mastered, Adobe Illustrator. Sometimes it makes sense to jump right in. He has an interesting approach to file setup, working from the top left corner of an artboard down and to the right as he iterates. This creates a neat timeline of thoughts and trials, keeping the latest version always on the bottom right of the file. Here’s a sad, quick recreation of that:</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/phxdw-illustrator-sketch.png"><blockquote>I’m a fucking beast at Illustrator. I own it. Except actually I rent it from Adobe.<cite>Armin Vit</cite></blockquote><hr><h2>Anne Yoachim, <a href="http://small.tulane.edu/our-team/leadership/ann-yoachim/">Tulane School of Architecture</a></h2><p>Anne’s work is fascinating: designing for specific communities in New Orleans and implementing physical solutions in real spaces. Her team worked on visual communication surrounding Hurricane Katrina, set up a community book center for underserved youth, and started a <a href="http://rubarbike.com/">community bike shop</a> where kids can learn to build and fix bicycles together.</p><p>With her work in the community as examples, she encouraged us to examine the relationships between all the roles we play. What are the biases we benefit from and inject into our work? What power dynamics are in place?</p><blockquote>Design is a capacity builder for companies… but it can’t solve everything.<cite>Anne Yoachim</cite></blockquote><hr><h2>Shari Benko, Experience Designer</h2><p>In another talk about recognizing bias, <a href="http://www.sharibenko.com/">Shari Benko</a> spoke on the relationship between UX and AI. In a field where you’re teaching a system to make decisions, how can you be as transparent as possible? How do you predict behaviors of the people interacting with it? She posed this question which I’ve been thinking about a lot ever since:</p><blockquote>How do you design for distrust?<cite>Shari Benko</cite></blockquote><hr><h2>Nakita M. Pope, <a href="http://brandingchicks.com/">Branding Chicks</a></h2><p>Nakita is a ray of sunshine and pure charisma. Branding is not a specialty of mine, but she makes it super relatable. She has a personal, one-to-one approach to branding and identity and compares it to counseling:</p><blockquote>You can help people figure out who they are and most importantly, you can give them permission to be fully themselves.<cite>Nakita M. Pope</cite></blockquote><hr><h2>Steve Thompson, Disney</h2><p><a href="https://www.instagram.com/sthompsonart/">Steve Thompson</a> talked about getting a gig at Disney and how his career path really started with a foundation in life drawing. An influential teacher in his past encouraged him to “draw from life.” It was this back-to-basics approach that’s helped him throughout all the turns of his career. It’s easy to forget about the foundations, but sometimes the simple stuff is what we need to solve hard problems.</p><p>He’s got an effortless, natural drawing style and I just love it.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/phxdw-steve-thompson.png"><p>He also shared the inspiration he’s gained from taking circus class and mastering trapeze. It’s amazing the confidence we can achieve through other ventures outside of our work. It may seem unrelated, but it all affects the work we do and the way we can be fully ourselves. </p><hr><h2>Jon Arvizu, <a href="https://jonarvizu.com/">Illustrator + Designer</a></h2><p>I found Jon’s honesty refreshing, speaking about the challenges of running your own business: navigating legal documents, protecting intellectual property, pushing against a lack of motivation, and the stress of leaving things unfinished.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/phxdw-jon-arvizu.png"><p>He’s an illustrator and printmaker and his work is really fun. I especially loved his Arizona-themed work (of course).</p><hr><h2>Cat Swetel, Lost Embossing Consulting</h2><p><a href="https://www.catswetel.com/">Cat Swetel</a>’s talk was a breakdown of the <a href="https://en.wikipedia.org/wiki/A3_problem_solving">A3 problem solving technique</a>, but what I found most interesting was the portion about reframing the problems we’re trying to solve. We often come at problems with a solution already in mind.</p><p>She gave the example of feeling thirsty. Some may frame the problem as “I don’t have a glass of water.” which is too specific. It already has a solution built in. A better framing of the problem is “I’m dehydrated.” which could be solved in a number of ways.</p><p>A good lesson in taking a step back and observing, noticing what we may have overlooked, and adjusting our thought process.</p><hr><h2>Lisa Peña, The Design School at ASU</h2><p>Lisa should really give a talk on the main stage next year. Her talk on design awareness had a lot of practical and insightful examples of how we “unconsciously omit groups from our designs” and how we can recognize our biases and design better experiences.</p><p>A few examples she spoke about:</p><ul><li><a href="https://youtu.be/LhpUJRGrZgc">Rainbow Bagel Quest</a> shows the time and effort it took for Zach Anner, a person with cerebral palsy, to obtain an elusive rainbow bagel</li><li>Burger King asks the American Sign Language (ASL) community to <a href="https://youtu.be/1akWJ2fiems">create a sign for the Whopper</a></li><li>Toyota’s <a href="https://youtu.be/2DhI7D5sS5U">Mobility for All campaign</a><li><a href="https://youtu.be/dKCdV20zLMs">Sesame Street introduces Julia</a>, a muppet with autism</li></li><li>Tennessee Tourist Development installs <a href="https://youtu.be/zi7R66sgvfU">scenic viewfinders for people with colorblindness</a> to experience the state’s natural beauty</li></ul><hr><h2>Aaron Draplin, Draplin Design Co.</h2><p>A peek at Draplin’s new book <em>Pretty Much Everything</em>:</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/phxdw-draplin.jpg"><p>Draplin is of course incredibly prolific and showcased that with gusto here. He spoke with passion about how any little thing in our lives—yard sale signs, birthday invites, funeral pamphlets—can become deeply personal, well-designed creative endeavors.</p><p>He’s certainly a unique communicator, full of energy and misdirection. The kind of person with a story about everything.</p><hr><p>It would be remiss of me to not mention I also gave a talk at this year’s event. There was no video captured, but I plan to post slides and maybe a narrated slideshow soon. Stay tuned.</p>]]></description>
      <pubDate>Tue, 23 Oct 2018 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/thoughts-from-phxdw-2018/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/thoughts-from-phxdw-2018/</guid>
    </item>

    <item>
      <title>Why give a conference talk? But also, why not.</title>
      <description><![CDATA[<p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-conf-talk-guide.jpg" alt="@2dtrung’s Guide to Conference Talk Prep: 1. Thesis 2. Outline 3. Steam clean floors 4. Watch entire season of Scandal 5. Sob quietly 6. Slides"></p><p>Earlier this month I was deciding whether I should speak at a developer conference in the fall and found myself waffling between a pros and cons list. Turns out I ❤️ giving conference talks <em>and</em> I also don’t?</p><p>Every talk I’ve ever given was ultimately worth doing and I feel so, so grateful for each of those opportunities. But let’s be honest; prepping, traveling for, and giving a quality talk takes <em>work</em>, physically and emotionally.</p><p>This breakdown of benefits and drawbacks helped me think through the “why?” and “why not?” of speaking this time around.</p><h2>Truly great benefits</h2><p><strong>Learning</strong><br>Prepping a talk requires research and double and triple checking facts. Writing a loose script for others to experience helps me better understand and articulate my process and perspectives. Nothing helps me master a topic like teaching it.</p><p><strong>Personal growth</strong><br>Getting up on stage is <em>scary</em>. Public speaking is no joke in the fear department. Every time I do it, it becomes less intimidating and I become more confident.</p><p><strong>Visibility</strong><br>Giving talks helps introduce new people to my work. These are folks who I may never have met or reached in any other way. It’s super cool to see my projects’ traffic spike after a talk or to see my work shared anew on social media.</p><p>And although I’m not looking for a job, it’s helpful when potential employers have seen me speak or are already familiar with my work.</p><p><strong>Credibility</strong><br>Whether it should or not, our industry values speaking at conferences. Having talks on my resume or videos/slides to point to increases my credibility with peers, clients, and with future conferences I might want to speak at too.</p><p><strong>Introvert assist</strong><br>Chatting with people at large events can cause anxiety for me, especially if I’m attending solo. Being a speaker is like having an invisible wingperson. People will come talk to me about the topic I chose. It alleviates a lot of the pressure of small talk. Plus, if there’s a speaker dinner, that’s also a less stressful setting for conversation.</p><p><strong>That Feeling</strong>™<br>After I’m done giving a talk, I feel <em>incredible</em>. It’s a combination of adrenaline, accomplishment, relief, and a whole bunch of other emotions. All the preparation and the stress and the worrying feel completely worth it. I try to hold on to That Feeling™ for as long as I can. It’s the #1 thing that convinces me to do another talk later on.</p><h2>But of course there are drawbacks too</h2><p><strong>Time</strong><br>Even for a 30 minute talk, it takes me months of prep. Research, outline, write, slides, practice. Repeat until the minute I’m on stage. The majority of this work is done outside of my day job hours and a lot of conferences don’t pay their non-keynote speakers. So it can be a significant free time commitment.</p><p><strong>Stress</strong><br>Even if I feel fully prepared, every moment until the talk is completed I’ll feel stressed out. I’ll be thinking about the talk while in the shower, when I’m out with friends, and OMG I should be working on my talk instead of watching this episode of The Office for the 76th time.</p><p>If I have a lot of other emotionally demanding plans, the stress of a talk can be too much. Or it can cancel out the relaxation I hope for during a vacation.</p><p><strong>Visibility</strong><br>On the flipside, sometimes greater visibility can be harmful. Being in the spotlight provides opportunity for negative attention, creepers, or harassment.</p><p>Sometimes the last thing I want is for a large group of people to be looking at me or my work and I know that’s not the season for doing conference talks.</p><p><strong>Introvert kryptonite</strong>.<br>Although being a speaker assists in conversation, it also can be super draining. The stresses of traveling, speaking, and full days of lots of people can leave me ready for a 24-hour nap. I sometimes need to skip the closing party when my talk is scheduled for later in the day. Planning some time to recover is a must for me.</p><h2>Why or why not?</h2><p>After thinking things through <em>a lot</em>, I ultimately decided to decline the invitation even though it would have provided a free trip to Europe (oof) and would have been, as I was reminded by friends and family, Good For My Career (double oof). With FOMO ever-present, it can seem like a no brainer to say “yes.”</p><p>Sometimes “yes” is absolutely the right answer, and other times “no” is just as right for me. I know I’ll find another opportunity to speak if/when I feel up for it. And if you’re thinking of giving a conference talk, I do hope you find the right event for you. &lt;3</p><p>--</p><p><em>This was originally published on <a href="https://blog.andyet.com/2018/04/24/why-give-a-conference-talk-but-also-why-not">blog.andyet.com</a>.</em></p>]]></description>
      <pubDate>Tue, 24 Apr 2018 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/why-give-a-conference-talk-and-why-not/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/why-give-a-conference-talk-and-why-not/</guid>
    </item>

    <item>
      <title>Why do work without a practical purpose?</title>
      <description><![CDATA[<p>The first website I ever made was a fansite for a local Phoenix band called 17FourEyes. I was <em>obsessed</em> and compiled everything I knew about them, including transcribing the lyrics to their songs from demos and an eventual EP (I found out later I got a lot wrong). Through the site’s forum I connected with another fan where we gushed together and we eventually started hanging out at their shows. It was just so cool and got me hooked on the magic of the web.</p><p>Fifteen years later you could argue that most of my projects are still glorified fansites. Digital love letters to <a href="https://a.singlediv.com">CSS</a>, <a href="https://airportcod.es">airports</a>, <a href="https://topchefstats.com">reality cooking competitions</a>, and my home state of <a href="https://why.az">Arizona</a>.</p><p>I joke that I pride myself on creating projects that compel people to post on the internet asking “Why do this?” I recognize my work isn’t for everyone. As recently as last week a friend of mine, who no doubt gets <em>me</em>, said about the popularity of my <a href="https://airportcod.es">airportcod.es</a> project, “I just don’t get it.”</p><p>A lot of people question the practicality of the work or search for a deeper purpose:</p><p></em>“Just wondering, is there any legitimate reason for doing this?”</em></p><p></em>“Sure, it’s challenging, but why should anybody care?”</em></p><p></em>“Really nice but I really don't see the point.”</em></p><p></em>“Nice one, but WHY??”</em></p><p>My CSS drawing project, <a href="https://a.singlediv.com">a.singlediv.com</a>, is usually on the receiving end of the “Why?”, but my <a href="https://2dtrung.site/thoughts/entries/case-study-2017-refresh">recent portfolio redesign</a> brought a fresh set of questioning.</p><p>My prepared goto answer is that these projects are just for fun and hey, it’s fun to do things that are weird. While technically true, there’s so much more I’m trying to do.</p><p>So… why then?</p><p>Why do we create art at all? Some artists create solely for themselves as a means of introspection and self expression. I truly love that. However, I’m not one of those artists.</p><p>I begin my process thinking about who will consume my work and how I hope they’ll respond to it. Art does not exist in isolation and it gains meaning from the people who experience it. It cannot be separate from the context in which it was created and the history of work that came before it. Those who view and participate in the work gain (or sometimes lose) something too.</p><h2>Seeing</h2><p>Have you ever had a friend send you an image and they say “This is incredible!”? You look at it. It has nice lighting I guess? What’s the big deal? “No, no. It’s not a photo. It’s a 12-foot oil painting.” In a small, special moment you aren’t sure if your eyes are playing tricks on you. “Whaaat?”</p><p>I <em>love</em> that feeling. Where someone’s work makes you question your reality. It begs you to dig deeper into how they did it. You want to, or in the best cases, <em>must</em> look closer. Imagine creating something that causes a tiny explosion in someone’s brain. When people view my work, I hope they might say “I didn’t know this was possible.”</p><p>Similarly, I love when someone’s work opens your eyes to something that was <em>always there</em>. A tool used in a new way, a pattern you never noticed, or the story behind a name. In an instant, this everyday thing is suddenly <em>different</em> and you can’t unsee it. The response I hope for in this case is, “Oh wow. Of course.”</p><p>Being surprised, stretching our imaginations, seeing things differently. Each an intention of the work and something I gain personally from creating it.</p><p>Experiences like this (as a viewer and a creator) are super valuable for me, especially long term. Every day we’re learning things that will be practical <em>someday</em>. You may not even realize you’re building this complex web of knowledge. We call it “intuition” but a big part of being an experienced designer/developer/whatever is how vast your web is and how effectively you can make connections between the disparate information and apply them to solve real problems.</p><h2>Challenging</h2><p>“Well, which is it? Art or design?!” a frustrated Redditor asks, trying to make sense of one of my projects. That question made me so happy. I want people who feel confused about what the work <em>is</em> to also question why they want to categorize it.</p><p>Designers do this a lot. I wish I had a piece of pizza for every “Design isn’t art” article I’ve seen. Art and design overlap in deep, meaningful ways and drawing a line between them does both a disservice. Also true for technology, where some want to draw the line even deeper. I want my work to blur the edges. I’m always amazed at the kind of magic we can create in the space where disciplines overlap.</p><p>Doing this work on the web specifically asks people to think about medium. I pay close attention when someone critiques art by saying the artist “must have a lot of time on their hands.” Almost always, it’s in response to work that’s made of unconventional material. Detailed portraits on Starbucks cardboard sleeves or styrofoam cups, landscapes constructed with thousands of matchsticks, drawings made with a single div and CSS. Very rarely does anyone say this about photography, oil painting, or stone sculpture.</p><p>What about a medium makes us value the time spent with it? I hope every person who views my CSS illustrations and says, “I can’t help but ask… why not just use SVG?” really does think about why. What would the work <em>be</em> if it was created in a format that’s obviously better suited? The medium we choose to work in is <em>part of the work</em> and contributes to its meaning.</p><h2>Sharing</h2><p>Lately the web can feel like an overwhelming sea of misery. (I won’t get into it. You know.) But it’s still such a joy to discover someone who shares in your weird, obsessive love for something. Maybe you stumble upon a website that feels like it was made just for you.</p><p>“Stumbling” upon something is such an important part of the web we take for granted. A huge contributor to a work of art’s meaning is how people access it. Does it exist in a physical space? Must you pay to enter that space and are the hours of access limited? Can people participate in it, contribute to it?</p><p>Connecting through art or shared passion is a gift and the web makes that possible at a scale unlike anything before. My little fansite turned a stranger into a friend, connecting on the web and at rock shows in the Nile basement. And that magic has only grown with every project since.</p><p>The joy we feel about the things we love is worth sharing and I encourage you to do it! You and the people viewing your work can benefit in a lot of ways, even if “the practicality of this is just non-existent.” 😉</p><p>--</p><p><em>This was originally published on <a href="https://blog.andyet.com/2018/01/24/why-do-work-without-a-practical-purpose">blog.andyet.com</a>.</em></p>]]></description>
      <pubDate>Wed, 24 Jan 2018 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/why-do-work-without-a-practical-purpose/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/why-do-work-without-a-practical-purpose/</guid>
    </item>

    <item>
      <title>Case Study: 2dtrung.site 2017 refresh</title>
      <description><![CDATA[<p>Over the past ten years I’ve made ten different versions of my website. I call it my annual portfolio “refresh” since the content usually stays the same. I do always start with a blank CSS file.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-version-old.jpg"><small class="footnote">some past iterations of <a href="https://2dtrung.site">2dtrung.site</a></small><p>I do this each year for a few reasons:</p><ul><li>to ensure I’ll complete at least one non-work project</li><li>to experiment with and learn new techniques (a few standout refreshes were my first attempts at responsive design, flexbox, and this year, CSS grid)</li><li>a year is about the right amount of time for a version to exist where I don’t feel sad once I sit down to change it</li></ul><p>Also, a truly great thing about redoing my own site is that it’s fully mine and I can do whatever the heck I want. 😊</p><p>A very small percentage of my portfolio’s visitors are <a href="https://airportcod.es/">airport enthusiasts</a>, <a href="https://topchefstats.com/">Top Chef viewers</a>, and family (hi, mom). But the primary audience is overwhelmingly web designers, developers, and tech recruiters. These are people who know how websites are built and might take an extra minute to inspect things. I wanted to design around that.</p><h2>Concept and inspiration</h2><p>For years we’ve been telling the world that a website doesn’t need to look the exact same in every browser for every user. With responsive design and progressive enhancement, users <em>will</em> see things differently. Not everyone needs to experience the entirety of the site.</p><p>But could I make people <em>want</em> to experience all of it? Could I surprise them by taking these concepts to an absurd extreme?</p><p>I love to resize my browser and see how the layout responds and how the designer decided when things change and what gets dropped or added. I know lots of other people do this too. I initially thought I could subvert expectations by making the ubiquitous phone, tablet, and desktop breakpoints trigger completely different layouts with unique styles, colors, and type treatments. Three sites in one.</p><p>The changes, as dramatic as they might have been, still felt too conventional. You already expect something to happen at tablet size and then again for phones.</p><p>I’d recently watched a <a href="https://youtu.be/Vy2Vhnqtu8I">YouTube video</a> about the <a href="https://en.wikipedia.org/wiki/Kuleshov_effect">Kuleshov Effect</a>, a term in film editing that describes “a phenomenon by which viewers derive more meaning from the interaction of two sequential shots than from a single shot in isolation.” A metaphorical bell chimed in my head.</p><p>There’s preexisting meaning for a site to have three (or a few more) distinct layouts: supporting common devices. But what would it <em>mean</em> for there to be 10, 15, or ultimately 21 distinct designs that “sit” side by side for you to discover one at a time, one after the other. Each one may be unremarkable on its own, but it’s the relationships (and differences) with the ones to the left/right and to the 18 others that make each one worth looking at.</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-version-new.jpg"><small class="footnote">A preview of <a href="https://2dtrung.site">2dtrung.site</a></small><h2>Executing the idea</h2><p>I already knew it was possible to use CSS to turn basic markup into something extraordinary. <a href="http://www.csszengarden.com/">CSS Zen Garden</a> showed us this repeatedly for years. Another side project of mine, <a href="http://a.singlediv.com">a.singlediv.com</a>, takes this concept to ridiculous extremes (I sense a pattern here).</p><p>So executing this redesign started with basic HTML. One thing I’ve learned over the years of experimenting with CSS is you can achieve <em>a lot</em> without needing to sacrifice clean markup. Here’s what I landed on. The <code>&lt;span&gt;</code>s inside of the <code>&lt;h1&gt;</code> and <code>&lt;p class='intro'&gt;</code> would allow me to style each line differently if I needed and the <code>&lt;picture&gt;</code> element would allow for a responsive image plus provide additional <code>:before</code> and <code>:after</code> pseudo-elements (which <code>&lt;img&gt;</code> doesn’t allow).</p>
<pre><code>&lt;body class='home'&gt;
  &lt;nav class='main-nav'&gt;
    &lt;a class='nav-home' href='/'&gt;Home&lt;/a&gt;
    &lt;a class='nav-web' href='/web'&gt;Web&lt;/a&gt;
    &lt;a class='nav-art' href='/art'&gt;Art&lt;/a&gt;
    &lt;a class='nav-about' href='/about'&gt;About&lt;/a&gt;
    &lt;a class='nav-thoughts' href='/thoughts'&gt;Thoughts&lt;/a&gt;
  &lt;/nav&gt;

  &lt;h1&gt;
    &lt;span class='name'&gt;Trung. Do Duc&lt;/span&gt;
    &lt;span class='desc'&gt;Senior Frontend Developer, Javascript Engineer and UX Engineer with over 7+ years of experience&lt;/span&gt;
  &lt;/h1&gt;

  &lt;p class='intro'&gt;
    &lt;span&gt;I make things for the web and for walls.&lt;/span&gt;
    &lt;span&gt;I specialize in light-hearted projects that make people say, “I don’t get it.”&lt;/span&gt;
    &lt;span&gt;Yes, I’ve heard of SVG.&lt;/span&gt;
  &lt;/p&gt;

  &lt;picture class='lynn'&gt;
    &lt;source srcset='https://2dtrung.site/assets/images/lynn-small.png' media='(max-width: 1400px)'&gt;
    &lt;source srcset='https://2dtrung.site/assets/images/lynn.png'&gt;
    &lt;img src='https://2dtrung.site/assets/images/lynn.png', alt='a photo of the artist'&gt;
  &lt;/picture&gt;
&lt;/body&gt;
</code></pre>
<p>Also I guess I should add a disclaimer here. I’m the only one touching this code so I set things up the way that worked for me. Of course there are different and surely better ways of doing all of this. 🙂</p><p>I use Stylus for CSS preprocessing (and will in the following examples). I first created a <code>home.styl</code> where a reset and variables would be imported, basic page styles would be declared, and where the media queries would be set up. It, plus the other pages, would import into one <code>main.styl</code> that gets compiled and minimized. The structure looks like this:</p>
<pre><code>📁 _styl
  📁 components
  📁 globals
  📂 pages
    📄 about.styl
    📄 home.styl
    📄 thoughts.styl
    📄 work.styl
  📄 main.styl
</code></pre>
<p>I planned on using CSS grid for this redesign, so I created a super basic fallback layout to show by default (separated into its own file in a <code>home</code> directory) and I placed everything else inside a <code>@supports</code> declaration.</p>
<pre><code>📁 _styl
  📂 pages
    📂 home
      📄 fallback.styl
    📄 home.styl
  📄 main.styl
</code></pre>
<pre><code>/* home.styl */

@import 'home/fallback'

@supports (display: grid)
  body.home
    [base styles here]
</code></pre>
<p>If a browser doesn’t support <code>display: grid</code> it will render the fallback, which looks like this:</p><img src="https://2dtrung.sitehttps://2dtrung.site/assets/images/2dtrung-version-fallback.jpg"><p>With a fallback in place, I could now focus on the many different layouts. To keep things manageable, I split up each layout into its own file alongside the <code>fallback.styl</code> in the <code>home</code> directory (don’t mind my ridiculous naming).</p>
<pre><code>📁 _styl
  📂 pages
    📂 home
      📄 b-and-w-and-gold-all-over.styl
      📄 big-nav.style
      📄 big.styl
      📄 blockhead.styl
      📄 bolt.style
      📄 cutout.styl
      📄 diagonal.styl
      📄 disguise.styl
      📄 fallback.styl
      📄 fifty-fifty.styl
      📄 half.styl
      📄 L-Y-N-N.styl
      📄 landscape.styl
      📄 movie.styl
      📄 pop-out.styl
      📄 rotate.styl
      📄 stranger.styl
      📄 third.styl
      📄 triangle.styl
      📄 white-bars.styl
      📄 white-box.styl
      📄 x.styl
    📄 home.styl
  📄 main.styl
</code></pre>
<p>Then I was able to import each layout into its own media query:</p>
<pre><code>/* home.styl */

@supports (display: grid)
  body.home
    [base styles here]

  @media screen and (max-width: 400px)
    @import 'home/diagonal'

  @media screen and (min-width: 401px) and (max-width: 500px)
    @import 'home/L-Y-N-N'

  @media screen and (min-width: 501px) and (max-width: 600px)
    @import 'home/blockhead'

  + 18 more (2300px being the widest media query)
</code></pre>
<p>This removes any collisions that might happen and eliminates the need to do massive overrides. There is some repeated styling across various layouts, but I found that acceptable to keep things clear and organized. Each breakpoint is only using the CSS it needs for its specific layout.</p><h2>Further learning</h2><p>If you’re interested in digging into the CSS a bit more or to inspect individual layouts, I made my repo <a href="https://github.com/2dtrung/2dtrung.site">public on GitHub</a>. 🙈</p><p>I won’t go into how to use grid here as <a href="https://twitter.com/rachelandrew">Rachel Andrew</a> and <a href="https://twitter.com/jensimmons">Jen Simmons</a> have written and spoken extensively on the topic. See Rachel’s <a href="https://gridbyexample.com/">Grid by Example</a> and Jen’s <a href="http://labs.jensimmons.com/">Experimental Layout Lab</a> as good places to start.</p><p><a href="https://twitter.com/patrickbrosset">Patrick Brosset</a> of Mozilla created a video breaking down the use of grid for one of my site’s layouts which is pretty cool:</p><div class="video-container wide"><iframe width="100%" src="https://www.youtube.com/embed/wmhYScbIxYk?rel=0" frameborder="0" allowfullscreen>></iframe></div><p>I planned on elaborating on some of my favorite parts of the redesign here, but I think I want people to be surprised as they explore. So if you haven’t checked it out yet, please do at <a href="https://2dtrung.site">2dtrung.site</a>.</p><h2>Response</h2><p>I always hope my work will inspire people to think about their medium and tools differently and to encourage them to experiment with what’s possible.</p><p>The response has been overwhelming and it’s truly wonderful to see people discovering and enjoying the site. I’m so grateful for everyone’s kind and encouraging words.</p><p>One piece of feedback I received is that a lot of people don’t resize their browsers at all. That’s true! And it’s totally okay. The site is still functional even if you don’t know any of the other layouts exist. Well, to be fair, there is one layout that would make for a super confusing experience (<em>Stranger Things</em> fans might know which one I’m talking about). But with my audience in mind, I figured risk was low.</p><p>With most of my work, there are people who ask “Why do this?” I have another post in the works that dives into the many reasons, but for now: sometimes it’s fun to do things that are weird.</p><p>Thanks for checking out the site. It means the world.</p><p>--</p><p><em>This was originally published on <a href="https://blog.andyet.com/2018/01/09/case-study-2dtrung-refresh">blog.andyet.com</a>.</em></p>]]></description>
      <pubDate>Tue, 09 Jan 2018 16:00:00 +0000</pubDate>
      <link>https://2dtrung.site/thoughts/entries/case-study-2017-refresh/</link>
      <guid isPermaLink="true">https://2dtrung.site/thoughts/entries/case-study-2017-refresh/</guid>
    </item>

  </channel>
</rss>
