<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <atom:link href="https://pauljmiller.com/rss.xml" rel="self" type="application/rss+xml" />

    <title>
      Paul's blog
    </title>
    <description>Paul's blog</description>
    <link>https://pauljmiller.com</link>
    
    <lastBuildDate>Thu,  5 Dec 2024 00:01:59 +0000</lastBuildDate>
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    <generator>https://github.com/futurepaul/my-own-personal-blog</generator>

    <item>
      <title>
        Why podcasts won
      </title>
      <link>https://pauljmiller.com/posts/podcasts.html</link>
      <pubDate>Thu,  5 Dec 2024 00:01:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/podcasts.html</guid>
      <description>
        <![CDATA[<p>Not to brag too hard, but I did a &quot;podcast&quot; before the term was invented. It was called &quot;Skippy Republic Radio,&quot; it was published in 2001-ish, and it was me and my best friend Geoff breaking down the important anime and video game news of the week.</p>
<p>I don't remember how we found microphones, or what audio interface we used, or what exact anime we talked about, but I do remember cringing when I listened to my voice, and especially my constant use of the filler-phrase &quot;it will be interesting to see...&quot; to punt the focus to an unknown future in the frequent instances I didn't have any information or opinion to add.</p>
<p>Little did I know I was &quot;early&quot; to a medium that 23 years later would be widely credited with a widespread political reorientation of the country and the election of a president.</p>
<p>I got the idea from my favorite magazine at the time, <em>MacAddict</em>, in its February '99 &quot;Pirate Issue.&quot;</p>
<p><img src="../static/images/macaddict_feb_99.jpg" alt="MacAddict Pirate Issue" /></p>
<p>&quot;Set up a renegade Internet RADIO STATION,&quot; the headline promised!</p>
<p>And so I did. Publishing your own &quot;radio show&quot; on the internet felt subversive because I lived in an era where the only forms of public broadcast were on government-regulated radio airwaves, or corporate-owned cable channels, or government-owned &quot;public access.&quot; Or you had to publish a book, or... I don't know... mail people VHS tapes?</p>
<p>Broadcasting your <em>own</em> show without anyone's permission was closely associated with illegality because the most well-known instances of it, pirate radio, were literally people breaking the law to broadcast on government-restricted radio spectrum.</p>
<p>My buddy Geoff and I, in addition to loving anime, Pokémon, and video games, idolized Weird Al Yankovich, whose film <em>UHF</em> had a total pirate radio vibe to it. It was based on this <em>crazy</em> premise that a well-meaning weirdo might accidentally end up with the legal right to broadcast entertainment he thought was cool.</p>
<p>In the decades since, most &quot;UHF&quot; spectrum (ultra-high frequency) has been auctioned off by the government for use in DTV (digital TV) and modern cellphone networks. It's quite likely that in the alternate universe of <em>UHF</em>, a 2024 Weird Al would no longer own the rights to broadcast weird television programs to his friends.</p>
<p>But he might have a podcast.</p>
<p>Of course, the real etymology of the term &quot;podcast&quot; comes from the &quot;iPod&quot;. Back when we called it &quot;internet radio,&quot; it was just nerds on computers listening to shows. My Skippy Republic Radio show had perhaps four listeners all-time. Portable MP3 players, a technology which the iPod brought to the mainstream in the early 2000s, meant you could now listen to an &quot;internet radio show&quot; in all the same places you listened to regular radio: on a commute, at the gym, while doing chores.</p>
<p>But the other fundamental technological &quot;breakthrough&quot; that led to the podcast's enduring and world-shifting success was RSS.</p>
<p>I think RSS is well-known and well-loved already in technology circles. But I feel like it's completely under-appreciated by the normie public, so I want to try and break down how impactful it is.</p>
<p>RSS stands for &quot;Really Simple Syndication,&quot; and it's simply a standard for publishing a &quot;feed&quot; of items. The original application was blog posts. Instead of you having to come to my website every day to check if I've published a new blog post, you could &quot;subscribe&quot; to my RSS &quot;feed&quot; and my new blog posts would be delivered to your &quot;feed reader&quot; next to all the other blogs you subscribe to.</p>
<p>Podcasts can travel over this same medium. Instead of text &quot;blog posts&quot; you publish audio podcast &quot;episodes&quot; and your &quot;podcast app&quot; shows you all the new episodes as they're published.</p>
<p>The technology is so &quot;Really&quot; simple that its impact isn't immediately obvious. Let me give a case study to help demonstrate this.</p>
<p>The first tech publication I worked for was Engadget. I began as a super-fan of the &quot;website,&quot; and when I say &quot;website&quot; I actually mean the RSS feed of blog posts. Engadget was, during prime hours, this constant feed of new posts about tech every 20-30 minutes. It would feel odd to check back on a website so often &quot;just in case&quot; something new hit the home page. But having an RSS reader app on my computer meant the posts just came to me, hot off the presses.</p>
<p>When Engadget launched a podcast, starring its founders Peter Rojas and Ryan Block, I ate it up. I don't even remember what device I was using at the time to listen, but I know I never missed an episode. Hanging with the boys? Talking about megapixels and gigahertz and QWERTY phone keyboards? Pump it straight into my veins.</p>
<p>The first episode of the Engadget Podcast was in 2004, and interestingly <a href="https://www.engadget.com/2004-10-05-engadget-podcast-001-10-05-2004-how-to-podcasting-get.html">the announcement post</a> (which pinged into my RSS reader alongside the regular feed of news about iterative digital camera upgrades and new laptops), includes an in-depth guide on <em>what</em> a podcast is, <em>how</em> to subscribe to a podcast, and even <em>how</em> the Engadget Podcast itself was produced.</p>
<p>I guess it felt obvious at the time that podcasting was a &quot;technology,&quot; and so while the podcast was <em>about</em> technology, it was also introduced to the Engadget audience <em>as</em> a technology.</p>
<p>But here's where it gets more interesting for today's purposes: Peter Rojas and Ryan Block in turn eventually left Engadget. And I was slowly introduced onto the show as a co-host. And I eventually co-hosted the show with the next editors of Engadget. And when we left Engadget? The show was continued by our own replacements.</p>
<p>RSS is &quot;sticky&quot; like that. People who subscribed for Peter and Ryan might barely be able to tolerate my &quot;it will be interesting to see...&quot; hot takes about the Blackberry Storm, but these dang episodes keep showing up in their feed (unless they go through the trouble of unsubscribing), and in many cases me and replacement co-hosts won that war of attrition.</p>
<p>Podcasts are sticky in another way. When my co-hosts and I left Engadget to start a new publication, we didn't even have a name for that publication yet. But we started a podcast. We called it &quot;This Is My Next,&quot; and we launched it immediately (and costlessly, RSS is simple remember?) after leaving Engadget so that our audience could quickly follow us before they built new podcasting habits.</p>
<p>So RSS is both &quot;sticky&quot; for a publisher to maintain an audience, and &quot;cheap&quot; for an upstart to spin up and attract a new or existing audience.</p>
<p>This is a <em>wild</em> combination in the history of media.</p>
<p>A <em>The New York Times</em> subscription is &quot;sticky.&quot; The newsletter I make 20 copies of on the office copy machine is &quot;cheap.&quot; Watching <em>60 Minutes</em> after Sunday night football is &quot;sticky.&quot; Bullshitting with your friends around a dinner table is &quot;cheap.&quot;</p>
<p>Somehow, magically, podcasts combined both properties.</p>
<p>Okay, fun history lesson, but what do these &quot;RSS&quot; feeds have to do with modern podcasting? Most people watch their &quot;podcasts&quot; on YouTube, which is a proprietary platform. <em>The Joe Rogan Experience</em>, the world's biggest and most influential podcast, launched originally as a video show, and is published on Spotify, another proprietary platform.</p>
<p>So didn't RSS lose in the long run? Was it &quot;RSS&quot; that unseated <em>CNN</em> and <em>Fox News</em> for political primacy? Or was it actually Spotify and YouTube? Big tech won. Not the little guy, right?</p>
<p>I'm biased, but I would argue that RSS still deserves some credit for this victory. And either way, the little guy is doing even better than he seems. Big tech can win in the short term, but simple, useful protocols like RSS are hard to kill.</p>
<p>In 2020, Joe Rogan's podcast went exclusive on Spotify, in exchange for over $200 million. Spotify basically paid Joe Rogan that money to <em>not</em> use RSS. Spotify could grow its platform by getting such a popular and sticky host. And now, in 2024, Joe Rogan is no longer exclusive, publishes full episodes to his RSS feed (which never totally went away), and Spotify paid him $250 million for this now non-exclusive setup.</p>
<p>Spotify could rely on the stickiness of Joe Rogan to bring people to their inconvenient and arbitrarily constrained platform in order to gain users. And Joe Rogan, once the deal was up, was able to cheaply and quickly spin up the sort of multi-platform (RSS-included) distribution his fans preferred.</p>
<p>Spotify paid big money to break into the podcast game, and now that they're a popular podcast platform, they don't seem to mind so much some randoms like me subscribing to &quot;their&quot; shows with alternative RSS-based podcast apps. RSS wins.</p>
<p>RSS doesn't have to be ubiquitous or even well-known to be powerful. It's an implicit threat. During the censorship bonanza of 2015-2023ish, shows whose medium was highly specific to a certain platform and algorithm were in constant danger of being shut down and booted to irrelevancy. But podcasts always had RSS as a backstop.</p>
<p>In an era dominated by platforms like YouTube, Facebook, and Twitter, RSS was the rare instance of &quot;self-hosted&quot; media. It was easy to get interesting and controversial shows banned by the willing stooges at big tech. But RSS-based podcasts were so diffuse, self-published, and hydra-esque that a broad direct banning campaign of RSS feeds themselves has never even been tried.</p>
<p>Even if you got a show booted off Apple's industry-leading podcast directory, which happened famously with Alex Jones, that <em>still</em> wouldn't end a podcast. The directory is huge for a podcast's discoverability and growth, but an RSS feed is a direct relationship between the user and the publisher, no platform permission required.</p>
<p>My favorite podcast during the lockdowns, Dave Smith's <em>Part Of The Problem</em> had its community Facebook group deplatformed. The show was constantly in danger of &quot;strikes&quot; or a looming ban from YouTube (which led to admitted self-censorship at the time, RSS hasn't fixed everything). And yet I enjoyed every single episode of the show completely unbothered on my humble RSS-based podcast app.</p>
<p>I don't even know if <em>POTP</em>'s RSS-based distribution outdid YouTube or Spotify in raw numbers. It's the fact that RSS was always there as a backstop that made the threat of censorship on those other platforms less effectual. Direct RSS distribution is the highly credible escape route that ruins the enemy's plan before it's even executed.</p>
<p>In the case of the attempted cancellation of Joe Rogan in 2022, I have no detailed knowledge of the situation, but part of me strongly believes that Joe Rogan survived because of the backstop of RSS. He had brought an immense audience with him to Spotify. And RSS exists. So he could weather the storm, safe in the knowledge that he can bring his audience with him to his own RSS feed the instant Spotify blinks.</p>
<p>&quot;I could self-publish this shit, I've done it before,&quot; is the plausible escape route. RSS-lovers like me bemoaned Joe's move to Spotify. You could argue it's actually limited his reach. He might be an even <em>bigger</em> deal in 2024 if he had stayed platform agnostic. And yet, even though Joe left RSS, RSS never stopped working as a credible backstop and defense against the woke mob.</p>
<p><em>And every single podcast with a committed audience is in that same position.</em></p>
<p>Podcasters are for sure playing with fire when they overly rely on algorithmic distribution like YouTube or TikTok. They might enjoy broader reach while they're in favor, but if they never achieve the &quot;stickiness&quot; of a real podcast subscription, their star will likely fade.</p>
<p>Once again, RSS is the winning move, the safe harbor for the creator.</p>
<p>And what's even better, podcasts are not just anti-fragile, sticky, easy to start, and easy to distribute, they're also <em>really good</em>.</p>
<p>Dave Smith had a great point on this (on his podcast, naturally): there are certain dumb ideas, such as &quot;transing the kids,&quot; that could only survive in a TV-dominated, short sound byte era. Transing the kids is a no-go when you have three hours to explain why it's a bad idea. Some idea parasites can no longer find a viable host, and good riddance.</p>
<p>I remember at some point between the years between 2010 and 2020 I discovered that podcasts were a particularly &quot;male&quot; medium. I'm embarrassed now to say that I was embarrassed then to be so enraptured with a medium that was largely unappealing to the fairer sex. In hindsight, I'm so grateful for the masculine urge to listen to podcasts, and the masculine urge to start a podcast.</p>
<p>Perhaps there's something quintessentially &quot;male&quot; about wanting a self-directed media diet, long form discussions, topical and historical deep dives, and bros clowning on bros. If so, the media landscape has been offering starvation portions to men for most of the 20th century. And now, &quot;all of a sudden&quot; (after two decades of steady growth), podcasts have been declared the most important medium, at least in the realm of the political conversation.</p>
<p>If you asked me to delete media formats one by one, starting with what's least precious to me, I would delete all of TV, and then movies, and even music, before I got rid of podcasts. Only books, and the truest signal of actually having a real conversation with your bros, come to mind as more valuable than me.</p>
<p>Podcasts are good. Podcasts won. RSS won.</p>
<p>Long live pirate radio.</p>
]]>
      </description>
    </item>
    <item>
      <title>
        Ten years on the internet
      </title>
      <link>https://pauljmiller.com/posts/internet.html</link>
      <pubDate>Mon,  1 May 2023 00:01:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/internet.html</guid>
      <description>
        <![CDATA[<p>Well, it's been 10 years since I finished <a href="https://www.theverge.com/2013/5/1/4279674/im-still-here-back-online-after-a-year-without-the-internet">my &quot;year without the internet.&quot;</a></p>
<p>So what's changed since then?</p>
<p>I use the internet a lot. My screen time is dialed up to the max. I'm obsessed with YouTube. I flip over to Hacker News or the Rust subreddit anytime my mind wanders. I pop open Twitter a couple times a day, don't find much that resonates, then scroll Damus for a few minutes for the good Nostr vibes. I talk to ChatGPT to brainstorm coding problems. I let GitHub Copilot's autocomplete write boilerplate for me. I search GitHub codebases for solutions because Stack Overflow is rarely specific enough. I send myself notes on Signal and even talk to friends on there. I check email a couple times a week. I run a synced bitcoin node at home. I send money with lightning on a regular basis. I design in Figma, I listen to Spotify, I watch Korean dramas on Netflix, I subscribe to dozens of podcasts on Pocket Casts, I spend all of my Audible credits. I use Bible Hub for comparative translations and iMessage my pastor the juicy bits. I write websites in React, Svelte, and Solid. I build web servers in Rust. This text document I'm writing right now is backed up to <em>the cloud</em>.</p>
<p>I'm just an internet man, man.</p>
<p>A lot has happened in the past 10 years. I've moved in and out of New York a few times. I've moved in with my parents twice. For almost two years now I've been living in Austin, TX, which has been wonderful but it sure took me a long time to discover.</p>
<p>Probably the most fundamental change in my life is that I'm no longer a journalist, and hardly even a writer: I &quot;learned to code.&quot; As a technology writer I realized I was jealous of the people I was writing about, envying them for building something. I wanted to build things. So I started the slow (for me) process of learning how to build things with code.</p>
<p>I actually <a href="https://eloquentjavascript.net/">had a book on Javascript</a> that I worked through a little back in 2012 / 2013 when I was off the internet. Every part of coding was difficult for me. I especially remember struggling with the concept of &quot;this.&quot; After I got back on the internet it was obviously easier to find resources. It was also easier to get distracted by new and shiny things: I dabbled with Clojure, Elixir, and eventually became extremely interested in Rust. <a href="https://github.com/linebender/druid/pull/39">My first ever pull request</a> was to a GUI Rust project called Druid. I was able to collaborate with the project maintainers over a Slack alternative called Zulip to guide me through the terrifying process of merging my shoddy work with their magnificent codebase.</p>
<p>In 2020 I felt like I was &quot;ready&quot; for a job as a developer and started applying for jobs. Coincidentally, 2020 was when my stint as a podcaster at The Verge ended, formally ending my tenure in journalism, and fimrly putting me in need of a job. I got a job through Twitter, so thanks internet. And then when that job ended, I got another job through Twitter, so double thanks internet.</p>
<p>Being a developer is just as satisfying as I hoped it would be, I absolutely <em>love</em> being able to create things with code. Being a developer also holds a ton of frustration that I wasn't really prepared or practiced for: being stuck on writing is more of a state of mind, being stuck on coding is just a fact. It doesn't work. It's my fault. I'm dumb, it turns out. I should've never learned to code. I should become a farmer.</p>
<p>Usually I figure it out, typically through prayer.</p>
<p>Now that I can build stuff, I have had the joy of being able to contribute to an ecosystem I'm passionate about: bitcoin. In fact, I moved to Austin to be around more bitcoiners. I did meet more bitcoiners. And now I've even started a company with a couple of bitcoin friends.</p>
<p>If you'd like to follow along, <a href="https://mutinywallet.com/">check out Mutiny Wallet</a>. I'm excited and a little scared to build a company and an app designed for consumers. I feel extremely grateful that I get to do this, and grateful to my co-founders Tony and Ben for choosing to build with me.</p>
<p>What does all this have to do with spending a year without using the internet from May 2012 to May 2013? I'm not sure, to be honest with you. It's unclear how much that experience shaped me. A lot? A little? Not at all? It's certainly not guiding my every waking step. I can easily go a week or a month without even thinking about that year once. But my hunch is it had <em>some</em> effect, beyond generating my own personal 15 minutes of fame.</p>
<p>I recently re-watched <a href="https://www.youtube.com/watch?v=trVzyG4zFMU">my TedX talk on YouTube</a>. I look at that guy and think he sounds pretty wise, humbled by his experience, and ready to be a better person. I look at myself now and know I'm trying to to be a better person, but I don't feel as wise as I talked then. Maybe I'm using too much internet to see the forest from the trees right now, who knows.</p>
<p>One thing that really resonated with me from the talk is a sense of focusing on what you believe to be important, rather than having your focus guided by the technology and medium landscape you find yourself in.</p>
<p>I'm not great at this yet, ten years later. But I feel like I'm better at it. I've become more sensitive to when my actions and my priorities misalign. I (sometimes) take steps to correct this. I (sometimes) watch two hours of YouTube in the morning instead of keeping my brain clear for important work. It's a battle and a marathon, no quick fix.</p>
<p>To be honest, my biggest productivity and mood hacks these days have more to do with playing tennis, jumping rope, and cutting back on carbs and alcohol, than any specific wins in my media diet.</p>
<p>I do avoid TikTok, though. That algorithm is just too dang good.</p>
<p>My other big takeaway from my year without the internet is that it was socially isolating, and being back on the internet gave me a fresh opportunity to connect and reconnect with people. My thoughts on this haven't changed at all. My current friend group is a solid blend of people I met via meatspace, and people I met on the internet. And the internet is fundamental to how we coordinate and share memes with each other. My co-founders and I live in the same place and work in person roughly half the time, but the internet is our true collaboration platform.</p>
<p>I'm not quitting the internet again because &quot;the internet is where people are,&quot; and people matter to me now more than ever.</p>
<p>To anyone reading this who remembers my year without the internet, watched a YouTube video, commented on my Verge articles... thank you. It's still crazy and wonderful to me that so many people found my stunt interesting, and reading the comments makes me so glad. Imagine that me being bad at self control, and maybe bad at life generally, but trying to write about it honestly, could be the nudge someone needed to emphasize their own priorities in life. At least that's what they tell me in the comments, mediated by screens and a global communications network... and I choose to believe them.</p>
<p>I apologize if this retrospective isn't quite up to snuff. I miss my editor from The Verge days, Thomas, who would no doubt have a million suggestions on how I could improve the language and point of this 10 year anniversary post. To be perfectly honest, I feel like <a href="https://trustisascalingsolution.com/">I'm becoming a worse writer</a> at the same pace I become a better developer. But I'm okay with that, I know my priority, and I'm excited to build. Thank you for your attention all the same.</p>
]]>
      </description>
    </item>
    <item>
      <title>
        A skateboard for the mind
      </title>
      <link>https://pauljmiller.com/posts/skateboard.html</link>
      <pubDate>Sun, 27 Feb 2022 00:01:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/skateboard.html</guid>
      <description>
        <![CDATA[<p><em>This is a writeup I did of a <a href="https://anchor.fm/futurepaul/episodes/Hmm-are-we-using-computers-correctly-edr27i">solo podcast I recorded two years ago</a>. My attempt was to gather together some of my ideas on how computers could be better. Because I often find myself referencing &quot;that skateboard blog&quot; I did, but actually never posted, I figured I would post it here in my grand tradition of posting well-aged and somewhat discarded content here.</em></p>
<p>The computer is &quot;a bicycle for our minds,&quot; as <a href="https://www.youtube.com/watch?v=rTRzYjoZhIY">Steve Jobs once said</a>.</p>
<p>Do you ever watch those velodrome events in the Olympics? They either have a rolling start, or they have to have someone holding them up for a standing start. The bikers look silly and helpless until they get moving. And then they go in a loop, round and round, very, very fast. If you turn a little too hard your wheels slide out from under you and you eat it. When bikers crash in the velodrome  their paper-thin costumes tear to shreds. The road rash is horrific.</p>
<p>What if we thought of the computer as a &quot;skateboard for the mind?&quot;</p>
<p>Skateboarding is improvisation. Repeated failure. Creative recombination. There's no &quot;right way&quot; to skate. It's also much slower than riding a bike. But much cooler.</p>
<p>I'M MAKING AN ANALOGY HERE.</p>
<p>The tradeoffs we've made in the development of computers since the 60s have favored the &quot;efficiency&quot; and &quot;raw speed&quot; of the velodrome over the ability to turn your own way.</p>
<p>The greatest bicycle I've ever owned is my iPad. It's always fast, always responsive, and incredibly secure. And yet, it can only do what Apple and its blessed legion of third-party developers allow it to do. Trying to code on the iPad is like riding the wrong way in a velodrome. &quot;That's not what it's for!&quot; Coding applications FOR the iPad ON the iPad is impossible. Unless you write some Swift in a text editor that you copy into Xcode later like a jokester.</p>
<p>What would a &quot;skateboard&quot; computer be like? How do we get there?</p>
<h1>The Cuckoo's Egg</h1>
<blockquote>
<p>“The future is already here – it's just not evenly distributed.&quot; - William Gibson</p>
</blockquote>
<p>I brought this up on the last episode, but I'm reading a book called &quot;The Cuckoo's Egg.&quot; It's making me very jealous of how much agency this guy has over his machines. In 1989!</p>
<p>He's tracking a hacker that has been poking around in the network of computers he's responsible for. So he writes tools to help himself track and fight the hacker, while also keeping up with his &quot;day job&quot; of writing software for his fellow astronomers.</p>
<p>Here are some &quot;skateboard&quot; things the Cuckoo's Egg guy does with his computer:</p>
<ol>
<li>
<p>(Physically) intercept the hacker's connection to his system and print out the hacker's every action onto paper.</p>
</li>
<li>
<p>When the hacker connects to his system, his computer dials his pager and sends a message in morse code.</p>
</li>
<li>
<p>A computer simulation of telescope bending (not related to hacking, but pretty cool!)</p>
</li>
<li>
<p>Statistical interpretation of 5,000 phone calls (based on end / start times)</p>
</li>
</ol>
<p>This sort of tool-builder will always be an outlier. It feels like the math stuff is especially difficult to democratize. But it's hard to know HOW outlier and HOW math-wiz this has to be because we've gone so far in the other direction.</p>
<h1>The Unix Philosophy</h1>
<p>Here's a widely cited, rarely followed, way to use computers, known as The Unix Philosophy:</p>
<ul>
<li>Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new &quot;features&quot;.</li>
</ul>
<p>&quot;Do one thing and do it well,&quot; is a beautiful thought, and I believe it's largely right. It's also responsible for some of the worst computer architecture crimes of this century. Microservices and <a href="https://www.theregister.co.uk/2016/03/23/npm_left_pad_chaos/">JavaScript's leftpad debacle</a> are two recent examples.</p>
<p>You have to know when you're winning by making simple composable pieces. Otherwise the coordination cost of composing those pieces overwhelms all the original wins.</p>
<ul>
<li>Expect the output of every program to become the input to another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input.</li>
</ul>
<p>As mad as I am about iOS's allergy to user-built software, the iOS music ecosystem is my favorite example of programs that work well together in this way. You can pipe midi from one program into another program's synth, then send the audio through AUv3 effect, then back to the first program for output.</p>
<ul>
<li>Design and build software, even operating systems, to be tried early, ideally within weeks. Don't hesitate to throw away the clumsy parts and rebuild them.</li>
</ul>
<p>lol nice job on this one unix</p>
<ul>
<li>Use tools in preference to unskilled help to lighten a programming task, even if you have to detour to build the tools and expect to throw some of them out after you've finished using them.</li>
</ul>
<p>This is &quot;yak shaving.&quot; It's easy to have the detour to make tools, and then the cascading detours that detour generates, take days, then weeks, then years, and then you're dead. It's very difficult for a tool-builder to know which and to build another tool.</p>
<p>I guess the solution is to build more tools!</p>
<h1>Smalltalk</h1>
<p>This is a bit of a tangent. But it's another example of how computers could be different and improvisational.</p>
<p>Smalltalk has a concept called &quot;reflection.&quot; Reflection has largely, though not entirely, disappeared from most of our modern systems.</p>
<blockquote>
<p>A reflective program is one that reasons about itself. A fully reflective procedural architecture [Smith 1983] is one in which a process can access and manipulate a full, explicit, causally connected representation of its own state. &quot;Causally connected&quot; means that any changes made to a process's self-representation are immediately reflected in its actual state and behavior.</p>
</blockquote>
<p><a href="http://www.laputan.org/ref89/ref89.html">Reflective Facilities in Smalltalk-80</a></p>
<p>What can you change about your computer while it's running? The color of the menu bars? The desktop picture? Can you touch the logic?</p>
<p>This of course is a very difficult thing to build, not to mention make performant. But it sure is interesting, isn't it?</p>
<h1>Wearables</h1>
<p>I don't want to brag but I've been disappointed by computers for a while now. <a href="https://www.theverge.com/2012/6/26/2986317/google-project-glass-wearable-computers-disappoint-me">Here's a piece I wrote about the history of wearable computers in 2012</a>, and how I was pretty sure Google Glass was the wrong direction.</p>
<blockquote>
<p>One of the first applications of a &quot;wearable computer&quot; was Beating roulette. Nerds have been bringing computers into casinos as early as the 60s, culminating in the 80s with serious wins at roulette. Thomas Bass, who wrote the definitive piece on wearables for Wired in 1998, smuggled a shoe computer to a table, gaining a 44% advantage over the house.</p>
</blockquote>
<blockquote>
<p>Predicting roulette is using a computer for something only a computer could do. It's taking in the same visuals as a human, but then running complicated calculations to predict the deceleration of the wheel, the movement of the ball, and the eventual landing spot. &quot;The problem is similar to landing a spaceship on the Moon,&quot; writes Bass, &quot;except all the calculations have to be done within the few seconds between the launch of the game and the croupier's call to place your bets.&quot;</p>
</blockquote>
<p>The piece also digs into a concept called affective computing (referencing that same Thomas Bass article):</p>
<blockquote>
<p>In Bass's Wired piece, he spends time with Jennifer Healey, another Media Lab graduate student working in the Affective Computing Group. She lived life with electrodes on her face to track when she was smiling and frowning, rings to measure the conductivity of her skin (sweat), and a heart rate monitor. A Palm Pilot tracked the data, and an earpiece could let her know how she was doing.</p>
</blockquote>
<blockquote>
<p>&quot;Your wearable computer could whisper in your ear,&quot; writes Negroponte, &quot;perhaps after playing for a few too many hours with a few too many kids, 'Patience, the birthday party is almost over.'&quot;</p>
</blockquote>
<p>Sounds creepy if Google or Facebook tried to do this for you. These are the sort of capabilities that only make sense if computing is skateboard-like. If you try this in the velodrome you'll crash and burn.</p>
<h1>Dyson sphere</h1>
<p>Along the lines of affective computing, <a href="https://www.theverge.com/2011/08/03/natural-user-interface-red-herring-dyson-sphere">another piece I wrote</a> even longer ago attempted to explain how much our computers are dropping on the floor when they interact with us.</p>
<p>My comparison was to a Dyson sphere. Here's the Wikipedia definition:</p>
<blockquote>
<p>A Dyson sphere is a hypothetical megastructure that completely encompasses a star and captures a large percentage of its power output.</p>
</blockquote>
<p>Here's my wrap-up paragraph:</p>
<blockquote>
<p>Ultimately, it's not that I want to use less of my computers, I just want my computers to use more of me. Luckily, most of the things I've outlined here are obvious and inevitable evolutions of computer interaction. What scares me is that in the meantime we'll get so hung up on &quot;natural user interface&quot; that we'll just use fancy new gestures and voice commands to do the exact same tasks we've been doing with perfect speed and accuracy for years.</p>
</blockquote>
<p>Again, this is creepy to say if you're asking Google and Facebook to scan your body 60 times per second to decide what's best for you. But a skateboard computer, composed of hand-built tools, could be much more interesting.</p>
<p>One example of Dyson sphere-ification is Kinect Star Wars vs. Beatsaber.</p>
<p>In Kinect Star Wars you pose and hope the system recognizes that pose. Your whole human body was being translated into a small handful of button presses.</p>
<p>Meanwhile, Beatsaber is &quot;analog.&quot; You swing the lightsabers with a full six degrees of freedom, and you hit those stupid blocks in 3D space or you don't.</p>
<p>Fun anecdote: I recently super-doxxed myself to Google. I needed a scan of my driver's license and Social Security card. I accidentally switched to Google Lens. Lol.</p>
<p><a href="https://www.theverge.com/2020/5/7/21250556/google-lens-copy-paste-handwritten-notes-computer-phone-ios-android">But this copy and paste thing seems cool</a>. It feels a bit more like a small tool, and not simply an appendage of the Google beast.</p>
<p>Maybe we can have nice things one day. Probably not. But maybe?</p>
<h1>Wrap-up</h1>
<p>There are some really cool people in the computer industry who are challenging the assumptions of inherent complexity. <a href="https://www.youtube.com/watch?v=pW-SOdj4Kkk">Jonathan Blow</a>, <a href="https://www.youtube.com/watch?v=kZRE7HIO3vk">Casey Muratori</a>, <a href="https://www.youtube.com/watch?v=4FbQre9VQLI">Raph Levien</a>. Sometimes they might come across as curmudgeons on Twitter. But I think they're fighting the good fight.</p>
<p>There's also a really good talk about what's gone wrong in computing called <a href="https://www.youtube.com/watch?v=lKXe3HUG2l4">&quot;The Mess We're In&quot;</a> by Joe Armstrong, RIP.</p>
<p>Finally, I recommend the <a href="https://oxide.computer/podcast/">On The Metal podcast</a> for a technical perspective. There's a whole battle raging to make it simpler and more secure to boot a computer. I know not everyone can dip into this particular battle, but it's at least cool to know it's happening.</p>
<p>I love riding my bike. And I'm bad at skateboarding. But I want to get better.</p>
]]>
      </description>
    </item>
    <item>
      <title>
        Premature Innovation
      </title>
      <link>https://pauljmiller.com/posts/premature-innovation.html</link>
      <pubDate>Sat, 20 Nov 2021 00:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/premature-innovation.html</guid>
      <description>
        <![CDATA[<p>The Mechanical Turk was a chess-playing robot unveiled in 1770. A major leap in technology at the time, the robot featured an articulated upper torso controlled by a large box full of cogs and clockwork and was capable of playing a game of chess against a human opponent.</p>
<p>Just one problem: the Mechanical Turk wasn’t a robot or in any way an automaton, it was a puppet controlled by a guy hiding inside its cabinetry. And yet the Turk tricked, or at least baffled, audiences and experts for almost a century.</p>
<p>It would be uncharitable of us to point and laugh at those rubes of centuries prior. They faced a complicated-seeming machine and skilled operators who carried out this magic trick. Perhaps some experts should’ve known better. But perhaps some experts did know better and failed to convince others, or merely enjoyed the joke too much to spoil the secret.</p>
<p>Instead of pointing and laughing, I’d like to see the Mechanical Turk as a caution: what false innovations are currently touring the globe in the 21st century, fooling rubes and experts alike?</p>
<h1>Evenly distributed</h1>
<blockquote>
<p>The future is already here – it's just not evenly distributed.</p>
</blockquote>
<p>This is a quote widely attributed to William Gibson. (Just to help us understand how bad we are at knowing things: nobody can figure out <a href="https://quoteinvestigator.com/2012/01/24/future-has-arrived/">exactly when Gibson said this</a>).</p>
<p>There’s a subtle mistake in this quote that I’ve only recently begun to understand. By mixing the concept of time with the benefits of futuristic technological advancement we begin to think of technological advancement, and a wider distribution of existing technological gains, as inevitable. The passage of time is seemingly constant and unstoppable, and so we transfer this property to technology and we’re surprised when life doesn’t work out this way.</p>
<h1>“Do things that don’t scale”</h1>
<p>A widely cited anecdote in startup circles is how when Airbnb was just getting started, and struggling to gain any traction, its founders went door to door to meet with and learn from early customers. They also would take nice photos on behalf of early listings to improve the perceived quality of the service.</p>
<p>These are Mechanical Turk-style innovations in a sense. They didn’t build personal relationships, in-depth direct CEO feedback, or free photography into some technological service backed by code and CPUs and databases. They just used people. The fact that Airbnb succeeded is largely credited to techniques like this, but nobody pretends that Airbnb succeeded by “scaling” or “distributing” these unscalable techniques.</p>
<p>The ultimate master of doing things that don’t scale is the US government. The Space Shuttle is a vastly unevenly distributed “future” technology: a “reusable space plane.” For instance, the Space Shuttle’s thermal protection system (TPS) was comprised of 31,000 tiles. There’s a lot of literature on the tiles because they sucked so hard, and a failure of the TPS led to the destruction of the Space Shuttle Columbia. But just one interesting unscalable aspect is <a href="https://en.wikipedia.org/wiki/Space_Shuttle_thermal_protection_system#Early_TPS_problems">how hard they were to install</a>:</p>
<blockquote>
<p>Each tile used cement that required 16 hours to cure. After the tile was affixed to the cement, a jack held it in place for another 16 hours. In March 1979 it took each worker 40 hours to install one tile; by using young, efficient college students during the summer the pace sped up to 1.8 tiles per worker per week. Thousands of tiles failed stress tests and had to be replaced. By fall NASA realized that the speed of tiling would determine the launch date. The tiles were so problematic that officials would have switched to any other thermal protection method, but none other existed.</p>
</blockquote>
<p>No company, not even Airbnb, would build something as wasteful and impractical as the Space Shuttle, because there’s no theoretical profit that could justify a reusable low Earth orbiter this dangerous, complicated, and inefficient.</p>
<p>And yet during the whole Shuttle era — which overlapped my entire childhood — I sat in awe among the Mechanical Turk’s audience. A reusable spaceplane. How futuristic! We’ve come so far as a species!</p>
<h1>Opportunity cost</h1>
<p>I first started noticing how many innovations surround us that don’t seem to “scale” after listening to a <a href="https://scotthorton.org/interviews/7-3-20-tom-woods-on-how-the-pentagon-makes-us-poorer/">Scott Horton podcast about the destructiveness of military spending</a>.</p>
<p>The accepted narrative I’ve always heard is how so many technological advancements can be traced back to military spending, and how “unfortunate” it is that it takes major conflicts like World War II to spur the sort of unbridled government spending required for major breakthroughs.</p>
<p>The internet, nukes, GPS, and digital cameras are all examples of military-funded inventions from the last century.</p>
<p>So, what’s the counter-narrative? Well, as Tom Woods and Scott Horton point out, we don’t know the true opportunity cost of all that spending. Military inventions are the &quot;seen,&quot; but what is the &quot;unseen&quot; in this case? We can’t re-run this experiment to see which of these (or other) innovations would’ve popped up in the free market.</p>
<p>The government, which has no budgetary constraints, bids up the cost of engineers and can easily afford to corner the market on top talent. Instead of solving problems perceived by civilians via product development, some of the best minds of the last century were milking fat government contracts to solve the challenge of killing people overseas, or in the best case winning a propaganda war with Russia by sending people into space.</p>
<p>Many good ideas developed in these efforts have spread widely to civilians — sometimes, like in the case of encryption, much to the chagrin of the government paymasters. Other ideas didn’t help civilians, or didn’t scale, or didn’t work at all… we don’t hear about those as often. But the failure of those ideas didn’t stop paychecks of the engineers nearly as quickly as in the free market where a company has shareholders to placate. The more wasteful the government’s innovation methodology is, the more in effect it bids up the pay for a competent engineer who could theoretically be building profitable innovations in this counter-factual.</p>
<h1>There’s no “we” in innovation</h1>
<p>Another piece of media that I can’t stop thinking about in this context is <a href="https://youtu.be/pW-SOdj4Kkk">Jonathan Blow’s “Preventing the Collapse of Civilization”</a>.</p>
<p>Jonathan Blow is famous for his rants and curmudgeonliness on the topic of modern software quality, and there’s plenty of that to be enjoyed here. But what struck me in this talk is how challenging it is to pass innovations forward in time, and to spread advanced technique to a wide number of people. (&quot;Technology&quot; is just &quot;technique&quot; turtles all the way down)</p>
<p>One of his anecdotes is from Bob Calwell, an Intel engineer, who found problems in a whole range of vendor chips that hadn’t been there previously. The vendor’s excuse:</p>
<blockquote>
<p>The first generation of transistor logic was done by the old gray beard guys that really know what they’re doing.
The new generation was done by kids who are straight out of school who didn’t know to ask what the change in packaging would do to inductive spikes.</p>
</blockquote>
<p>Does the term &quot;inductive spikes&quot; go over your head? Is it too technical to grasp the actual problem? Yeah, for me too. That’s why there’s no “we” in innovation. Some people know how to do some stuff. And most of the stuff <em>they</em> do relies on _other people knowing how to do <em>other</em> stuff. And any break in the chain has the potential of setting back our civilization’s technological level — potentially for centuries or millennia, like in the case of Roman concrete. Everything that's been invented, and then lost, must be reinvented to be useful again.</p>
<p>It always bugs me when a Peter Thiel or Elon Musk type holds up a phone and complains in the vein of: “We know how to build this, but we don't know how to go to the moon anymore.”</p>
<p>Not that they’re completely wrong, but the “we” is misleading. “We” don’t know shit about how to make phones. Some people, including, I’m sure, Thiel and Musk, know more than others, but not enough by a long shot.</p>
<p>I know how to go to the store and buy a phone. Several people at Apple know how to contract certain manufacturers to build one. Those manufacturers hold oodles of received and developed knowledge on how to do what they do. It’s for similar reasons that we don’t go to the moon anymore: “we” never knew how. Some people knew how, and that knowledge began to fade rapidly as soon as Apollo 17 splashed down.</p>
<p>(Ironically, when looking around for a more precise quote on this topic from these guys I'm straw-manning I found this piece about Peter Thiel's thoughts on innovation. Except the site hosting it is down now, so <a href="https://web.archive.org/web/20210323015959/https://pando.com/2014/05/16/peter-thiel-the-us-as-we-know-it-depends-on-us-rediscovering-our-innovation/">I had to use archive.org</a> to view it)</p>
<h1>Abstraction is dependence</h1>
<p>The more complicated a piece of knowledge is, the harder it is to propagate forward in time or broadly to many people. And since our brains are finite, even if we do learn many details of an advanced technology, we never have quite enough room for all details of all abstractions. And so we specialize and rely on others.</p>
<p>In technology, this can lead to what I see as a variant of the “good times create weak men, weak men create bad times, bad times create strong men, strong men create good times” meme.</p>
<ul>
<li>Strong programmers create frameworks (abstractions)</li>
<li>Frameworks create weak programmers (never bothered to learn how the abstraction works, become alienated from the underlying machine)</li>
<li>Weak programmers create bad software (this is why Jonathan Blow is so mad right now)</li>
<li>Bad software creates strong programmers (I don’t know if this is true but it sounds nice. I guess at some point programmers become so sick of the state of things that they dig deep and start to rebuild the foundations with new operating systems and programming languages and… uh oh! new frameworks)</li>
</ul>
<p>If we are in the upswing of the cycle we should see strong programmers, forged in fire, creating new frameworks. And I see some glimmers of that right now.</p>
<p>Rust (from Mozilla), Jai (from Jonathan Blow), and Zig (from Andrew Kelley) are all examples of new programming languages forged by strong programmers who were tired of suffering in our current mess. All three languages have a strong relationship or reference to the C programming language while rejecting the modern orthodoxy of C++.</p>
<p>But why is there so much C++ code in the world to react against in the first place? This is the bloated, inefficient code that's to blame for Chrome taking a couple of seconds to close a tab. Or Photoshop taking the same amount of time to launch in 2021 as it took to launch in 2001, despite computer speed increasing exponentially. Mozilla built Rust because some problems in Firefox's C++ codebase were becoming intractable. Jonathan Blow built Jai because he figured if he spent a few years building a programming language for game development he'd still net save time over building games with C++ for the rest of his career.</p>
<p>The proliferation of bad programmers, and bloated, inefficient programs, is &quot;sustainable&quot; because we have a government with no real bottom line, money-printing-backed startups doing things that won't scale, and government-protected monopolies with unassailable market positions.</p>
<h1>Monopoly profits breed fragility</h1>
<p>Aha, I've written myself into a corner where <a href="https://cdn.mises.org/Against%20Intellectual%20Property_2.pdf">I get to rant about patents</a>.</p>
<p>Patents are a huge honeypot for paying bad programmers to make bad programs. It doesn't matter how efficiently you build your software, or how maintainable it is into the future. Build the product quickly, get it out the door even if it's a buggy mess, and patent &quot;the hell out of it&quot; as Steve Jobs said about the iPhone (and proved by suing the hell out of Samsung).</p>
<p>Patents incentivize being &quot;the first to invent.&quot; It's a high time preference activity. You don't have to publish your code in the patent, just a diagram of your idea and a few implementation details. And now, if the patent office falls for your scheme, men with guns will defend your exclusive right to build that product for the next couple of decades. You can clean up the code &quot;later&quot; (you won't), while you're busying harvesting monopoly profits.</p>
<p>The monopoly profits are highly self-perpetuating as well. Once a company has an edge (Google with its search algorithm patent, Amazon with its 1-Click patent, Apple with its swipe to unlock) you can afford to hire more engineers, and, more importantly, more patent attorneys, to build more bullshit and patent that as well. Even if the patent wouldn't hold up in court, it has a chilling effect of discouraging other companies and inventors even trying to build something similar because they'll likely end up in court for a few years if they do. Funding a rival to a well-established tech giant is such a huge risk that it's rarely attempted.</p>
<p>And so knowledge is consolidated inside huge tech companies, and yet inside these companies, this knowledge is spread thinly over thousands of engineers all pumping out gobs of unmaintainable code. Externally we experience the sensation of &quot;innovation&quot; and &quot;the future&quot; because these companies keep delivering astonishing products and incremental improvements on their flagship devices.</p>
<p>But how many billion dollars would you need to re-create the iPhone?</p>
<p>Think of how thick the vertical tech stack of an iPhone is, and how little of that knowledge is widely known or understood outside of Apple. Or is even knowledge legal to apply.</p>
<p>Apple's chip designs are a couple years ahead of the competition. Apple's operating is largely closed source. It's nearly impossible to run an open source operating system like Linux on Apple hardware, even when Apple doesn't explicitly lock it down. Even if you source the same camera module the iPhone uses, the software to process those images represents hundreds of man-years.</p>
<p>And, of course, there are the &quot;innumerable antecedents,&quot; as <a href="https://fee.org/resources/i-pencil/">they're called in <em>I, Pencil</em></a>, that go into the iPhone. These are technologies that Apple doesn't build, but contracts with others to build. Many of which are only affordable with Apple-level margins. And there are plenty of patents along this chain of suppliers — not only of the parts themselves but also of the processes to build the parts.</p>
<p>In the end, the price tag of building an iPhone de novo might not be in the billions, but in the trillions. In fact, &quot;just&quot; to build a modern chip fab, and the dependencies of a chip fab, and the recursive dependencies of the dependencies, might already put you over the trillion dollar mark.</p>
<p>I believe strongly we wouldn't currently sit at such technological heights — we would not be so deep into the future — if it weren't for Apple's monopoly profits via patents. But who is the &quot;we&quot; in this case? Any choice that Apple makes to exclude a user or use case from an ecosystem, in turn, excludes that user from this &quot;future&quot; entirely.</p>
<p>The future is here, but it's not evenly distributed.</p>
<p>And, importantly, <em>it may never be</em>. How much of what Apple builds is just Space Shuttle tiles? Only made possible by a government-enforced monopoly. How much innovation do we currently enjoy that is built on such coercive grounds?</p>
<p>The future is here, but it's owned and permissioned.</p>
<h1>Bitcoin in El Salvador</h1>
<p>My original inspiration for writing all this is my unsettled feeling about El Salvador's government-forced adoption of Bitcoin.</p>
<p>I was in the crowd in Miami when Jack Mallers got on stage and announced that Bitcoin would be legal tender in El Salvador. I rose to my feet and applauded. I even felt a little choked up about it. I've become extremely dedicated to the cause of Bitcoin in recent years precisely because of Bitcoin's liberating effect. How could I not cheer to see an impoverished country free itself from the constraints of the US dollar and usher in the Bitcoin era?</p>
<p>Unfortunately, the details of the law were a mixed bag. Legal tender? Yes! Forced legal tender? Hmm, that doesn't sound right. A government-built wallet? Government-sponsored ATMs? A $30 airdrop to every citizen? Government offering exchange services? Sounds like you need a whole lot of government to implement freedom money!</p>
<p>And as a developer, I also felt a little bit of responsibility and embarrassment. In casual conversations before June, I think the consensus on whether the Lightning network was ready for mass adoption was a resounding &quot;no.&quot; In fact, at the Bitcoin conference in Miami, all the retailers were set up to receive Lightning payments, but the phone service was slammed and I didn't get a single payment through. It sure didn't feel ready to me! Isn't it a little cruel of us to beta test it on an unwitting populace?</p>
<p>Of course, another part of me hates to look a gift horse in the mouth. Isn't this at least better than no Bitcoin law?</p>
<p>Just to make my doubts look even more unfounded, reports I've seen of the actual rollout in El Salvador have been almost universally positive. The government wallet is rough but functional, the same can be said for the ATMs. People got their $30 airdrop. Pizza Hut and Starbucks accept Bitcoin. Crisis averted, yeah?</p>
<p>But I still think El Salvador fucked up.</p>
<p>Because we can't ever know the counterfactual of a government program. The government can pay any amount of money to force an innovation through. Just like the government can enforce a monopoly claim of any dubious quality. The choice is made, the price is of a little concern, and the &quot;unseen&quot; is exactly that: unseen. We won't know if this whole experiment was Space Shuttle tiles until it's too late.</p>
<p>Are we witnessing an autonomous chess-playing robot? Or is there a dude in the box making fools of us all? Is El Salvador &quot;doing things that don't scale,&quot; and what happens when the initial investment runs out?</p>
<h1>Actually, on the subject of gift horses</h1>
<p>I'll admit, at this point in my premature innovation journey I'm suspicious of anything nice.</p>
<p>Nice website? Probably a shitcoin, or at least heavily VC-backed... so it will probably turn into a shitcoin eventually.</p>
<p>Cool application of machine learning? No way you make enough money on playing Go and chess to justify the compute power and man-hours you're dedicating to this. Oh right, you're funded by Google.</p>
<p>Excellent Bitcoin wallet that &quot;just works&quot; and the user &quot;doesn't even need to think about&quot; channel management? There's probably a big gotcha in there as well.</p>
<p>By the way, I use one of those wallets and I love it. And I'm writing this in the Notes app on a new MacBook Pro. So perhaps I should take the log out of my own eye.</p>
<p>And that's where it gets very hard to apply these fears I have about the precarious position of modern innovation. Because modern innovation is so dang <em>wonderful</em>. I even did <a href="https://anchor.fm/futurepaul/episodes/Our-excellent-dystopia-with-Matt-Odell-enbrfe">a whole podcast episode about this with Matt Odell</a>.</p>
<p>I'm worried that the delta between good, broadly distributable, &quot;sustainable&quot; innovation might be as far as the difference between the <a href="https://www.crowdsupply.com/sutajio-kosagi/precursor">open source Precursor device</a> and an iPhone. Or maybe, if we're being charitable, the difference between the <a href="https://www.pine64.org/pinephone/">PinePhone</a> and a Google Pixel.</p>
<p>Open source mobile hardware isn't even in the black and white TV era yet (the Precursor has yet to ship). And open source, DIY computer processor fabrication a few is <a href="https://www.youtube.com/c/BenEater">Ben Eater videos</a> away from not existing at all.</p>
<p>Most open source software is hosted on GitHub.</p>
<p>Basically, everything that's great and accessible and freedom preserving and humanity empowering and widely distributable in technology is also highly dependent on something that is none of those things.</p>
<h1>What to do on the subject of premature innovation</h1>
<p>I don't want the perfect to be the enemy of good. And I can only control what is within my power. So, with those maxims in mind, my strategy is pretty simple:</p>
<p>How much un-fragile innovation can I build and embrace?</p>
<p>(And maybe with the caveat that I'd like to avoid regressing my personal technology level a full century)</p>
<p>I'd like to use the illustration of modern, unsustainable technology being like the outlines of a picture, and we have to color in the picture with truly democratic technologies to build it out for real. But who even knows if the picture Apple and DARPA drew for us is the right shape?</p>
<p>But here I am straying from practical application once again.</p>
<p>It starts by refusing to be impressed by a dude in a box pretending to be a robot. Step two might involve me not using Apple's Notes app. And who knows where it ends?</p>
]]>
      </description>
    </item>
    <item>
      <title>
        Christianity for Bitcoiners
      </title>
      <link>https://pauljmiller.com/posts/christianity-for-bitcoiners.html</link>
      <pubDate>Mon,  5 Apr 2021 00:01:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/christianity-for-bitcoiners.html</guid>
      <description>
        <![CDATA[<p><em>This began as a subtweet of the <a href="https://anchor.fm/john-vallis/episodes/Bitcoiner-Book-Club-Explores-Jordan-Petersons-Maps-of-Meaning-er4ggi">Bitcoin Book Club discussion on &quot;Maps of Meaning,&quot;</a> if you're curious who are these generic Bitcoiners I'm arguing against in my head.</em></p>
<p>I've recently enjoyed the book <a href="https://programmingbitcoin.com/thank-god-for-bitcoin/"><em>Thank God for Bitcoin</em></a>. It's a book that makes the moral case for Bitcoin and serves as an easy introduction for Christians of the importance of money and the qualities of Bitcoin.</p>
<p>But what should a Bitcoiner think about Christianity?</p>
<p>Many non-Christians in this circle have kind things to say about religion in general and Christianity in general, largely thanks to the work of Jordan Peterson and Nassim Taleb's &quot;Lindy&quot; concept. The way I frequently hear it told, Christianity is a powerful, world-shaping myth. The Abrahamic God is worshipped by a good percentage of the world, and the Christian, Jewish, and Muslim faiths can be traced back thousands of years. There is likely much we can learn from these faiths about the structure of existence, and some morals we can cherry pick as appropriate, and perhaps even some religious observances we can pepper into our own life as a form of meditation.</p>
<p>In other words, we can be shitcoiners when it comes to religion.</p>
<p>&quot;Bitcoin is great, it got everything started. It's digital gold. But I'm interested in blockchain technology and what else can be accomplished beyond money.&quot;</p>
<p>The shitcoiner believes he has discovered a fundamental truth in Bitcoin, but that Bitcoiners have been too narrow minded to take the idea to its full, Turing-complete conclusion. Bitcoiners are fundamentalists clinging to outdated notions like proof-of-work and radical decentralization. Bitcoiners faint like scandalized church ladies when you talk about pre-mines. Bitcoiners are superstitious rubes who can't appreciate technology.</p>
<p>But Bitcoiners know that Bitcoin is more than an interesting idea that kicked off an industry. It's a one and done. It's the single opportunity at digital scarcity that we know of, because everything after Bitcoin is money printing. Bitcoin isn't just a single software instantiation of an idea, it is the idea itself. 21 million, halvings, proof-of-work, and difficulty adjustments aren't just features of a single coin they’re the whole innovation. Everything else is just LARPing.</p>
<p>The Bible teaches quite clearly that there's only one God, and who in particular that God is, so why do we behave as if God is merely conceptual, or pretend as if any substitute could be sufficient?</p>
<p>Adam and Eve's original sin was not trusting God. They wanted more and they got it: the &quot;knowledge of good and evil.&quot; The price was simply a cursed, painful, and mortal existence for themselves and their children.</p>
<p>The story of the people of Israel throughout the Old Testament is scenario after scenario where people who trust God are sustained, blessed, and delivered by God, while those who don't trust God soon suffer the consequences.</p>
<p>And this isn't always a &quot;blind&quot; faith like many Christians have operated from in modern times.</p>
<p>When God brought the people of Israel out of Egypt, he did it with a large quantity of unsubtle miracles. Plagues, the parting of the Red Sea, and then a pillar of cloud to guide them during the day and a pillar of fire at night. God wasn't in any way a theoretical entity to them.</p>
<p>You might be skeptical any of those things ever happened. Perhaps this is just a fairy tale. But from the point of view of the characters in this story, all these things had just happened last week.</p>
<p>And what did they do the moment Moses took his eyes off them for five seconds to go up the mountain and receive the 10 commandments? They created an idol of a cow out of gold and started worshipping it. Instant shitcoiners.</p>
<p>The Israelites frequently expressed to Moses that they would prefer slavery in Egypt to this newfound liberty.</p>
<p>Sound like anyone you know?</p>
<p>The Christian recognizes that, by nature, we’re all like Israel. We’re all shitcoiners. Despite a knowledge of God, perhaps even practical miraculous experiences, or at the very least an understanding of the miracle of existence, we reject God for something vastly, comically worse than God.</p>
<p>We pick money. Or power. Or fame. Or family. Or a football team. And we bow down and worship it. And it constantly disappoints us. And yet we avoid worshipping the only thing in existence -- the God who created existence -- worth worshipping.</p>
<p>God, being God, is not surprised by our stupidity -- the Bible calls this &quot;hardness of heart.&quot;</p>
<p>Here are the first two commandments that God was giving Moses while the people of Israel were debasing themselves in front of a gold cow:</p>
<ol>
<li>You must not have any other god but me.</li>
<li>You must not make for yourself an idol of any kind of an image of anything in the heavens or on the earth or in the sea. You must not bow down to them or worship them, for I, the Lord your God, am a jealous God who will not tolerate your affection for any other gods.</li>
</ol>
<p>Pretty explicit, yeah?</p>
<p>Here's how Paul (my namesake) explains it in the book of Romans:</p>
<blockquote>
<p>But God shows his anger from heaven against all sinful, wicked people who suppress the truth by their wickedness. They know the truth about God because he has made it obvious to them. For ever since the world was created, people have seen the earth and sky. Through everything God made, they can clearly see his invisible qualities -- his eternal power and divine nature. So they have no excuse for not knowing God.</p>
</blockquote>
<p>Ultimately, our proclivity to shitcoin is so strong, we are completely hopeless. We can't help ourselves. We are born shitcoiners, tainted by Adam's original sin that has been passed on to us -- the knowledge of good and evil turned out to be hereditary.</p>
<p>This is why the &quot;immaculate conception&quot; is so important to Christians. Because Jesus didn't have an earthly father, he wasn't a born shitcoiner. He didn't have rebellion against God built into his soul. And so he was able to live a perfect life, and act as a perfect sacrificial substitution on our behalf, ultimately repairing the damage that Adam did in the first place.</p>
<p>This is the simple gospel (&quot;good news&quot;) that a Christian believes: Jesus is the Son of God, lived a perfect life, died on our behalf so we could be reconciled to God, and rose again from the dead to prove beyond a shadow of a doubt he is who he said he is.</p>
<p>To view this as a mere archetype, as the best example of a hero's journey, as an impressive myth worth imitating, is to completely miss the point. To not take the gospel literally isn't some subtle, modern way of viewing the Christian message, it's the oldest human flaw in the book. There is only one literal actual God, and there is only one literal son of God, and only one literal way of salvation. Everything else is a lie with a very bad outcome.</p>
<p>Here's how Jesus himself explained it:</p>
<blockquote>
<p>You can enter God's Kingdom only through the narrow gate. The highway to hell is broad, and its gate is wide for the may who choose that way. But the gateway to life is very narrow and the road is difficult, and only a few ever find it.</p>
</blockquote>
<p>Unless this sounds discouragingly difficult, here's another prayer of Jesus:</p>
<blockquote>
<p>O Father, Lord of heaven and earth, thank you for hiding these things from those who think themselves wise and clever, and for revealing them to the childlike. Yes, Father, it pleased you to do it this way!</p>
</blockquote>
<p>And later in that same passage:</p>
<blockquote>
<p>For my yoke is easy to bear, and the burden I give you is light.</p>
</blockquote>
<p>In a sense it's ridiculously easy to be a follower of Christ. You simply trust him to save you and he does. You’re merely choosing to dedicate your worship and affection, that you were by nature going to dedicate to <em>something</em>, to specifically Jesus.</p>
<p>But in another sense, it's very hard to do this. It's a narrow way, and we are constantly tempted to worship something, sometimes it feels like <em>anything</em> else, not out of some self-interest, but out of some built-in hatred for God that we inherited from grandpa Adam.</p>
<p>Bitcoiners are familiar with this dichotomy.</p>
<p>It's ridiculously simple and easy to do Bitcoin: buy and hold. Trading is a distraction, shitcoins are worse, and fiat currency is the dumpster fire that inspired Satoshi and the cypherpunks in the first place -- a violence-based system where the elite profit and the rest of us suffer.</p>
<blockquote>
<p>Stay humble and stack sats</p>
</blockquote>
<p>But the way is narrow, and so many have fallen off the path. Greed, impatience, a fundamental misunderstanding of the nature of Bitcoin, and a fatal lack of humility have all turned honest Bitcoiners into shitcoiners over the years. Many of us started out as shitcoiners, fell into a few traps early on, and are grateful to be on the other side now. Poorer than if we'd never shitcoined at all, but perhaps wiser for the experience.</p>
<p>Christians have a phrase along those lines: &quot;There, but for the grace of God, go I.&quot;</p>
]]>
      </description>
    </item>
    <item>
      <title>
        Speech
      </title>
      <link>https://pauljmiller.com/posts/speech.html</link>
      <pubDate>Mon, 11 Jan 2021 00:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/speech.html</guid>
      <description>
        <![CDATA[<p><em>This the newsletter I wrote to accompany <a href="https://anchor.fm/futurepaul/episodes/Facts-eepcbr">a May 2020 episode of my podcast</a>. I love to complain about censorship on Twitter because it's a way of shaming the assholes who cheer for it and want to pretend they're being moral. But in my heart, I think Twitter shutting down speech is probably the best thing that can happen for speech, because it forces us to build new and better platforms that can't be shut down so easily.</em></p>
<blockquote>
<p>&quot;You can't stop other people from reading that which you disagree with.&quot;</p>
</blockquote>
<p>@pierre_rochard on <a href="https://noded.org/podcast/noded-0620-with-will-cole/">Noded 0.62.0</a></p>
<p>Speech laws and regulation and platform moderation are always about what &quot;others&quot; should see. Because you have to see it to moderate it. Just something to think about.</p>
<h1>The first amendment</h1>
<p>The way I'm thinking about &quot;free speech,&quot; as a principle, is that I'm not going to use my power proactively to silence your speech. The actual law, of course, is about prohibiting the government from using its power to silence speech. But we're adults, we can talk about right and wrong it's okay.</p>
<p>Censorship is not an educational tool, it's a tool of control. You don't know what's being censored because you never see it. That was the whole point. So how do you know whether the right things are being censored? The potential for misapplication and the lack of means of correction are sky-high.</p>
<p>But platforms like Facebook and Twitter are in a dumb no-man's land where their &quot;speech&quot; is primarily the promulgation of other people's speech.</p>
<p>I personally would not want to be forced promulgate information I find abhorrent. But I also don't want to stop other people from accessing information I disagree with. Censorship doesn't restrain conspiracy theories, it validates them. The cure for wrongthink isn't a ban, it's better information. I also believe people who have facts on their side aren't afraid of people hearing &quot;different facts.&quot;</p>
<p>And as great as I sound to myself when I say these things, none of it is useful as a prescription for how Twitter or Facebook should act.</p>
<p>Maybe there's like a range of speech-adjacent activities we can define:</p>
<ol>
<li>Censorship: actively using power to limit what someone can say or hear.</li>
<li>Non-promulgation: &quot;silencing&quot; others through inactivity.</li>
<li>Promulgation: republishing others.</li>
<li>Self-publication: creating your own platform to host your own speech or the speech of others.</li>
</ol>
<p>Promulgation is really some of the most powerful speech there is. And, of course, there's no promulgation without non-promulgation. Otherwise you're just transmitting static.</p>
<p>Twitter, Facebook, and YouTube are self publishers with a truly historic level of promulgation, and now they're trending toward non-promulgation, which seems only reasonable. Meanwhile government is flirting with censorship, because it really has no power other than to destroy and oppose. Meanwhile <em>meanwhile</em> I'm thinking I need to get myself some of that self-publishing apparatus to secure and promote the ideas I think are good.</p>
<p>As a sidenote, I do find it sad sometimes how narrow a view we often have of what is acceptable and useful discourse, but there's really nothing I can do to change that. If it's easy to stay within the appropriate bubble of thought, then times seem good. But it leaves you with no recourse if you start getting extra-bubble ideas. And it might be actively harming the formation of extra-bubble ideas (which was the whole point of non-promulgation, obviously).</p>
<p>So what can I do?</p>
<h1>The solution</h1>
<p>I think I'm becoming a censorship accelerationist.</p>
<p>Personally, I see no good solution to &quot;Twitter should moderate more&quot; vs. &quot;Twitter should moderate less,&quot; other than &quot;Twitter's decisions have no impact on what I can say and who I can listen to.&quot; Like with Bitcoin and money, I'm not looking for reform, I'm looking for the exit.</p>
<p>I have no desire to force platforms to publish content that they believe is against their own interests, or against their moral code or public duty. And as an anarchist, the idea of a &quot;public square&quot; sounds pretty dumb to me. Union Square isn't where I go to to hear great information. I go there to watch the skateboarders.</p>
<p>A few points on this:</p>
<ul>
<li>Echo chambers are natural and healthy.</li>
</ul>
<p>Editing, curating, and gatekeeping are important methods of dealing with information. I have inputs and outputs. By constraining my inputs to what I believe to be trustworthy and relevant, and even further constraining my outputs along those lines, I'm in a sense creating value for anyone who listens to me.</p>
<p>Echo chambers are actually wonderful for engaging with opposing ideas because when you trust that someone is on your &quot;side,&quot; it's much safer to listen to their critique. When it comes from outside your tribe it just feels like an attack and must be defended against.</p>
<p>If Twitter Facebook YouTube to create echo-chambers for their own crowd, I say let them.</p>
<ul>
<li>I don't want to host porn on my blog comments.</li>
</ul>
<p>Sorry not sorry. Along these lines, I still can't figure out how to feel about Tor.</p>
<ul>
<li>The Disney film, &quot;Newsies,&quot; starring Christian Bale.</li>
</ul>
<p>Where do you talk about whether or not it's okay to talk about something? With people you trust. Like with Christian Bale, for instance. We need more, not fewer, conspiracies.</p>
<p>How do you get a message opposing the &quot;New York World&quot; out in the world? Not by publishing a story in &quot;New York World,&quot; but by giving the story to the opposition or starting your own.</p>
<p>I don't rage at HBO that my podcast isn't on their &quot;platform.&quot; Twitter is like a newspaper &quot;anyone can publish to.&quot; YouTube is like an HBO &quot;anyone can publish to.&quot; They're kind of non-sensical and untenable.</p>
<h1>I think the key may be</h1>
<p>Stop thinking of speech on YouTube or Twitter or Facebook as other people's speech. Start seeing Twitter handles the same way you'd see a byline in a newspaper or magazine. A newspaper might run an opposing editorial, but it's still only publishing information it wants you to hear. This is seriously not a knock on on these platforms, but of the impossibility of being a promulgator. Impartiality can't be achieved, so why not lean into it?</p>
<p>I'm not for or against section 230. Whatever the government is going to do or not do, I'm sure it's going to suck. So how do I make sure it sucks the least for myself and the people I care about?</p>
<p>One we realize what platforms actually are, we become more desperate to own our own printing presses. Once we have our own printing presses, we can decide whether or not to promulgate. There's no reason technically that what we now call &quot;Twitter&quot; couldn't be composed of millions of independent publishers talking to each other over a protocol. We just haven't felt the need.</p>
<p>I think the bubble's going to pop. I think we're going to feel it. So now is the time to prepare.</p>
<h1>A practical solution, though?</h1>
<p>I don't know. Mastodon? Email? I should update my blog.</p>
]]>
      </description>
    </item>
    <item>
      <title>
        Building a widget for Druid
      </title>
      <link>https://pauljmiller.com/posts/druid-widget-tutorial.html</link>
      <pubDate>Wed, 23 Oct 2019 00:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/druid-widget-tutorial.html</guid>
      <description>
        <![CDATA[<p>Want to build a desktop app? You probably want to use Electron or Qt or GTK or a native toolkit.</p>
<p>Want to build a thing that you could (maybe) <em>someday</em> use to build a native desktop app? <a href="https://github.com/xi-editor/druid">Contribute to Druid</a>!</p>
<p>Druid is a work-in-progress, open source &quot;data-oriented Rust UI design toolkit.&quot; You can use it right now to build <em>very</em> feature-incomplete desktop applications for macOS, Windows, and Linux.</p>
<p>For most of 2019 I've been contributing to Druid in the form of widgets. Exciting UI elements like: a button with rounded corners! A progress bar with rounded corners! A checkbox with rounded corners! A textbox with rounded corners!</p>
<p>It's not much, but it's honest work.</p>
<p>One thing I'm really enjoying about Druid is that at the widget level I control every pixel. Druid is a UI framework, sort of like React is for the web, but it uses a 2D graphics library called Piet to actually put pixels on the screen. Drawing my own widgets from scratch, instead of just styling someone else's widgets, was a big conceptual leap at first for me, but it quickly turned into an extremely satisfying activity.</p>
<p>So, I'd like to walk you through the widget creation process. Perhaps you too will adopt this widget-creation hobby and help me fill out Druid's palette of default elements! I think we'd all like to live in a world where an open source project like Druid can build feature-<em>complete</em> desktop applications, but first <em>somebody</em> has to build that world.</p>
<h2>1. What is a widget?</h2>
<p>In Druid, &quot;Widget&quot; is a trait. So to make a new kind of widget, you just make a new type and then implement <code>Widget</code> on it.</p>
<p>Let’s use a color picker widget as an example:</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">struct </span><span style="color:#323232;">ColorPicker;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">impl </span><span style="color:#323232;">Widget </span><span style="font-weight:bold;color:#a71d5d;">for </span><span style="color:#323232;">ColorPicker {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">paint</span><span style="color:#323232;">(...) {</span><span style="font-weight:bold;color:#a71d5d;">...</span><span style="color:#323232;">}
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">layout</span><span style="color:#323232;">(...) {</span><span style="font-weight:bold;color:#a71d5d;">...</span><span style="color:#323232;">}
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">event</span><span style="color:#323232;">(...) {</span><span style="font-weight:bold;color:#a71d5d;">...</span><span style="color:#323232;">}
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">update</span><span style="color:#323232;">(...) {</span><span style="font-weight:bold;color:#a71d5d;">...</span><span style="color:#323232;">}
</span><span style="color:#323232;">}
</span></pre>
<p>And we're done!</p>
<p>To use our <code>ColorPicker</code> widget, we include the widget as part of a widget hierarchy. Then it's Druid's job to send events to widgets as appropriate and to update widgets as appropriate with new data when the app's state changes.</p>
<p>The widget's methods are generally are called in this order (it’s possible for a widget to receive <code>update</code> without ever receiving <code>event</code>):</p>
<pre style="white-space: pre-wrap;">event -&gt; update -&gt; layout -&gt; paint
</pre>
<p>So an <code>event</code>, like a mouse clicking on our widget, could potentially cause a data <code>update</code>, and then we'll position and size the widget correctly with the <code>layout</code> method, and finally <code>paint</code> the widget to the screen.</p>
<h2>2. Getting started</h2>
<p>A great way to get started working on widgets in Druid is to clone the whole <a href="https://github.com/xi-editor/druid">repo</a> and then make a copy of <code>custom_widget.rs</code> in the examples directory. We'll call it <code>color_picker.rs</code>.</p>
<p>So, in our case:</p>
<pre style="white-space: pre-wrap;">cargo run --example color_picker
</pre>
<p>(If you're on macOS you'll need to <code>brew install cairo</code> first.)</p>
<p>You should end up opening a window that looks something like this:
<img src="../static/images/dw_1.png" alt="custom widget example" /></p>
<p>This example has some minimal in-line documentation, so feel free to experiment.</p>
<p>If it helps your mental model, here's what's happening when we launch this app:</p>
<p>The <code>AppLauncher</code> is given a <code>WindowDesc</code> which holds a root widget called CustomWidget. At launch the app's initial state is the String <code>Druid + Piet</code>, which is passed to the widget tree. When we resize the window, the size constraint passed to CustomWidget is updated, and so the widget is redrawn to match its new size.</p>
<h2>3. Painting with Piet</h2>
<p>Before we think too hard about our data model (famous last words), let's get our own pixels on the screen.</p>
<p>I think we should do a HSL color picker. This widget we're building can display and control the SL (Saturation and Lightness), and then we can add a slider to the app to control H (Hue).</p>
<p>HSL can be represented as three floats in the range (0.0, 1.0). But Piet's <code>Color</code> type is RGBA under the hood, so we need to do some converting before we draw the color on the screen.</p>
<p>Here's a handy HSL to RGB converter I just had laying around. Feel free to copy and paste because this isn't really the focus of this tutorial!</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">hue_to_rgb</span><span style="color:#323232;">(p: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">, q: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">, t: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">) -&gt; </span><span style="font-weight:bold;color:#a71d5d;">f64 </span><span style="color:#323232;">{
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">let mut</span><span style="color:#323232;"> t </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> t;
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">if</span><span style="color:#323232;"> t </span><span style="font-weight:bold;color:#a71d5d;">&lt; </span><span style="color:#0086b3;">0. </span><span style="color:#323232;">{
</span><span style="color:#323232;">        </span><span style="color:#323232;">t </span><span style="font-weight:bold;color:#a71d5d;">+= </span><span style="color:#0086b3;">1.
</span><span style="color:#323232;">    </span><span style="color:#323232;">}
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">if</span><span style="color:#323232;"> t </span><span style="font-weight:bold;color:#a71d5d;">&gt; </span><span style="color:#0086b3;">1. </span><span style="color:#323232;">{
</span><span style="color:#323232;">        </span><span style="color:#323232;">t </span><span style="font-weight:bold;color:#a71d5d;">-= </span><span style="color:#0086b3;">1.
</span><span style="color:#323232;">    </span><span style="color:#323232;">};
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">if</span><span style="color:#323232;"> t </span><span style="font-weight:bold;color:#a71d5d;">&lt; </span><span style="color:#0086b3;">1. </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#0086b3;">6. </span><span style="color:#323232;">{
</span><span style="color:#323232;">        </span><span style="font-weight:bold;color:#a71d5d;">return</span><span style="color:#323232;"> p </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">(q </span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#323232;"> p) </span><span style="font-weight:bold;color:#a71d5d;">* </span><span style="color:#0086b3;">6. </span><span style="font-weight:bold;color:#a71d5d;">*</span><span style="color:#323232;"> t;
</span><span style="color:#323232;">    </span><span style="color:#323232;">}
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">if</span><span style="color:#323232;"> t </span><span style="font-weight:bold;color:#a71d5d;">&lt; </span><span style="color:#0086b3;">1. </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#0086b3;">2. </span><span style="color:#323232;">{
</span><span style="color:#323232;">        </span><span style="font-weight:bold;color:#a71d5d;">return</span><span style="color:#323232;"> q;
</span><span style="color:#323232;">    </span><span style="color:#323232;">}
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">if</span><span style="color:#323232;"> t </span><span style="font-weight:bold;color:#a71d5d;">&lt; </span><span style="color:#0086b3;">2. </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#0086b3;">3. </span><span style="color:#323232;">{
</span><span style="color:#323232;">        </span><span style="font-weight:bold;color:#a71d5d;">return</span><span style="color:#323232;"> p </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">(q </span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#323232;"> p) </span><span style="font-weight:bold;color:#a71d5d;">* </span><span style="color:#323232;">(</span><span style="color:#0086b3;">2. </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#0086b3;">3. </span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#323232;"> t) </span><span style="font-weight:bold;color:#a71d5d;">* </span><span style="color:#0086b3;">6.</span><span style="color:#323232;">;
</span><span style="color:#323232;">    </span><span style="color:#323232;">}
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">return</span><span style="color:#323232;"> p;
</span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">hsl_to_rgb</span><span style="color:#323232;">(h: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">, s: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">, l: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">) -&gt; (</span><span style="font-weight:bold;color:#a71d5d;">u8</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">u8</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">u8</span><span style="color:#323232;">) {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> r;
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> g;
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> b;
</span><span style="color:#323232;">
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">if</span><span style="color:#323232;"> s </span><span style="font-weight:bold;color:#a71d5d;">== </span><span style="color:#0086b3;">0.0 </span><span style="color:#323232;">{
</span><span style="color:#323232;">        </span><span style="color:#323232;">r </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> l;
</span><span style="color:#323232;">        </span><span style="color:#323232;">g </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> l;
</span><span style="color:#323232;">        </span><span style="color:#323232;">b </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> l; </span><span style="font-style:italic;color:#969896;">// achromatic
</span><span style="color:#323232;">    </span><span style="color:#323232;">} </span><span style="font-weight:bold;color:#a71d5d;">else </span><span style="color:#323232;">{
</span><span style="color:#323232;">        </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> q </span><span style="font-weight:bold;color:#a71d5d;">= if</span><span style="color:#323232;"> l </span><span style="font-weight:bold;color:#a71d5d;">&lt; </span><span style="color:#0086b3;">0.5 </span><span style="color:#323232;">{ l </span><span style="font-weight:bold;color:#a71d5d;">* </span><span style="color:#323232;">(</span><span style="color:#0086b3;">1. </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> s) } </span><span style="font-weight:bold;color:#a71d5d;">else </span><span style="color:#323232;">{ l </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> s </span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#323232;"> l </span><span style="font-weight:bold;color:#a71d5d;">*</span><span style="color:#323232;"> s };
</span><span style="color:#323232;">
</span><span style="color:#323232;">        </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> p </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">2. </span><span style="font-weight:bold;color:#a71d5d;">*</span><span style="color:#323232;"> l </span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#323232;"> q;
</span><span style="color:#323232;">        </span><span style="color:#323232;">r </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#62a35c;">hue_to_rgb</span><span style="color:#323232;">(p, q, h </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#0086b3;">1. </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#0086b3;">3.</span><span style="color:#323232;">);
</span><span style="color:#323232;">        </span><span style="color:#323232;">g </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#62a35c;">hue_to_rgb</span><span style="color:#323232;">(p, q, h);
</span><span style="color:#323232;">        </span><span style="color:#323232;">b </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#62a35c;">hue_to_rgb</span><span style="color:#323232;">(p, q, h </span><span style="font-weight:bold;color:#a71d5d;">- </span><span style="color:#0086b3;">1. </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#0086b3;">3.</span><span style="color:#323232;">);
</span><span style="color:#323232;">    </span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#323232;">(
</span><span style="color:#323232;">        </span><span style="color:#323232;">(r </span><span style="font-weight:bold;color:#a71d5d;">* </span><span style="color:#0086b3;">255.</span><span style="color:#323232;">).</span><span style="color:#62a35c;">round</span><span style="color:#323232;">() </span><span style="font-weight:bold;color:#a71d5d;">as u8</span><span style="color:#323232;">,
</span><span style="color:#323232;">        </span><span style="color:#323232;">(g </span><span style="font-weight:bold;color:#a71d5d;">* </span><span style="color:#0086b3;">255.</span><span style="color:#323232;">).</span><span style="color:#62a35c;">round</span><span style="color:#323232;">() </span><span style="font-weight:bold;color:#a71d5d;">as u8</span><span style="color:#323232;">,
</span><span style="color:#323232;">        </span><span style="color:#323232;">(b </span><span style="font-weight:bold;color:#a71d5d;">* </span><span style="color:#0086b3;">255.</span><span style="color:#323232;">).</span><span style="color:#62a35c;">round</span><span style="color:#323232;">() </span><span style="font-weight:bold;color:#a71d5d;">as u8</span><span style="color:#323232;">,
</span><span style="color:#323232;">    </span><span style="color:#323232;">);
</span><span style="color:#323232;">}
</span></pre>
<p>Let's draw a color on the screen as a sanity check.</p>
<p>Clear out the widget impl's <code>paint</code> method and put this in instead:</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">paint</span><span style="color:#323232;">(
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">&amp;mut </span><span style="color:#323232;">self,
</span><span style="color:#323232;">    </span><span style="color:#323232;">paint_ctx: </span><span style="font-weight:bold;color:#a71d5d;">&amp;mut</span><span style="color:#323232;"> PaintCtx,
</span><span style="color:#323232;">    </span><span style="color:#323232;">base_state: </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">BaseState,
</span><span style="color:#323232;">    </span><span style="color:#323232;">data: </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">String,
</span><span style="color:#323232;">    </span><span style="color:#323232;">_env: </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">Env,
</span><span style="color:#323232;">) {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> rgb </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#62a35c;">hsl_to_rgb</span><span style="color:#323232;">(</span><span style="color:#0086b3;">0.5</span><span style="color:#323232;">, </span><span style="color:#0086b3;">0.5</span><span style="color:#323232;">, </span><span style="color:#0086b3;">0.5</span><span style="color:#323232;">);
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> rect </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">Rect::from_origin_size(Point::</span><span style="color:#0086b3;">ORIGIN</span><span style="color:#323232;">, base_state.</span><span style="color:#62a35c;">size</span><span style="color:#323232;">());
</span><span style="color:#323232;">    </span><span style="color:#323232;">paint_ctx.</span><span style="color:#62a35c;">fill</span><span style="color:#323232;">(rect, </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">Color::rgb8(rgb.</span><span style="color:#0086b3;">0</span><span style="color:#323232;">, rgb.</span><span style="color:#0086b3;">1</span><span style="color:#323232;">, rgb.</span><span style="color:#0086b3;">2</span><span style="color:#323232;">));
</span><span style="color:#323232;">}
</span></pre>
<p>If everything goes well, you may discover a marvelous new shade of... blue? I think that's in the blue family.</p>
<p><img src="../static/images/dw_2.png" alt="delightful blue widget" /></p>
<p>Now let's draw our SL by repurposing that suspiciously convenient <code>make_image_data()</code> function at the bottom of this file.</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">make_sl_image</span><span style="color:#323232;">(width: </span><span style="font-weight:bold;color:#a71d5d;">usize</span><span style="color:#323232;">, height: </span><span style="font-weight:bold;color:#a71d5d;">usize</span><span style="color:#323232;">, hue: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">) -&gt; Vec&lt;</span><span style="font-weight:bold;color:#a71d5d;">u8</span><span style="color:#323232;">&gt; {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">let mut</span><span style="color:#323232;"> image_data </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">vec![</span><span style="color:#0086b3;">0</span><span style="color:#323232;">; width </span><span style="font-weight:bold;color:#a71d5d;">*</span><span style="color:#323232;"> height </span><span style="font-weight:bold;color:#a71d5d;">* </span><span style="color:#0086b3;">4</span><span style="color:#323232;">];
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">for</span><span style="color:#323232;"> y </span><span style="font-weight:bold;color:#a71d5d;">in </span><span style="color:#0086b3;">0</span><span style="font-weight:bold;color:#a71d5d;">..</span><span style="color:#323232;">height {
</span><span style="color:#323232;">        </span><span style="font-weight:bold;color:#a71d5d;">for</span><span style="color:#323232;"> x </span><span style="font-weight:bold;color:#a71d5d;">in </span><span style="color:#0086b3;">0</span><span style="font-weight:bold;color:#a71d5d;">..</span><span style="color:#323232;">width {
</span><span style="color:#323232;">            </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> ix </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">(y </span><span style="font-weight:bold;color:#a71d5d;">*</span><span style="color:#323232;"> width </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> x) </span><span style="font-weight:bold;color:#a71d5d;">* </span><span style="color:#0086b3;">4</span><span style="color:#323232;">;
</span><span style="color:#323232;">            </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> x_ratio </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> x </span><span style="font-weight:bold;color:#a71d5d;">as f64 /</span><span style="color:#323232;"> width </span><span style="font-weight:bold;color:#a71d5d;">as f64</span><span style="color:#323232;">;
</span><span style="color:#323232;">            </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> y_ratio </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> y </span><span style="font-weight:bold;color:#a71d5d;">as f64 /</span><span style="color:#323232;"> width </span><span style="font-weight:bold;color:#a71d5d;">as f64</span><span style="color:#323232;">;
</span><span style="color:#323232;">
</span><span style="color:#323232;">            </span><span style="font-style:italic;color:#969896;">// Where the magic happens
</span><span style="color:#323232;">            </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> color </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#62a35c;">hsl_to_rgb</span><span style="color:#323232;">(hue, x_ratio, y_ratio);
</span><span style="color:#323232;">
</span><span style="color:#323232;">            </span><span style="color:#323232;">image_data[ix </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#0086b3;">0</span><span style="color:#323232;">] </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> color.</span><span style="color:#0086b3;">0</span><span style="color:#323232;">;
</span><span style="color:#323232;">            </span><span style="color:#323232;">image_data[ix </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#0086b3;">1</span><span style="color:#323232;">] </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> color.</span><span style="color:#0086b3;">1</span><span style="color:#323232;">;
</span><span style="color:#323232;">            </span><span style="color:#323232;">image_data[ix </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#0086b3;">2</span><span style="color:#323232;">] </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> color.</span><span style="color:#0086b3;">2</span><span style="color:#323232;">;
</span><span style="color:#323232;">            </span><span style="color:#323232;">image_data[ix </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#0086b3;">3</span><span style="color:#323232;">] </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">255
</span><span style="color:#323232;">        </span><span style="color:#323232;">}
</span><span style="color:#323232;">    </span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="color:#323232;">    </span><span style="color:#323232;">image_data
</span><span style="color:#323232;">}
</span></pre>
<p>I promise you that most of Piet isn't creating your own <code>Vec&lt;u8&gt;</code> image buffers from scratch, but that doesn't mean you can't enjoy these occasions.</p>
<p>Now let's return to the paint method and draw the image:</p>
<pre style="background-color: #eff0f1;"><span style="font-style:italic;color:#969896;">// We&#39;re generating a 256 by 256 pixels image, with a constant hue of 0.5
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> image_data </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#62a35c;">make_sl_image</span><span style="color:#323232;">(</span><span style="color:#0086b3;">256</span><span style="color:#323232;">, </span><span style="color:#0086b3;">256</span><span style="color:#323232;">, </span><span style="color:#0086b3;">0.5</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> image </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> paint_ctx
</span><span style="color:#323232;">    </span><span style="color:#323232;">.</span><span style="color:#62a35c;">make_image</span><span style="color:#323232;">(</span><span style="color:#0086b3;">256</span><span style="color:#323232;">, </span><span style="color:#0086b3;">256</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">image_data, ImageFormat::RgbaSeparate)
</span><span style="color:#323232;">    </span><span style="color:#323232;">.</span><span style="color:#62a35c;">unwrap</span><span style="color:#323232;">();
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// When piet draws our image it will stretch it automatically.
</span><span style="font-style:italic;color:#969896;">// We&#39;ll fix this later by giving our widget a fixed size.
</span><span style="color:#323232;">paint_ctx.</span><span style="color:#62a35c;">draw_image</span><span style="color:#323232;">(
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">image,
</span><span style="color:#323232;">    </span><span style="color:#323232;">Rect::from_origin_size(Point::</span><span style="color:#0086b3;">ORIGIN</span><span style="color:#323232;">, base_state.</span><span style="color:#62a35c;">size</span><span style="color:#323232;">()),
</span><span style="color:#323232;">    </span><span style="color:#323232;">InterpolationMode::Bilinear,
</span><span style="color:#323232;">);
</span></pre>
<p>Okay, so we're the king of gradients now. But how about interactivity?</p>
<h2>4. Paint a rectangle</h2>
<p>To put the &quot;picker&quot; in color picker, let's draw a rectangular cursor that we can move around.</p>
<p>Our cursor will need an x and y coordinate to be drawn at, and that will require some modicum of statefulness. For now, let's make it private to our widget.</p>
<p>If you haven't renamed the <code>CustomWidget</code> struct yet, now is your moment!</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">struct </span><span style="color:#323232;">ColorPicker {
</span><span style="color:#323232;">    </span><span style="color:#323232;">cursor_x: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">,
</span><span style="color:#323232;">    </span><span style="color:#323232;">cursor_y: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">,
</span><span style="color:#323232;">}
</span></pre>
<p>Let's initialize ColorPicker with some default values in <code>main()</code>:</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> window </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">WindowDesc::new(|| ColorPicker { cursor_x: </span><span style="color:#0086b3;">0.2</span><span style="color:#323232;">, cursor_y: </span><span style="color:#0086b3;">0.9 </span><span style="color:#323232;">});
</span></pre>
<p>Now let's draw a black rectangle at that (x, y) position. Inside our paint method, below the call to <code>draw_image()</code>:</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> cursor_rect </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">Rect::from_origin_size((</span><span style="color:#0086b3;">100.</span><span style="color:#323232;">, </span><span style="color:#0086b3;">100.</span><span style="color:#323232;">), (</span><span style="color:#0086b3;">10.</span><span style="color:#323232;">, </span><span style="color:#0086b3;">10.</span><span style="color:#323232;">));
</span><span style="color:#323232;">paint_ctx.</span><span style="color:#62a35c;">stroke</span><span style="color:#323232;">(cursor_rect, </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">Color::</span><span style="color:#0086b3;">BLACK</span><span style="color:#323232;">, </span><span style="color:#0086b3;">1.0</span><span style="color:#323232;">);
</span></pre>
<p>That paints a black-stroked rectangle at the point (100., 100.), with the size of (10., 10.). I know that doesn't use our <code>cursor_x</code> / <code>y</code>, but I just wanted to show you the basic pixel positioning version real quick before we get fancy and use a <code>UnitPoint</code> for positioning.</p>
<p><img src="../static/images/dw_3.png" alt="we drew a rectangle" /></p>
<p>Okay, fancy time:</p>
<pre style="background-color: #eff0f1;"><span style="font-style:italic;color:#969896;">// Create a UnitPoint from our cursor floats
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> cursor_point </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">druid::piet::UnitPoint::new(self.cursor_x, self.cursor_y);
</span><span style="font-style:italic;color:#969896;">// Create a rect that&#39;s the size of our whole widget
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> resolve_rect </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">Rect::from_origin_size(Point::</span><span style="color:#0086b3;">ORIGIN</span><span style="color:#323232;">, base_state.</span><span style="color:#62a35c;">size</span><span style="color:#323232;">());
</span><span style="font-style:italic;color:#969896;">// Calling resolve on the UnitPoint returns a Point relative to the rectangle it&#39;s passed
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> resolved_point </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cursor_point.</span><span style="color:#62a35c;">resolve</span><span style="color:#323232;">(resolve_rect);
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> cursor_rect </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">Rect::from_origin_size(resolved_point, (</span><span style="color:#0086b3;">10.</span><span style="color:#323232;">, </span><span style="color:#0086b3;">10.</span><span style="color:#323232;">));
</span><span style="color:#323232;">paint_ctx.</span><span style="color:#62a35c;">stroke</span><span style="color:#323232;">(cursor_rect, </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">Color::</span><span style="color:#0086b3;">BLACK</span><span style="color:#323232;">, </span><span style="color:#0086b3;">1.0</span><span style="color:#323232;">);
</span></pre>
<p>Beautiful.</p>
<p>One last thing to draw: an inset white rectangle to make our cursor visible over dark zones.</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> inset_point </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> resolved_point </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">druid::kurbo::Vec2::new(</span><span style="color:#0086b3;">1.</span><span style="color:#323232;">, </span><span style="color:#0086b3;">1.</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> white_cursor_rect </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">Rect::from_origin_size(inset_point, (</span><span style="color:#0086b3;">8.</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8.</span><span style="color:#323232;">));
</span><span style="color:#323232;">paint_ctx.</span><span style="color:#62a35c;">stroke</span><span style="color:#323232;">(white_cursor_rect, </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">Color::rgba8(</span><span style="color:#0086b3;">255</span><span style="color:#323232;">, </span><span style="color:#0086b3;">255</span><span style="color:#323232;">, </span><span style="color:#0086b3;">255</span><span style="color:#323232;">, </span><span style="color:#0086b3;">128</span><span style="color:#323232;">), </span><span style="color:#0086b3;">1.0</span><span style="color:#323232;">);
</span></pre>
<p>Note the tasteful use of transparency in the fourth or fifth method of color creation I've shown thus far.</p>
<h2>5. Adding interactivity</h2>
<p>Time to move on to the <code>fn event()</code> method! The <code>event()</code> method receives an <code>Event</code> called <code>event</code> that we can match on:</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">event</span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">&amp;mut </span><span style="color:#323232;">self, event: </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">Event, _ctx: </span><span style="font-weight:bold;color:#a71d5d;">&amp;mut</span><span style="color:#323232;"> EventCtx, _data: </span><span style="font-weight:bold;color:#a71d5d;">&amp;mut</span><span style="color:#323232;"> String, _env: </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">Env) {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">match</span><span style="color:#323232;"> event {
</span><span style="color:#323232;">        </span><span style="color:#323232;">Event::MouseDown(mouse) </span><span style="font-weight:bold;color:#a71d5d;">=&gt; </span><span style="color:#323232;">{
</span><span style="color:#323232;">            </span><span style="color:#323232;">dbg!(mouse);
</span><span style="color:#323232;">        </span><span style="color:#323232;">},
</span><span style="color:#323232;">        </span><span style="font-weight:bold;color:#a71d5d;">_ =&gt; </span><span style="color:#323232;">(),
</span><span style="color:#323232;">    </span><span style="color:#323232;">}
</span><span style="color:#323232;">}
</span></pre>
<p>If you run the app and click anywhere inside the window, you should get some helpful info about the <code>MouseEvent</code> printed to the terminal.</p>
<p>Here's what mine said:</p>
<pre style="white-space: pre-wrap;">[examples/color_picker.rs:133] mouse = MouseEvent {
    pos: (260.84375, 203.609375),
    mods: Mods(None),
    count: 1,
    button: Left,
}
</pre>
<p>So what we want to do is take that position, <code>UnitPoint</code>-ify it, and set <code>self.cursor_x</code> / <code>self.cursor_y</code> to that.</p>
<p>But here's the thing: we need to know how big the widget is to calculate a 0.0 -&gt; 1.0 value, and we can't access that size information from inside the event handler. So: more state!</p>
<p>Add a size field to our struct.</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">struct </span><span style="color:#323232;">ColorPicker {
</span><span style="color:#323232;">    </span><span style="color:#323232;">cursor_x: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">,
</span><span style="color:#323232;">    </span><span style="color:#323232;">cursor_y: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">,
</span><span style="color:#323232;">    </span><span style="color:#323232;">size: Size,
</span><span style="color:#323232;">}
</span></pre>
<p>And initialize it as <code>Size::default()</code>.</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> window </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">WindowDesc::new(|| ColorPicker {
</span><span style="color:#323232;">    </span><span style="color:#323232;">cursor_x: </span><span style="color:#0086b3;">0.2</span><span style="color:#323232;">,
</span><span style="color:#323232;">    </span><span style="color:#323232;">cursor_y: </span><span style="color:#0086b3;">0.9</span><span style="color:#323232;">,
</span><span style="color:#323232;">    </span><span style="color:#323232;">size: Size::default()
</span><span style="color:#323232;">});
</span></pre>
<p>Inside the widget's <code>layout</code> method we'll set the size to equal the max <code>BoxConstraints</code> our widget is passed and then return that.</p>
<pre style="background-color: #eff0f1;"><span style="color:#323232;">self.size </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> bc.</span><span style="color:#62a35c;">max</span><span style="color:#323232;">();
</span><span style="color:#323232;">
</span><span style="color:#323232;">self.size
</span></pre>
<p>And now, finally, we can do our calculation inside the <code>event</code> method:</p>
<pre style="background-color: #eff0f1;"><span style="color:#323232;">Event::MouseDown(mouse) </span><span style="font-weight:bold;color:#a71d5d;">=&gt; </span><span style="color:#323232;">{
</span><span style="color:#323232;">    </span><span style="color:#323232;">self.cursor_x </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> mouse.pos.x </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#323232;">self.size.width;
</span><span style="color:#323232;">    </span><span style="color:#323232;">self.cursor_y </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> mouse.pos.y </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#323232;">self.size.height;
</span><span style="color:#323232;">    </span><span style="color:#323232;">dbg!(self.cursor_x, self.cursor_y);
</span><span style="color:#323232;">},
</span></pre>
<p>Run that and... Oh no! The cursor isn't moving! This was my clever plan to get you to notice one very important part of widget-building:</p>
<pre style="background-color: #eff0f1;"><span style="color:#323232;">ctx.</span><span style="color:#62a35c;">invalidate</span><span style="color:#323232;">();
</span></pre>
<p>Invalidate marks this widget as &quot;dirty,&quot; so now Druid knows to redraw it on its next pass. Add this line below those cursor calculations in <code>event</code> and you should have your first interactive Druid widget up and running! Congrats.</p>
<h2>6. Better event handling</h2>
<p><img src="../static/images/dw_anim_small.gif" alt="interactive example" /></p>
<p>If you click around you'll notice the cursor doesn't move exactly how you'd expect, especially when you click and drag. That's because you've used a color picker before, and you have expectations. This is the &quot;game&quot; of making widgets: if it looks like a widget people have used before, it needs to behave in a way that those prior experiences have conditioned them for.</p>
<p>To be specific: in our case, we need to handle <code>Event::MouseMoved</code> inside our <code>event</code> match statement.</p>
<pre style="background-color: #eff0f1;"><span style="color:#323232;">Event::MouseMoved(mouse) </span><span style="font-weight:bold;color:#a71d5d;">=&gt; </span><span style="color:#323232;">{
</span><span style="color:#323232;">    </span><span style="color:#323232;">self.cursor_x </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> mouse.pos.x </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#323232;">self.size.width;
</span><span style="color:#323232;">    </span><span style="color:#323232;">self.cursor_y </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> mouse.pos.y </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#323232;">self.size.height;
</span><span style="color:#323232;">    </span><span style="color:#323232;">ctx.</span><span style="color:#62a35c;">invalidate</span><span style="color:#323232;">();
</span><span style="color:#323232;">},
</span></pre>
<p>If you run that, you'll notice it works a little too well: now the cursor follows your mouse around no matter what.</p>
<p>In the <code>MouseDown</code> event we need to set the widget as &quot;active,&quot; and then when we move the cursor we can check if we're active. And so, of course, we'll also need a <code>MouseUp</code> event to turn off active.</p>
<pre style="background-color: #eff0f1;"><span style="color:#323232;">Event::MouseDown(mouse) </span><span style="font-weight:bold;color:#a71d5d;">=&gt; </span><span style="color:#323232;">{
</span><span style="color:#323232;">    </span><span style="color:#323232;">ctx.</span><span style="color:#62a35c;">set_active</span><span style="color:#323232;">(</span><span style="color:#0086b3;">true</span><span style="color:#323232;">);
</span><span style="color:#323232;">    </span><span style="color:#323232;">self.cursor_x </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> mouse.pos.x </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#323232;">self.size.width;
</span><span style="color:#323232;">    </span><span style="color:#323232;">self.cursor_y </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> mouse.pos.y </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#323232;">self.size.height;
</span><span style="color:#323232;">    </span><span style="color:#323232;">ctx.</span><span style="color:#62a35c;">invalidate</span><span style="color:#323232;">();
</span><span style="color:#323232;">},
</span><span style="color:#323232;">Event::MouseMoved(mouse) </span><span style="font-weight:bold;color:#a71d5d;">=&gt; </span><span style="color:#323232;">{
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">if</span><span style="color:#323232;"> ctx.</span><span style="color:#62a35c;">is_active</span><span style="color:#323232;">() {
</span><span style="color:#323232;">        </span><span style="color:#323232;">self.cursor_x </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> mouse.pos.x </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#323232;">self.size.width;
</span><span style="color:#323232;">        </span><span style="color:#323232;">self.cursor_y </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> mouse.pos.y </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#323232;">self.size.height;
</span><span style="color:#323232;">        </span><span style="color:#323232;">ctx.</span><span style="color:#62a35c;">invalidate</span><span style="color:#323232;">();
</span><span style="color:#323232;">    </span><span style="color:#323232;">}
</span><span style="color:#323232;">},
</span><span style="color:#323232;">Event::MouseUp(</span><span style="font-weight:bold;color:#a71d5d;">_</span><span style="color:#323232;">) </span><span style="font-weight:bold;color:#a71d5d;">=&gt; </span><span style="color:#323232;">{
</span><span style="color:#323232;">    </span><span style="color:#323232;">ctx.</span><span style="color:#62a35c;">set_active</span><span style="color:#323232;">(</span><span style="color:#0086b3;">false</span><span style="color:#323232;">);
</span><span style="color:#323232;">},
</span><span style="font-weight:bold;color:#a71d5d;">_ =&gt; </span><span style="color:#323232;">(),
</span></pre>
<p>You'll notice we're working with the mutable <code>EventCtx</code> object, which is a bit of a grab bag of functionality. I won't go into it all here, I'm just giving you a heads up in case you're wondering how to do X and you find out later that X is a method on <code>EventCtx</code>.</p>
<h2>7. Dealing with Data</h2>
<p>Right now our app functional but... incomplete. One limitation is the fact that we have no idea what color value we've selected unless we print it to the terminal. Let's fix that.</p>
<p>You might have noticed that we're still passing a <code>String</code> to our root widget at app launch. Let's change that to a custom <code>ColorState</code> struct, and make a new <code>HSL</code> color type for it to hold.</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">use </span><span style="color:#323232;">druid::{Data, </span><span style="font-weight:bold;color:#a71d5d;">...</span><span style="color:#323232;">};
</span><span style="color:#323232;">
</span><span style="color:#323232;">#[derive(Clone, Data)]
</span><span style="font-weight:bold;color:#a71d5d;">struct </span><span style="color:#323232;">HSL {
</span><span style="color:#323232;">    </span><span style="color:#323232;">hue: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">,
</span><span style="color:#323232;">    </span><span style="color:#323232;">saturation: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">,
</span><span style="color:#323232;">    </span><span style="color:#323232;">lightness: </span><span style="font-weight:bold;color:#a71d5d;">f64
</span><span style="color:#323232;">}
</span></pre>
<p>The <code>Data</code> trait has to be implemented for any data that flows through our app; Druid uses it to determine when changes have occured that our widget needs to know about. <code>Data</code> can be derived in most cases; what’s important is that types that implement <code>Data</code> should be fairly cheap to clone and compare. Importantly, <code>Data</code> is implemented automatically for primitive types, as well as for <code>Arc&lt;T&gt;</code> and <code>Rc&lt;T&gt;</code>; if you're using a more complicated type, you can always wrap it in one of those smart pointers.</p>
<p>Right now our <code>ColorPicker</code> widget only accepts data of type <code>String</code>. Change it to <code>HSL</code>.</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">impl </span><span style="color:#323232;">Widget&lt;HSL&gt; </span><span style="font-weight:bold;color:#a71d5d;">for </span><span style="color:#323232;">ColorPicker {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">...
</span><span style="color:#323232;">}
</span></pre>
<p>Then, in the AppLauncher, change the initial state to an <code>HSL</code> object with your favorite initial values.</p>
<pre style="background-color: #eff0f1;"><span style="color:#323232;">.</span><span style="color:#62a35c;">launch</span><span style="color:#323232;">(</span><span style="color:#0086b3;">HSL </span><span style="color:#323232;">{ hue: </span><span style="color:#0086b3;">0.4</span><span style="color:#323232;">, saturation: </span><span style="color:#0086b3;">0.4</span><span style="color:#323232;">, lightness: </span><span style="color:#0086b3;">0.4 </span><span style="color:#323232;">})
</span></pre>
<p>We also need to change the type of the data field in each of our widget methods from <code>&amp;String</code> / <code>&amp;mut String</code> to <code>&amp;HSL</code> / <code>&amp;mut HSL</code>.</p>
<p>And now that <em>that's</em> all wired up, we can go around and change all of our <code>self.cursor_x</code> and <code>self.cursor_y</code> out for <code>data.saturation</code> and <code>data.lightness</code> respectively and delete <code>cursor_x</code> / <code>cursor_y</code> from the ColorPicker struct. In a sense, we've &quot;lifted&quot; the source of truth for our widget's important state up to the app level, while keeping the unimportant implementation details (just the size, in this case) internal.</p>
<p>Now if you change the hardcoded hue value being passed to <code>make_sl_image()</code> to <code>data.hue</code>, you should see whatever initial hue state you've provided your app.</p>
<h2>8. Sliders (and Lenses!)</h2>
<p>So right now we can set the hue at compile time. But a real color picker would let you adjust it on the fly. What we need is a slider.</p>
<p>I just so happen to be the proud father of a widget called Slider. While our ColorPicker is currently designed to work with data of type <code>HSL</code>, Slider operates on plain old <code>f64</code>. So if we put a Slider in our widget tree, what will happen? We'll get an error something like this:</p>
<pre style="white-space: pre-wrap;">the trait `druid::Widget&lt;HSL&gt;` is not implemented for `impl druid::Widget&lt;f64&gt;`
</pre>
<p>But ColorPicker is just three f64s under the hood. How do we get at those?</p>
<p>Enter Lenses. A lens is a datatype that gives access to a part of a larger data structure. In our case, we can derive Lens just like how we derived Data:</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">use </span><span style="color:#323232;">druid::{Lens, </span><span style="font-weight:bold;color:#a71d5d;">...</span><span style="color:#323232;">};
</span><span style="color:#323232;">
</span><span style="color:#323232;">#[derive(Clone, Data, Lens)]
</span><span style="font-weight:bold;color:#a71d5d;">struct </span><span style="color:#323232;">HSL {
</span><span style="color:#323232;">    </span><span style="color:#323232;">hue: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">,
</span><span style="color:#323232;">    </span><span style="color:#323232;">saturation: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">,
</span><span style="color:#323232;">    </span><span style="color:#323232;">lightness: </span><span style="font-weight:bold;color:#a71d5d;">f64</span><span style="color:#323232;">,
</span><span style="color:#323232;">}
</span></pre>
<p>This macro creates a module called <code>lenses</code>, with a submodule of <code>hsl</code>, with subsubmodules of <code>hue</code>, <code>saturation</code>, and <code>lightness</code>. We can use these lenses to adapt our <code>HSL</code> data structure to any widget that expects an f64:</p>
<pre style="background-color: #eff0f1;"><span style="color:#323232;">LensWrap::new(WidgetThatExpectsf64::new(), lenses::hsl::hue);
</span></pre>
<p>Sorry for the excess of magic, Druid is a work in progress and we're still figuring out the design for some of this stuff. The most important takeaway for now is that Lenses let us &quot;focus&quot; on a single field in a larger data structure.</p>
<pre style="white-space: pre-wrap;">                   +-------+
                   |       |
Struct with        |       |       That one
a bunch of  +----&gt; | Lens  | +---&gt; field we
fields             |       |       care about
                   |       |
                   +-------+
</pre>
<p>You could think of them like a mask in Photoshop:
<img src="../static/images/dw_lens.png" alt="lens mask" /></p>
<p>Or, if it helps, just think of it as a getter / setter.</p>
<p>Okay, so we're about to expand our widget tree a bit. Let's spin it out into its own function. For starters, let's just do a lens-wrapped Slider on its own and then we'll add the ColorPicker back in.</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">use </span><span style="color:#323232;">druid::{LensWrap, </span><span style="font-weight:bold;color:#a71d5d;">...</span><span style="color:#323232;">};
</span><span style="font-weight:bold;color:#a71d5d;">use </span><span style="color:#323232;">druid::widget::{Slider};
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">ui_builder</span><span style="color:#323232;">() -&gt; impl Widget&lt;HSL&gt; {
</span><span style="color:#323232;">    </span><span style="color:#323232;">
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> slider </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">LensWrap::new(Slider::new(), lenses::hsl::hue);
</span><span style="color:#323232;">    </span><span style="color:#323232;">
</span><span style="color:#323232;">    </span><span style="color:#323232;">slider
</span><span style="color:#323232;">
</span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> window </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">WindowDesc::new(ui_builder);
</span><span style="color:#323232;">    </span><span style="color:#323232;">
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">...
</span><span style="color:#323232;">    </span><span style="color:#323232;">
</span><span style="color:#323232;">}
</span></pre>
<p>So now <code>ui_builder()</code> will construct our widget tree for us. We pass the Slider widget and the hue lens to LensWrap, which acts as a higher order widget. The Slider gets (mutable!) access to the HSL’s hue field.</p>
<p>If you run that, you should get an app that's just a Slider. Let's add a few labels so we can see what the slider is doing.</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">use </span><span style="color:#323232;">druid::widget::{Column, DynLabel, </span><span style="font-weight:bold;color:#a71d5d;">...</span><span style="color:#323232;">};
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let mut</span><span style="color:#323232;"> col </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">Column::new();
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> slider </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">LensWrap::new(Slider::new(), lenses::hsl::hue);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> hue_label </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">DynLabel::new(|data: </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">HSL, _env| {
</span><span style="color:#323232;">    </span><span style="color:#323232;">format!(</span><span style="color:#183691;">&quot;Hue: </span><span style="color:#0086b3;">{0:.2}</span><span style="color:#183691;">&quot;</span><span style="color:#323232;">, data.hue)
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> sat_label </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">DynLabel::new(|data: </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">HSL, _env| {
</span><span style="color:#323232;">    </span><span style="color:#323232;">format!(</span><span style="color:#183691;">&quot;Saturation: </span><span style="color:#0086b3;">{0:.2}</span><span style="color:#183691;">&quot;</span><span style="color:#323232;">, data.saturation)
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> light_label </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">DynLabel::new(|data: </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">HSL, _env| {
</span><span style="color:#323232;">    </span><span style="color:#323232;">format!(</span><span style="color:#183691;">&quot;Lightness: </span><span style="color:#0086b3;">{0:.2}</span><span style="color:#183691;">&quot;</span><span style="color:#323232;">, data.lightness)
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="color:#323232;">col.</span><span style="color:#62a35c;">add_child</span><span style="color:#323232;">(slider, </span><span style="color:#0086b3;">1.0</span><span style="color:#323232;">);
</span><span style="color:#323232;">col.</span><span style="color:#62a35c;">add_child</span><span style="color:#323232;">(hue_label, </span><span style="color:#0086b3;">1.0</span><span style="color:#323232;">);
</span><span style="color:#323232;">col.</span><span style="color:#62a35c;">add_child</span><span style="color:#323232;">(sat_label, </span><span style="color:#0086b3;">1.0</span><span style="color:#323232;">);
</span><span style="color:#323232;">col.</span><span style="color:#62a35c;">add_child</span><span style="color:#323232;">(light_label, </span><span style="color:#0086b3;">1.0</span><span style="color:#323232;">);
</span><span style="color:#323232;">col
</span></pre>
<p>Each of these DynLabel widgets accepts a closure which converts the data into a String (so no need for a Lens). We add them each, along with the slider, to a column widget to keep everything nice and organized.</p>
<p>Now let's add back in the ColorPicker widget.</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> color_picker </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> ColorPicker {
</span><span style="color:#323232;">    </span><span style="color:#323232;">size: Size::default()
</span><span style="color:#323232;">};
</span><span style="color:#323232;">col.</span><span style="color:#62a35c;">add_child</span><span style="color:#323232;">(color_picker, </span><span style="color:#0086b3;">1.0</span><span style="color:#323232;">);
</span></pre>
<p>If everything has gone correctly, the hue slider should control the hue of our ColorPicker now. Not too bad, yes?</p>
<h2>Eight Point Five</h2>
<p>One quick fix to keep our cursor (mostly) inside its zone:</p>
<pre style="background-color: #eff0f1;"><span style="color:#323232;">data.saturation </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">(mouse.pos.x </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#323232;">self.size.width).</span><span style="color:#62a35c;">max</span><span style="color:#323232;">(</span><span style="color:#0086b3;">0.0</span><span style="color:#323232;">).</span><span style="color:#62a35c;">min</span><span style="color:#323232;">(</span><span style="color:#0086b3;">1.0</span><span style="color:#323232;">);
</span><span style="color:#323232;">data.lightness </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">(mouse.pos.y </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#323232;">self.size.height).</span><span style="color:#62a35c;">max</span><span style="color:#323232;">(</span><span style="color:#0086b3;">0.0</span><span style="color:#323232;">).</span><span style="color:#62a35c;">min</span><span style="color:#323232;">(</span><span style="color:#0086b3;">1.0</span><span style="color:#323232;">);
</span></pre>
<h2>9. Layout</h2>
<p>Right now our rectangle of color squishes and squashes when we resize the window. That might be appropriate for some widgets, but in my experience, most color pickers have a fixed size and aspect ratio.</p>
<p>Also, just so you're aware, Piet's <code>draw_image()</code> method automatically scales and adjusts the aspect ratio of an image to match the rectangle it's passed. That's why our &quot;256 x 256&quot; image is never actually &quot;256 x 256&quot;</p>
<p>Let's revisit the <code>layout</code> method and fix this.</p>
<pre style="background-color: #eff0f1;"><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> default_size </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">Size::new(</span><span style="color:#0086b3;">256.</span><span style="color:#323232;">, </span><span style="color:#0086b3;">256.</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;">self.size </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> bc.</span><span style="color:#62a35c;">constrain</span><span style="color:#323232;">(default_size);
</span><span style="color:#323232;">
</span><span style="color:#323232;">self.size
</span></pre>
<p>What <code>bc.constrain</code> is saying is: I want to be this particular size, clamped between the maximum size I'm <em>allowed</em> to fill and the minimum size I'm <em>required</em> to fill.</p>
<p>So if we run this... nothing has changed. That's because, in fact, the constraints we're being passed have an identical minimum and max. Therefore <code>constrain</code> ends up ignoring our <code>default_size</code> entirely.</p>
<p>To fix this we need one more widget to wrap <code>color_picker</code> when we add it to <code>col</code>.</p>
<pre style="background-color: #eff0f1;"><span style="color:#323232;">druid::widget::{Align, </span><span style="font-weight:bold;color:#a71d5d;">...</span><span style="color:#323232;">};
</span><span style="font-style:italic;color:#969896;">// col.add_child(color_picker, 1.0);
</span><span style="color:#323232;">col.</span><span style="color:#62a35c;">add_child</span><span style="color:#323232;">(Align::centered(color_picker), </span><span style="color:#0086b3;">1.0</span><span style="color:#323232;">);
</span></pre>
<p>What Align does (in addition to aligning its child) is to pass along a minimum constraint of zero size while keeping the max constraint the same.</p>
<p>Finally, let's zero out the flex amount of the slider and labels:</p>
<pre style="background-color: #eff0f1;"><span style="color:#323232;">col.</span><span style="color:#62a35c;">add_child</span><span style="color:#323232;">(slider, </span><span style="color:#0086b3;">0.0</span><span style="color:#323232;">);
</span><span style="color:#323232;">col.</span><span style="color:#62a35c;">add_child</span><span style="color:#323232;">(hue_label, </span><span style="color:#0086b3;">0.0</span><span style="color:#323232;">);
</span><span style="color:#323232;">col.</span><span style="color:#62a35c;">add_child</span><span style="color:#323232;">(sat_label, </span><span style="color:#0086b3;">0.0</span><span style="color:#323232;">);
</span><span style="color:#323232;">col.</span><span style="color:#62a35c;">add_child</span><span style="color:#323232;">(light_label, </span><span style="color:#0086b3;">0.0</span><span style="color:#323232;">);
</span></pre>
<p><img src="../static/images/dw_4.png" alt="final app" /></p>
<p>Now if we run this, we can still squish the ColorPicker if we make the window really small, but we can't stretch it beyond 256 x 256.</p>
<h2>10. A time for self-congratulation</h2>
<p>Good job if you got this far, and thanks for reading!</p>
<p>Obviously there are a lot of improvements left to make. For instance, the cursor hangs off the edge on the bottom and right sides, and isn't really centered on the mouse anyway. But I think it should be pretty straightforward to solve that problem using the techniques we've already covered and some peeking at other widget code.</p>
<p>It might be fun to make a color picker that's generic over other color spaces, but I don't really know the best way to do that myself so maybe you could do that and tell me about it.</p>
<p>If you do run into issues in general that sound more my speed, please hit me up in my <a href="https://twitter.com/futurepaul">twitter dms</a> or join the #druid channel in our <a href="https://xi.zulipchat.com/">Zulip chat</a>.</p>
<p><em>Update: An earlier version of this tutorial incorrectly used &quot;luminosity&quot; to refer to &quot;lightness.&quot; This has been corrected. Thank you, /u/burgundy_tide!</em></p>
]]>
      </description>
    </item>
    <item>
      <title>
        WHY BITCOIN
      </title>
      <link>https://pauljmiller.com/posts/why-bitcoin.html</link>
      <pubDate>Sat, 21 Sep 2019 00:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/why-bitcoin.html</guid>
      <description>
        <![CDATA[<p><em>This article has been corrected to correct for its lack of capitalization and to fix some broken links. The price was ~10k usd when I wrote this. These days I recommend <a href="https://bitcoin-intro.com/">bitcoin-intro</a> as a nice guided tour if you're looking to get started.</em></p>
<p>OVER THE PAST YEAR I'M SURE YOU'VE NOTICED ME STEERING NEARLY EVERY CONVERSATION INTO BITCOIN. I'LL SAY SOMETHING LIKE, &quot;AND THAT'S WHAT'S SO GREAT ABOUT BITCOIN...&quot; OR &quot;BITCOIN FIXES THIS BECAUSE...&quot; OR A SIMPLE &quot;BUY BITCOIN!&quot;</p>
<p>I APPRECIATE YOUR FORBEARANCE AS I'VE DEVOLVED INTO A CRAZED CULT MEMBER OF AN IMPROBABLE, INVISIBLE, DIGITAL CURRENCY.</p>
<p>BUT WHAT IF I'M NOT, IN FACT, CRAZY? I'D LIKE YOU TO GIVE ME A FEW MINUTES OF YOUR TIME WHILE I EXPLAIN THE RATIONALE BEHIND MY OBSESSION. I DON'T MIND YOU DUNKING ON ME WITH &quot;SILLY PAUL AND HIS BITCOIN!&quot; GOOFS, I UNDERSTAND THAT BITCOIN ON ITS SURFACE SOUNDS WEIRD AND POINTLESS. BUT THERE IS AN ACTUAL DEPTH OF THOUGHT AND A SERIOUS MOTIVATION BEHIND BITCOIN, AND I'D LOVE IT IF YOU HEAR ME OUT JUST THIS ONCE, AS A KINDNESS TO ME IF FOR NO OTHER REASON.</p>
<h1>WHAT'S MONEY?</h1>
<p>SERIOUSLY, WHAT IS IT? HOW WOULD YOU DEFINE IT? WHY IS IT IMPORTANT? WHY DON'T WE JUST HAVE A BARTER ECONOMY? WHY IS SOME MONEY BETTER THAN OTHER MONEY? WHICH MONEY IS BEST?</p>
<p>I'D ENCOURAGE YOU TO THINK THROUGH THESE QUESTIONS AT YOUR OWN PACE AND MAKE SURE YOU HAVE A SATISFACTORY ANSWER. IT'S QUESTIONS LIKE THESE, MANY OF WHICH I FIRST ENCOUNTERED IN <a href="https://saifedean.com/thebitcoinstandard/">SAIFEDEAN AMMOUS' <em>THE BITCOIN STANDARD</em></a>, WHICH LED ME TO MY CURRENT STANCE ON THE TOPIC: BITCOIN IS THE BEST MONEY.</p>
<p>HERE'S ONE WAY TO THINK OF MONEY: MONEY IS A TECHNOLOGY FOR TRANSFERRING VALUE THROUGH TIME AND SPACE.</p>
<p>WHEN WE DO USEFUL WORK WE CREATE VALUE. OFTEN SOMEONE IS WILLING TO PAY US FOR OUR WORK. IT MIGHT BE A LIKE-FOR-LIKE EXCHANGE: &quot;I'LL DO THE DISHES IF YOU MOW THE LAWN.&quot; IT MIGHT BE SOME FORM OF BARTER: &quot;I'LL GIVE YOU A PLAYSTATION IF YOU PAINT THE FENCE.&quot; BUT USUALLY OUR PRIMARY INCOME IS IN THE FORM OF MONEY: &quot;I'LL GIVE YOU $75,000 IF YOU SHOW UP AT THIS OFFICE AND EDIT SPREADSHEETS FOR A YEAR.&quot;</p>
<p>WHEN SOMEONE PAYS US FOR OUR WORK, WE'RE MAKING A TRADE: I VALUE THIS PAYMENT MORE THAN I VALUE MY TIME. AND THE REASON OUR DAY JOB USUALLY PAYS US IN MONEY, NOT PLAYSTATIONS OR BACKRUB IOUS OR CHUCK E. CHEESE TOKENS, IS BECAUSE MONEY IS &quot;THE MOST SALEABLE GOOD.&quot; THAT IS TO SAY, THERE ARE MORE BUYERS OF MONEY THAN THERE ARE BUYERS OF PLAYSTATIONS OR BACKRUB IOUS, THEREFORE IT'S USUALLY THE MOST CONVENIENT THING TO STORE VALUE IN, ALL THINGS BEING EQUAL.</p>
<p>MONEY IS AN INTERMEDIATE. IT'S FOR TRANSFERRING VALUE THROUGH TIME UNTIL YOU KNOW WHAT TO DO WITH IT. IF YOU DON'T KNOW WHAT TO GET SOMEONE FOR THEIR BIRTHDAY, YOU GIVE THEM CASH, SO THEY CAN BUY SOMETHING THEY ACTUALLY WANT. AND YOUR EMPLOYER PAID YOU THAT CASH IN THE FIRST PLACE FOR SIMILAR REASONS.</p>
<p>SO, WHAT DOES THIS HAVE TO DO WITH BITCOIN. WELL, HERE'S A QUESTION ABOUT YOUR CURRENT MONEY: <a href="HTTPS://WWW.FEDERALRESERVE.GOV/FAQS/MONEY_12845.HTM">HOW MANY DOLLARS ARE THERE IN THE WORLD</a>? HOW MANY DOLLARS WILL BE IN THE WORLD TOMORROW? OR A YEAR FROM NOW? FIFTY YEARS FROM NOW?</p>
<p>IF THE PURPOSE OF MONEY IS TO MOVE VALUE THROUGH TIME, WOULDN'T IT BE NICE TO KNOW WHAT &quot;ONE DOLLAR&quot; IS ACTUALLY A SHARE OF? YOU KNOW THE NUMBER ON THE TOP OF THE FRACTION, BUT WHAT'S THE DENOMINATOR? AND, MORE IMPORTANTLY, WHAT WILL THE DENOMINATOR BE WHEN YOU FINALLY NEED TO SPEND IT? IN THE EXTREME CASE: ARE YOU HOLDING ON TO DOLLARS THAT YOU WILL ONE DAY BE SHOVELING INTO A WHEELBARROW?</p>
<p>FOR BITCOIN, <a href="https://www.buybitcoinworldwide.com/how-many-bitcoins-are-there/">FIGURING OUT THE DENOMINATOR IS EASY</a>. AT THE TIME OF THIS WRITING THERE ARE 17,947,425 BITCOINS. EACH DAY THERE ARE 1,800 NEW BITCOINS ADDED. EVERY FOUR YEARS THE ISSUANCE RATE IS CUT IN HALF. IN THE LONG RUN THERE WILL BE 21,000,000 BITCOINS, AND NEVER ANY MORE.</p>
<p>SO, ALL THINGS BEING EQUAL, HOW WOULD YOU PREFER TO STORE YOUR WEALTH: AS A FIXED FRACTION OF A FIXED SUPPLY, OR AS A DWINDLING FRACTION OF AN EVER-INCREASING AND DIFFICULT TO AUDIT SUPPLY?</p>
<p>WHAT'S WORTH MORE: A RARE BEANIE BABY OR A NON-RARE BEANIE BABY? YOU DON'T EVEN NEED TO LOOK IT UP ON EBAY, THE ANSWER IS INTUITIVE. HUMANS VALUE SCARCITY.</p>
<p>SEE, GOVERNMENT-RUN CURRENCIES (AND BEANIE BABIES) SERVE A DUAL PURPOSE. YOU USE THEM TO STORE VALUE. GOVERNMENTS AND BANKS (AND TY INC.) USE THEM TO RAISE REVENUE THROUGH DEBASEMENT AND SEIGNIORAGE. THESE PURPOSES ARE AT ODDS! FOR A CENTRALLY CONTROLLED ASSET, THE TEMPTATION TO INFLATE IS TOO STRONG TO BE RESISTED!</p>
<p>BECAUSE WE'VE GROWN UP IN A COUNTRY WITH A FROG-BOILINGLY-STEADY RATE OF INFLATION (WITH THE OCCASIONAL TERRIFYING BLIP OF SERIOUS INFLATION), WE'RE KNOWLEDGEABLE IN WAYS TO MITIGATE THE PAIN OF HAVING OUR HARD-WON WEALTH SIPHONED AWAY. BUY STOCKS. BUY HOUSES. IF YOU'RE REALLY RICH, BUY ART. THESE ITEMS GAIN WHAT'S CALLED A &quot;MONETARY PREMIUM,&quot; AS IN THEY COST MORE THAN THEY MIGHT OTHERWISE, DUE TO THEIR DUAL USE: PART PRACTICAL ASSET (STOCKS ARE SUPPOSED TO GIVE DIVIDENDS, HOUSES ARE FOR LIVING IN) AND PART MONEY (SALEABLE, VALUE-HOLDING).</p>
<p>BUT HOUSES ARE HARDER TO SELL THAN MONEY (LESS LIQUID). THE STOCK MARKET IS DOMINATED BY PROFESSIONAL INVESTORS WHO KNOW MORE THAN YOU DO, AND BIG PLAYERS WHO GET NEW MONEY FOR CHEAPER THAN YOU DO (UNLEVEL PLAYING FIELD). PUTTING A $10 MILLION PAINTING IN A VAULT SEEMS LIKE IT'S MISSING THE POINT SOMEHOW, AND PAYING $10 MILLION FOR A PAINTING YOU HATE, JUST BECAUSE IT MIGHT STORE VALUE, SEEMS EVEN SADDER.</p>
<p>INVESTING IS A USE FOR MONEY, BUT IT'S DIFFERENT THAN MONEY. IDEALLY MONEY WOULD HOLD ITS VALUE THROUGH TIME WHILE YOU WAIT FOR AN OPPORTUNITY TO USE IT WELL, RATHER THAN SLIPPING THROUGH YOUR FINGERS AS YOU HOLD IT, FORCING YOU INTO SUB-OPTIMAL INVESTMENTS.</p>
<p>ONCE YOU START TO REALIZE HOW ARBITRARY, INFLATIONARY, AND WEAPONIZED THE US DOLLAR IS, A LOT OF THE PUZZLING PARTS OF THE ECONOMY START TO MAKE SENSE: WHY ARE ALL THESE PEOPLE MAKING MILLIONS ON WALL STREET FOR THE SEEMINGLY NON-PRODUCTIVE TASK OF MAKING WEIRD ABSTRACTIONS OUT OF MONEY, DEBT, AND RISK? WHY DO WE HAVE BOOMS AND BUSTS? WHY DON'T RETAIL BANKS PAY ME INTEREST ON MY SAVINGS ANYMORE? WHY IS TRUMP TWEETING ABOUT NEGATIVE INTEREST RATES? WHY IS MODERN MONETARY THEORY SO HOT RIGHT NOW? WHY DO TVS GET BETTER, BIGGER, AND CHEAPER EVERY YEAR, WHILE EDUCATION AND HEALTH CARE SKYROCKET IN COST?</p>
<p>A BETTER MONEY FIXES THIS. BITCOIN FIXES THIS.</p>
<h1>BUT WILL IT WORK?</h1>
<p>AND SO PERHAPS LET'S SAY YOU COULD BE CONVINCED THAT A BETTER FORM OF MONEY IS CONCEIVABLE. BUT PRACTICAL? THAT'S PIE-IN-THE-SKY THINKING, YES?</p>
<p>WELL, I WANT YOU TO TAKE YOURSELF BACK IN TIME THREE YEARS. IMAGINE IF YOU HAD BEEN CONVINCED THEN THAT BITCOIN IS MONEY AND YOU SAID, &quot;ALRIGHT, I'LL GIVE IT A SHOT.&quot; <a href="HTTPS://DCABTC.COM">EACH WEEK YOU BOUGHT $100 OF BITCOIN, NO MATTER WHAT THE PRICE WAS, AND YOU NEVER SOLD</a>. AFTER INVESTING $15,700 IN THREE YEARS, THAT BITCOIN WOULD NOW BE WORTH $51,477 IF YOU WANTED TO EXIT BACK INTO DOLLARS. HOW MANY STOCKS DO YOU KNOW OF THAT COULD OUTPERFORM THOSE RETURNS?</p>
<p>PAST PERFORMANCE IS NO INDICATION OF FUTURE SUCCESS. BITCOIN HAS BEEN MAKING INVESTORS FABULOUSLY WEALTHY FOR TEN YEARS RUNNING, BUT IT COULD BE JUST ONE GIANT BUBBLE, OR A TRULY EXCELLENT PONZI SCHEME.</p>
<p>OR IT COULD BE WHAT I THINK IT IS: A BETTER MONEY. A MONEY THAT STORES VALUE, WITH NO LONG MILKSHAKE STRAW AVAILABLE TO BANKS AND GOVERNMENT TO SIPHON THAT VALUE AWAY. AND A BETTER MONEY IN ALL OTHER REGARDS AS WELL. THE PEOPLE THAT BELIEVE THAT ARE BUYING BITCOIN. NOT JUST AS AN INVESTMENT, BUT AS A TRANSITION TO A NEW SYSTEM. THE TRUE &quot;HODLERS&quot; AREN'T PLANNING ON COMING BACK.</p>
<p>I UNDERSTAND THIS IS A WILD AND IMPROBABLE CLAIM. IT REQUIRES SOME SERIOUS EVIDENCE TO BACK IT UP.</p>
<p>AND THIS, I WOULD ARGUE, IS WHY BITCOIN IS SUCH A RABBIT HOLE FOR SOMEONE LIKE ME. MY FIRST REACTION IS: IT WOULD BE COOL IF IT COULD WORK, BUT IT WON'T. THEN, A FEW YEARS LATER: WOAH, THAT BITCOIN THING IS STILL AROUND? WHY? HOW?</p>
<p><em>WHY? HOW?</em> ARE VERY DEEP QUESTIONS.</p>
<p>MOST PEOPLE DON'T KNOW WHY OR HOW THEIR FIAT CURRENCY WORKS. IT JUST WORKS UNTIL IT DOESN'T. MANY PEOPLE ARE CONFUSED AND DISHEARTENED TO LEARN ABOUT FRACTIONAL RESERVE BANKING. OR THE FACT THAT THE US DOLLAR ISN'T BACKED BY GOLD IN FORT KNOX. YOU'VE PROBABLY HEARD THE TERM &quot;QUANTITATIVE EASING,&quot; BUT HAVE YOU LOOKED UP WHAT IT MEANS? WHO DO YOU THINK GETS RICH OFF OF THAT SORT OF SCAM?</p>
<p>IN CONTRAST, EVERYTHING I LEARN ABOUT BITCOIN'S FUNDAMENTALS IS <em>HEARTENING</em>. AND IT MAKES ME WANT TO LEARN MORE.</p>
<h1>WHAT BITCOIN IS</h1>
<p>BITCOIN IS A DIGITAL CURRENCY. ITS FUNDAMENTAL TECHNICAL BREAKTHROUGH IS SOLVING &quot;DIGITAL SCARCITY&quot; THROUGH AN ALGORITHM CALLED &quot;PROOF OF WORK.&quot;</p>
<p>BASICALLY, BITCOIN IS ONE BIG SHARED LEDGER. IT'S EASY TO ADD NEW TRANSACTIONS, BUT IT'S NEARLY IMPOSSIBLE TO EDIT OLD ONES.</p>
<p>NODES ON THE BITCOIN NETWORK ACCEPT VALID TRANSACTIONS AND REJECT INVALID ONES. VALID TRANSACTIONS ARE PUT INTO A &quot;BLOCK&quot; WHICH IS &quot;HASHED&quot; BY MINERS. WHEN A MINER FINDS A HASH UNDER A CERTAIN NUMBER (AKIN TO ROLLING A HUGE SET OF DICE A FEW TRILLION TIMES UNTIL THEY COME UP ALL ONES) THEN THAT BLOCK OF TRANSACTIONS IS ADDED TO THE &quot;BLOCKCHAIN&quot; AND IS PROPAGATED TO THE WHOLE NETWORK. THE MINER IS REWARDED FOR HIS EFFORT WITH A &quot;BLOCK REWARD&quot; (SOME QUANTITY OF NEW BITCOIN ISSUANCE) AND ANY TRANSACTION FEES (WHICH ARE THE MINER'S INCENTIVE FOR INCLUDING ANY SPECIFIC TRANSACTION IN THE BLOCK).</p>
<p>THE &quot;DIFFICULTY&quot; (HOW IMPROBABLE OF A NUMBER THE MINER NEEDS TO FIND) IS DYNAMICALLY ADJUSTED TO MAKE SURE A NEW BLOCK IS FOUND, ON AVERAGE, EVERY TEN MINUTES.</p>
<p>EVERY FOUR YEARS THE SIZE OF THE MINER'S BLOCK REWARD GETS CUT IN HALF. RIGHT NOW IT'S 12.5 BTC. <a href="HTTPS://WWW.BITCOINCLOCK.COM/">IN MAY OF NEXT YEAR</a> WE'RE HAVING ANOTHER &quot;HALVING,&quot; AND MINERS WILL ONLY RECEIVE 6.25 BTC PER BLOCK THEY DISCOVER. DESPITE THIS UNSTOPPABLE DOWNWARD TREND FOR THE BLOCK REWARD (IN BTC TERMS), THE &quot;HASHRATE&quot; (THE AMOUNT OF COMPUTING POWER BEING ACTIVELY APPLIED TO MINING BITCOIN) <a href="HTTPS://BITINFOCHARTS.COM/COMPARISON/BITCOIN-HASHRATE.HTML">IS CLIMBING RAPIDLY</a>.</p>
<p>SINCE THIS NETWORK IS COMPLETELY DECENTRALIZED AND PERMISSIONLESS, THE &quot;TRUE STATE&quot; OF THE BITCOIN NETWORK — WHO HAS HOW MUCH BITCOIN — IS WHICHEVER BLOCKCHAIN IS THE &quot;TALLEST,&quot; WHICH MEANS WHICHEVER CHAIN HAS THE MOST BLOCKS IN IT, AND HENCE WHICHEVER CHAIN TOOK THE MOST &quot;WORK&quot; TO CREATE.</p>
<p>TO ATTACK THE BITCOIN NETWORK WITH FRAUDULENT TRANSACTIONS YOU WOULD NEED, AT A MINIMUM, TO HAVE MORE THAN HALF THE &quot;HASHING POWER&quot; OF THE BITCOIN NETWORK UNDER YOUR CONTROL. THIS IS VERY DIFFERENT THAN TYPICAL CYBER SECURITY. EACH INDIVIDUAL MEMBER OF THE BITCOIN NETWORK CAN BE HACKED (WHICH IS JUST LIKE TYPICAL CYBER SECURITY), BUT BECAUSE THE BITCOIN NETWORK HAS NO CENTRAL POINT OF FAILURE, THERE IS NO KNOWN WAY TO ATTACK THE NETWORK AS A WHOLE OUTSIDE OF BRUTE FORCE HASH POWER — WHICH, AT THE CURRENT LEVELS OF HASHING, WOULD REQUIRE A SIGNIFICANT AMOUNT OF RESOURCES AND EFFORT ON THE PART OF A MAJOR NATION STATE TO PULL OFF.</p>
<h1>THANKS FOR THE NERD RANT, NERD!</h1>
<p>LOOK, I KNOW I JUST THREW A TON OF TECHNICAL TERMS AT YOU. AND, I'LL BE TOTALLY HONEST RIGHT NOW: I DON'T KNOW HOW THE US DOLLAR SYSTEM REALLY WORKS IN COUNTERPOINT. AS FAR AS I KNOW, IT'S A FEW PEOPLE IN A ROOM WHO DECIDE INTEREST RATES AND OCCASIONAL QUANTITATIVE EASING, AND THEN BANKS HAND OUT THE DOLLARS THROUGH FRACTIONAL RESERVE LENDING AND... YEAH, I REALLY DON'T GET IT.</p>
<p>BUT I <em>GET</em> BITCOIN. I DARE YOU TO ASK ME ABOUT IT. IT'S A COMPLICATED SYSTEM WITH SEVERAL NOVEL-SOUNDING PIECES. BUT THE SYSTEM IS KNOWABLE, IT'S WELL DEFINED, AND IT WORKS.</p>
<p>WITH BITCOIN, POSSESSION MEANS OWNING THE CRYPTOGRAPHIC KEY (A LONG PASSWORD) TO A BITCOIN ADDRESS (A STRING OF LETTERS AND NUMBERS). IF YOU HAVE THE PASSWORD, YOU CAN SEND BITCOIN TO ANOTHER ADDRESS. IF YOU DON'T, YOU CAN'T. THAT'S ALL YOU REALLY NEED TO KNOW TO ACTUALLY USE BITCOIN. THERE'S NO BANK TO PUT A STOP ON YOUR ACCOUNT WHENEVER IT FEELS LIKE IT. THERE'S NO GOVERNMENT TO INFLATE THE CURRENCY OR LIMIT YOU WITH CAPITAL CONTROLS.</p>
<p>AND THERE ARE NO BACKSIES IF YOU SCREW UP.</p>
<p>THE TRADEOFF WITH BITCOIN IS THAT IT REQUIRES TAKING MORE RESPONSIBILITY FOR THE CUSTODY OF YOUR MONEY. THERE'S NO FDIC OUT HERE IN THIS WILD WEST.</p>
<p>IT ALSO MEANS TAKING RESPONSIBILITY FOR THE MONETARY POLICY. THE ISSUANCE RATE, THE 21 MILLION LONGTERM FIXED SUPPLY, AND THE VALIDITY OF EVERY SINGLE TRANSACTION, ARE VALIDATED BY NETWORK PARTICIPANTS RUNNING &quot;FULL NODES.&quot; IT'S A SELF-SELECTED FEDERAL RESERVE IN A WEIRD WAY. AND THE MORE PEOPLE WHO JOIN, THE MORE OSSIFIED THE FUNDAMENTAL RULES OF THE NETWORK BECOME.</p>
<p>IN SOME WAYS THIS IS MORE STRAIGHTFORWARD THAN STORING YOUR MONEY IN A BANK, WITH ALL THEIR ARCANE RULES, RANDOM FEES, AND ARBITRARY RIGHTS OVER YOUR MONEY. BUT I CAN'T ARGUE THAT IT'S <em>EASIER</em>.</p>
<p>PLUS, BITCOIN'S 10 YEAR TRACK RECORD IS IMPRESSIVE FOR A PROJECT IN THE DIGITAL AGE, BUT ISN'T QUITE ON THE SCALE OF SOMETHING LIKE THE US DOLLAR OR GOLD.</p>
<p>AND SO I CAN UNDERSTAND WHY SOMEONE WHO IS DOING WELL INSIDE THE CURRENT SYSTEM WOULD HAVE VERY LITTLE IMPETUS TO DIVERSIFY TO BITCOIN.</p>
<p>BUT IF YOU'RE WORRIED ABOUT THE STABILITY OR PRACTICALITY OF THE CURRENT SYSTEM, I THINK BITCOIN IS AN EXCELLENT HEDGE. OR, FOR SOME OF US, A BEAUTIFUL EXIT STRATEGY. AND FULLY WORTH THE HASSLE.</p>
<h1>THE ETHICS OF HOARDING</h1>
<blockquote>
<p>JESUS SAID TO HIM, “IF YOU WOULD BE PERFECT, GO, SELL WHAT YOU POSSESS AND GIVE TO THE POOR, AND YOU WILL HAVE TREASURE IN HEAVEN; AND COME, FOLLOW ME.”</p>
<p><em>MATTHEW 19:21</em></p>
</blockquote>
<p>LET'S IMAGINE AGAIN, FOR A MOMENT, THAT YOU AGREED WITH ME. THE US DOLLAR IS BAD MONEY, OR AT LEAST HAS SOME MAJOR FLAWS, AND BITCOIN IS A BETTER MONEY, AT LEAST IN THE LONG RUN.</p>
<p>BUT WHY SHOULD I BE THIS FOCUSED ON MONEY IN THE FIRST PLACE? AS IT SAYS IN 1ST TIMOTHY: &quot;THE LOVE OF MONEY IS THE ROOT OF ALL KINDS OF EVIL.&quot;</p>
<p>OR, HERE'S ANOTHER CLASSIC FROM JESUS HIMSELF:</p>
<blockquote>
<p>&quot;WHY PUT ME TO THE TEST, YOU HYPOCRITES? SHOW ME THE COIN FOR THE TAX.&quot; AND THEY BROUGHT HIM A DENARIUS. AND JESUS SAID TO THEM, &quot;WHOSE LIKENESS AND INSCRIPTION IS THIS?&quot; THEY SAID, &quot;CAESAR’S.&quot; THEN HE SAID TO THEM, &quot;THEREFORE RENDER TO CAESAR THE THINGS THAT ARE CAESAR'S, AND TO GOD THE THINGS THAT ARE GOD’S.&quot;</p>
<p><em>MATTHEW 22:18-21</em></p>
</blockquote>
<p>THERE'S NO PORTRAIT ON BITCOIN, SO WHO SHOULD WE RENDER IT TO ANYWAY? JUST LIKE HOW THE US CONSTITUTION MADE THE &quot;WE THE PEOPLE&quot; SOVEREIGN, NOT THE LEADERS, THE SOVEREIGNS IN BITCOIN ARE THE NETWORK PARTICIPANTS, NOT ABRAHAM LINCOLN.</p>
<p>LET'S BREAK DOWN THE BASIC USES FOR MONEY AND SEE WHAT BITCOIN'S ETHICAL IMPLICATIONS ARE.</p>
<h2>1. BUYING STUFF WE NEED</h2>
<p>A BETTER MONEY WOULD BE BETTER FOR BUYING STUFF WE NEED, BECAUSE IT WOULD HOLD ITS VALUE UP THROUGH THE EXACT MOMENT SPENDING IS REQUIRED. AN INFLATIONARY, DEBT-BASED MONEY, IN CONTRAST, ENCOURAGES SPENDING AS QUICKLY AS POSSIBLE.</p>
<h2>2. BUYING STUFF WE WANT</h2>
<p>A DEFLATIONARY CURRENCY LIKE BITCOIN DISCOURAGES CONSUMERISM, BECAUSE YOUR MONEY IS ALMOST ALWAYS WORTH MORE TOMORROW THAN IT IS TODAY. ASK ANY LONG TERM BITCOINER HOW THEIR PURCHASING HABITS HAVE CHANGED OVER TIME. IT'S A REMARKABLE SHIFT IN MINDSET!</p>
<h2>3. INVESTING</h2>
<p>A HARD MONEY BENEFITS INVESTMENT (AT LEAST FROM A SUBJECTIVE POINT OF VIEW) BECAUSE WITH A HARD MONEY, INVESTMENT ISN'T A MANDATORY ACTIVITY. THIS IMPROVES THE SIGNAL TO NOISE RATIO. YOU CAN INVEST IN INNOVATION AND TRULY IMPORTANT BUSINESSES AND PROJECTS, BUT YOU DON'T NEED TO PLAY THE STOCK MARKET AND INVEST IN RANDOM MEGACORPS JUST TO STAY AFLOAT.</p>
<h2>4. GIVING</h2>
<p>THIS IS WHERE IT GETS INTERESTING!</p>
<p>IT'S HARDER TO GIVE YOUR BITCOIN AWAY THAN IT IS TO GIVE AWAY FIAT. AS IN, YOU AREN'T GOING TO WANT TO DO IT. WHEN YOU GIVE AWAY A BITCOIN YOU MIGHT THINK TO YOURSELF: &quot;THAT COULD BE WORTH A FORTUNE SOMEDAY.&quot; WHEN YOU GIVE AWAY FIAT, YOU CAN MAYBE THINK: &quot;I'M NOT USING IT, AND IT WILL BE WORTHLESS IN A DECADE OR TWO!&quot; BITCOIN CREATES THE OPPOSITE SENSATION OF &quot;IT'S BURNING A HOLE IN MY POCKET.&quot; BITCOIN REPAIRS POCKET HOLES.</p>
<p>WHAT A GOOD, &quot;HARD,&quot; MONEY LIKE BITCOIN TEACHES YOU IS THAT <a href="HTTPS://TWITTER.COM/PIERRE_ROCHARD/STATUS/1062510947510697984">HOARDING MONEY <em>IS</em> USING IT</a>.</p>
<p>ONE WAY TO THINK ABOUT HOARDING IS IT'S GIVING EVERYONE ELSE A CHANCE TO SPEND. YOU'RE CREATING SCARCITY BY WITHOLDING YOUR SPENDING, WHICH IMPROVES THE PURCHASING POWER OF ANYONE WHO NEEDS TO SPEND RIGHT THIS SECOND.</p>
<p>IMAGINE YOU'RE SHOPPING FOR A HOUSE. AND ALSO JEFF BEZOS IS SHOPPING FOR A HOUSE IN THE SAME NEIGHBORHOOD SIMULTANEOUSLY. WILL IT BE EASIER FOR YOU TO AFFORD A HOUSE, OR HARDER? JEFF BEZOS COULD HELP ME WITH HIS MONEY BY INVESTING IN MY BUSINESS, BUT HIM SPENDING IN THE SAME MARKET THAT I'M SPENDING ACTIVELY HURTS MY PURCHASING POWER.</p>
<p>OKAY, BACK TO JESUS. DID JESUS ASK THE RICH YOUNG GUY TO SELL EVERYTHING HE HAD AND GIVE THE MONEY TO THE POOR BECAUSE OF RAMPANT INFLATION? OR THE AVAILABLE TAX DEDUCTION? OR AS AN ECONOMIC STIMULUS PLAN? I DON'T BELIEVE SO. I BELIEVE HE ASKED IT OF THIS MAN BECAUSE HE KNEW IT WOULD BE THE HARDEST THING FOR HIM TO DO AND WAS TRYING TO PROVE A POINT.</p>
<p>BITCOIN, LIKE ANY GOOD MONEY, IS DIFFICULT TO GIVE AWAY. I DON'T THINK THAT'S AN INDICTMENT ON BITCOIN, I THINK THAT'S AN INDICTMENT ON US.</p>
<h1>WHAT MONEY ACTUALLY IS</h1>
<p>HUMANS LONG FOR SAFETY. WE WOULDN'T NEED MONEY IF WE KNEW, FOR A CERTAINTY, THAT OUR EVERY NEED AND DESIRE, AND THE NEEDS AND DESIRES OF THE PEOPLE WE CARE ABOUT, WOULD BE SUPPLIED IN PERPETUITY. WEALTH IS A HEDGE AGAINST UNCERTAINTY, AND MONEY, BEING THE MOST SALEABLE GOOD, IS THE MOST CONVENIENT FORM TO HOLD WEALTH IN.</p>
<p>WHICH IS WHY WEALTH IS SO DANGEROUS: WE CAN BEGIN TO BELIEVE THAT WE HAVE TRUE CONTROL OVER OUR LIVES, OR AT LEAST BECOME OBSESSED WITH CHASING THAT CONTROL.</p>
<p>BITCOIN REMOVES SOME OF MONEY'S UNCERTAINTIES. MOSTLY DUE TO THE FACT THAT IT'S NEITHER A TRADITIONAL PHYSICAL GOOD LIKE GOLD, OR SUBJECT TO THE DAY-TO-DAY ARBITRARY JUDGEMENT CALLS OF THE FEDERAL RESERVE. BITCOIN DOESN'T RUST OR DISSOLVE OVER TIME. IT'S EASY TO TRANSPORT. IT'S HARDER TO STEAL. IT IMPOSSIBLE TO INFLATE. IT'S REALLY JUST MATH, NUMBERS, AND ENERGY AT THE END OF THE DAY, AND THERE'S SOMETHING REALLY BEAUTIFUL ABOUT THAT.</p>
<p>I THINK IT'S BETTER AT MONEY THINGS THAN ANY MONEY WE'VE EVER HAD ON THIS PLANET.</p>
<p>BUT IT'S STILL JUST MONEY.</p>
<p>I THINK IT'S POSSIBLE TO LOVE <em>A</em> MONEY WITHOUT NECESSARILY LOVING MONEY.</p>
<p>MAYBE I'M JUST MINCING WORDS.</p>
<p>ANYWAYS, THIS IS GETTING LONG, AND I PROMISED IT WOULD ONLY TAKE A FEW MINUTES OF YOUR TIME.</p>
<p><a href="HTTPS://NAKAMOTOINSTITUTE.ORG/">BUY BITCOIN</a>!</p>
]]>
      </description>
    </item>
    <item>
      <title>
        Three projects is one less than four
      </title>
      <link>https://pauljmiller.com/posts/three-projects-in-may-actually.html</link>
      <pubDate>Wed, 26 Jun 2019 12:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/three-projects-in-may-actually.html</guid>
      <description>
        <![CDATA[<p>Last month <a href="https://pauljmiller.com/posts/four-projects-in-may.html">I created a plan for myself</a>: instead of just tinkering with various projects, I would bring four projects to a point of portfolio-worthiness. One project a week.</p>
<p>The result? I did three of them! And, also, did other things as well. Here's what went right, and what went wrong.</p>
<h3>Code on tape</h3>
<p>The moral of this story is: write your own components if you can. I've always approached programming as &quot;the idiot in the room.&quot; That is, I assume everyone else's GitHub code is so much better than mine that I'd be a <em>fool</em> to try and write my own implementation.</p>
<p>But, in this case, it turned out way more efficacious — and, more importantly, more educational — to write my own component for wrapping the <a href="https://github.com/Microsoft/monaco-editor">Monaco Editor</a>. And a hook to <a href="https://codesandbox.io/s/81zkxw8qnl">record audio</a>. I still got stuck a lot, and still copied a lot of code from GitHub. Also, that hook <a href="https://twitter.com/dan_abramov/status/1126264624326823942">ended up being fixed by React's own Dan Abramov</a>, which feels a bit like cheating, but...</p>
<p>The moral is still the same! Writing, or at least attempting to write, my own components instead of instantly reaching for whatever's hot on npm lead me to much better understanding of what I was doing, and therefore more steady progress instead of eternal stuckness.</p>
<p>Unfortunately, while I got Code on tape to a working state, I didn't get it to an easily shareable state. Maybe I'll do that someday! This knocks my number of &quot;finished&quot; projects down to three, but of course &quot;finished&quot; is a very subjective thing.</p>
<p>Oh, one more sidenote: I did state management in Overmind because it seemed to offer similar advantages to Redux but with much less boilerplate. I think that proved to be true!</p>
<p>(Github: <a href="https://github.com/futurepaul/code-on-tape/tree/overmind">Code on tape</a>)</p>
<h3>Calculator 2</h3>
<p>This was easily my favorite project to build. Like with Code on tape, I had built a version of it before in React, but decided to rewrite it in Svelte 3 this time. And, because Svelte was such a breeze to work with, I ended up with more time to achieve two nice-to-haves:</p>
<ol>
<li>
<p>Using Rust to do math. My earlier versions of Calculator 2 had used some random Javascript library to evaluate the math expressions. But now I'm using <a href="https://crates.io/crates/rsc">RSC, a Rust crate</a>, for which I created a simple WASM wrapper. It works, it feels fast and &quot;solid,&quot; if that's worth anything. And, also: it works!</p>
</li>
<li>
<p>Because of Svelte and WASM, I was already dabbling in Webpack, which led me to make the boldest move of all: I wrote my own Webpack loader to turn mathematical notation into SVG. Earlier versions of Calculator 2 had used the excellent MathJax at runtime to accomplish the same thing. But, thanks to my Webpack loader I'm able to run MathJax at compile-time, saving gobs of Javascript at load-time and making everything just feel better.</p>
</li>
</ol>
<p>(Github: <a href="https://github.com/futurepaul/calculator-2">Calculator 2 on Github</a>)</p>
<h3>Fragment Notes</h3>
<p>Again I switched to Svelte 3 for the frontend, instead of the weird non-React view library I had been using. I also rearranged the project into three pieces: the pure Rust library (that does the full-text search, mostly a ripgrep wrapper), the native module library (that wraps the Rust library with <a href="https://neon-bindings.com/">Neon Bindings</a> to make it work on Node), and the Electron app. This worked very well.</p>
<p>Except.</p>
<p>There's something I just don't really understand about how Node compiles native modules. When I try to compile a &quot;release&quot; version of my app to run as a binary, it ends up gigabytes big and insanely slow. But when I run <code>npm run start</code> from my project folder it works fine! And I find the build process so difficult, obtuse, and random, that I have zero motivation right now to track down a solution.</p>
<p>So Fragment Notes is now a working product that I use for my own notes-searching purposes. But I don't know how to package and share it, unfortunately.</p>
<p>(Github: <a href="https://github.com/futurepaul/fragment">Fragment Notes</a>)</p>
<h3>My Own Personal Blog</h3>
<p>Instead of totally revamping the My Own Personal Blog project to be the static site generator for normies, I merely added the functionality necessary to <a href="https://pauljmiller.com/projects.html">add the projects page</a>. So, in a way, this is still undone. That said, I really love using my own static site generator, and am always glad I chose to roll my own instead of attempting sticking with Hugo.</p>
<p>(Github: <a href="https://github.com/futurepaul/my-own-personal-blog/tree/genericify">My Own Personal Blog</a>)</p>
<h3>svg-to-piet</h3>
<p>Woah, what's this? This wasn't in the original plan!</p>
<p>That's right, during this month of working seriously on my own projects I also got extremely involved in the Piet / Druid community. My biggest work in this regard was a collab with <a href="https://github.com/cbrewster">Connor Brewster</a> to build a <a href="https://github.com/futurepaul/piet/tree/master/piet-raqote">Piet backend with Raqote</a>. That is to say, Piet is a API for 2D graphics, Raqote does the grunt work of laying down pixels, and what we wrote was the adapter between them.</p>
<p>While piet-raqote is mostly an educational project, what I'm really excited about is <a href="https://github.com/xi-editor/druid">Druid</a>, which is a GUI framework built on Piet. With Druid I can make real, native apps using Rust — for instance, once Druid has the necessary functionality, I will be re-writing Fragment in Druid. Sorry, Electron, but you know this day would come eventually!</p>
<p>To help with some Druid development I was doing, I made svg-to-piet, which is a simple utility to convert an SVG into Piet draw calls.</p>
<p>If I had to pick a programming job out of a hat, I hope it would be a job that involved more or less straightforward data transformation of the kind that svg-to-piet turned out to be.</p>
<p>It wouldn't, however, involve writing Rust macros, which was the actual hard part of svg-to-piet.</p>
<p>(Github: <a href="https://github.com/futurepaul/svg-to-piet">svg-to-piet</a>)</p>
<h3>What's next?</h3>
<p>I can't decide, tbh. This month was a great idea. I ended up with a portfolio I'm proud to share, and I learned a lot in each individual project. But I don't have another four projects of a similar character sitting on my back burner. I have a bunch of vague ideas that require education and exploration, which is a much more meandering process.</p>
<p>If you'd like to help me pick my next project, <a href="mailto:paul@pauljmiller.com">perhaps consider hiring me</a>!</p>
]]>
      </description>
    </item>
    <item>
      <title>
        How to fix the internet
      </title>
      <link>https://pauljmiller.com/posts/how-to-fix-the-internet.html</link>
      <pubDate>Thu, 20 Jun 2019 00:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/how-to-fix-the-internet.html</guid>
      <description>
        <![CDATA[<p>Here's my idea in a nutshell: make it more like WordPress. Take any popular service you use from The Big Bad Tech Boys and make it more like WordPress.</p>
<p>I'm giving you the least glamorous version of my idea up front to build trust. Is it working? Please don't leave. I understand that very few people love WordPress, especially not the people who work with it on a regular basis. WordPress is slow, old, bloated, complicated, and historically insecure.</p>
<p>Also, WordPress powers roughly 30 percent of the top 10 million websites. So not only is my idea bad, it's also the status quo.</p>
<p>But!</p>
<p>What if stuff was more like WordPress?</p>
<p>Let's say I want to start a new YouTube channel. But instead of starting it on YouTube, I start it à la WordPress.</p>
<ol>
<li>I buy a domain name, or <a href="https://elephantnames.com">use one I already own</a>.</li>
<li>I set up hosting and connect it to my domain.</li>
<li>I install a YouTube-like CMS on my server (instead of WordPress).</li>
<li>I add videos, information, and design tweaks to the channel.</li>
<li>Nobody ever discovers my videos because they're not on YouTube.</li>
</ol>
<p>Okay, so step five sounds disheartening. But we could solve this the way podcasts solved it: apps!</p>
<p>See, podcasts are like WordPress blogs. In fact, many podcasts that are hosted DIY, instead of through a platform like SoundCloud or Anchor, publish via WordPress.</p>
<p>A podcast is just:</p>
<ol>
<li>An RSS feed.</li>
<li>A set of MP3s.</li>
</ol>
<p>It turns out, it's really straightforward to write an app that can subscribe to RSS feeds and play MP3 files. Hence the proliferation of podcast-listening apps.</p>
<p>So if our WordPress-like YouTube replacement was just:</p>
<ol>
<li>An RSS feed.</li>
<li>A set of videos.</li>
</ol>
<p>We'd be doing pretty well, yes?</p>
<p>This is where we get to the inevitable: &quot;That sounds like an obvious idea. If it were also a <em>good</em> idea, it would've already been done. Therefore it must not be good.&quot;</p>
<p>Maybe.</p>
<p>Or perhaps we haven't had the incentive to self-publish our own video channels before now. YouTube was a good enough. The upsides, like discoverability and monetization, far outweighed the downsides: not owning your own distribution, a capricious algorithm, Google's discretion as to what's appropriate.</p>
<p>Hosting the videos is expensive, especially if we want anything close to the low latency and high quality of YouTube. And there's very little incentive to build a high quality app for these video channels because they don't exist (a classic chicken / egg scenario).</p>
<p>Also, for some reason, Google is the only company on earth with the budget to create a really good video player for the web.</p>
<h3>Fast-forward to the year 2025</h3>
<p>There are many well-established content types. Just like .txt / .doc / .png, except for things like .tweet, .podcast, .video, .blog.</p>
<p>When I want to publish some content, let's say a video, I use my favorite app to package it into a standard .video file. That file is basically just the real video file, plus any metadata the .video format requires, such as title, description, etc.</p>
<p>I publish &quot;paul-minecraft-lets-play-episode-4190.video&quot; to my home server. My home server is just a black box in my closet that's plugged into power and ethernet.</p>
<p>My home server updates a list of .video files with the hash of my latest .video file and serves this file (like an RSS feed, except in the year 2025 maybe we don't use XML anymore). If I'm a very popular video creator, my home server seeds the video to a bunch of CDNs that serve the bulk of traffic. If I'm very controversial (I always dig straight down), perhaps my videos are only torrented. Or if only my mom watches my Let's Plays, she can probably load the video directly from my home server without a problem.</p>
<p>A subscriber is notified of my upload on her phone, because in this fantastical future, if you subscribe and click the bell icon, notifications actually work. She opens her app of choice for consuming this content. It might be an app focused only on .video subscriptions, or an app that can handle many different content type feeds.</p>
<p>If she likes the video, she can click the &quot;fav&quot; button and leave a comment, just like in the year 2019. But her fav and her comment aren't published to my server, or to a central server like YouTube, they're published to her server. A .comment file, a .liked index.</p>
<p>Insofar as the videos and other content she enjoys are presented to her via algorithm, it's an algorithm she chose herself that runs on her own server against her own data.</p>
<p>Someone who follows her .video channel, or her .blog channel, might be more likely to see my video in the &quot;Other recommended channels&quot; list. Or not! It's up to her. My server is simply notified that she's published a comment, and I can publish a reference to her comment without hosting it myself.</p>
<h3>Some notes of clarification on what the future's like</h3>
<p>I think what we'll see very clearly in hindsight is that when we published our content on other people's servers, it always went bad. Instagram's algo made us sad. YouTube's algo made us mad. Twitter's algo mad us sad AND mad. Google Photos algo, it turned out, made us easily tracked and controlled by totalitarian governments. Oops!</p>
<p>Self-hosting will be the &quot;difficult&quot; and &quot;cumbersome&quot; option for a while, but by the year 2025 it will be easier than the centralized services are. Think about it: have you ever tried to upload a YouTube video? There are a ton of options, and the interface is kind of annoying, and it's a many-step process. This is because YouTube has to be designed to be a jack of all uploading trades, master of none. But when self-hosting is mature and common, you'll be able to pay for a highly specific app that streamlines the experience to match your exact needs. If you don't want to pay for a high-end app there will likely be a more general, harder-to-use, free and open source option as well.</p>
<p>And: any things that <em>are</em> difficult about self-hosting are directly related to self-determination. &quot;Nobody is obliged to host your shitty Let's Play. It's two gigabytes. You swear a lot, so we can't use it to sell soap. Four people watch it. And three of those people hit the thumbs down button.&quot; Correct.</p>
<p>What about popular, non-controversial content? Does this system work for that? &quot;Caching is a hard problem&quot; is something you might've heard. I don't think we'll have a perfectly decentralized internet by 2025 that can outpace high quality CDN services. But I do think we'll have new ways to pay CDNs for their service. A big company who wants its detergent ad seen by millions with a low buffer time might pay CDNs up front. But barely monetized user-created content might be mirrored by CDNs in exchange for some kind of per-use payment from viewers.</p>
<p>Standardizing on different content types is obviously a whole can of worms in itself. It does seem to be an improvement, however, on the current situation, where we have basically three main &quot;open&quot; content types for publishing:</p>
<ol>
<li>RSS (for blogs)</li>
<li>Apple's bastardized RSS (for podcasts)</li>
<li>WWW, which is possibly the most complicated spec of all time.</li>
</ol>
<p>I think WWW's ongoing role will be for discovering new content types, for interactive media, and for application distribution (maybe). But for well-established content types I think it adds way too much complication and bloat. If you think about it, most of what proprietary systems add to well-established content types is a way to consume them <em>without</em> the pain and suffering of WWW. Medium, Twitter, Google Photos, YouTube, etc. Of course, in all of these cases, can serve as a completely fine fallback when you don't have the appropriate app.</p>
<h3>How do we get there from here?</h3>
<p>If I knew exactly what the next step was, I'd be foolish to not be working on it. And yet look at me: blogging! I think, perhaps, creating easy-to-use self publishing systems (that put content on a creator's own Digital Ocean server, while we wait for the black box home server to arrive) is the right thing to do.</p>
<p>But do the content types need to exist first? Should I create a content type for &quot;.blog&quot; (probably Markdown with some TOML on top) and see if anybody likes using it? I tried to make a podcast generator entirely based on MP3 metadata but that was pretty difficult and probably not the right approach.</p>
<p>Should hosting be stateful, like a WordPress blog with a MySQL backend, or stateless, like a Hugo blog built with a static site generator? For plain text blogs, the static site generator works great, but if video files and images are involved we might want some sort of object storage?</p>
<p>Do the apps that consume this content need to truly know about the different content types? Could we do all of this by bastardizing RSS, like podcasts did?</p>
<p>Should I be looking into Activity Streams? Or is that just WWW being needlessly complicated again?</p>
<p>What we need:</p>
<ol>
<li>Tools to package content for distribution.</li>
<li>Services to self-publish that content with minimal effort.</li>
<li>Apps to subscribe to channels and enjoy the content.</li>
</ol>
<p>And, hopefully, all three steps will involve standard protocols and formats.</p>
<p>Then, once all of this works, we can build toward feature parity with existing services by closing the loop: the app you use to enjoy video channels can also publish comments to your home server, which are then somehow linked to by the video publisher's server. It gets dicey and unsolved-problem-ey!</p>
<p>All of this without monetizing via scam or raising money in such a way that incentivizes centralization. Most Web 3.0 efforts, sadly, fail this test. Maybe I should be taking <a href="https://solid.inrupt.com/how-it-works">Sir Tim Berners-Lee's Solid</a> more seriously, but it feels needlessly alien to me.</p>
<p>So, please hit me up on Twitter and let me know what you think, let me know if you want to help, and let me know if you have any hot tips.</p>
<p>I think a better internet is possible. It should be more like WordPress, I think. As long as it isn't literally WordPress. Because it should be more app-ish. Also, I'm not going to bother to learn PHP after all these years.</p>
]]>
      </description>
    </item>
    <item>
      <title>
        A Keyboard Placement Manifesto
      </title>
      <link>https://pauljmiller.com/posts/keyboard-in-the-front-club.html</link>
      <pubDate>Tue,  4 Jun 2019 00:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/keyboard-in-the-front-club.html</guid>
      <description>
        <![CDATA[<p>The Keyboard In The Front Club <a href="https://pauljmiller.com/manifesto.txt">manifesto.txt</a>, presented without modification outside of appropriate line breaks.</p>
<pre style="white-space: pre-wrap;">          A Keyboard Placement Manifesto

                 by Paul Miller

We have sweaty palms. And we did not ask for this. A &quot;laptop&quot; is for laps only if you have no more imagination than a dictionary. I want a portable computer. I want my palms to remain at an acceptable temperature. I want you to join me. Let's start the Keyboard In The Front Club.

For too long we have allowed laptop manufacturers to believe that we demand keyboards in the back, touchpads in the front. We have tricked them, or even ourselves, into believing that we are all rubber stamped consumers, pleading for rubber stamped laptops from our corporate overlords. Someone mistakenly thought that we are baby birds, mouths agape, waiting for mama bird to regurgitate last year's laptop design into us. Disgusting.

    I am not stamped from rubber.
      I am no baby.
        I want a keyboard in the front.
          Sometimes.

The Keyboard In The Front Club demands no loyalty. We seek no conformance. We only seek the liberty of non-conformance. Some &quot;laptops&quot; are aptly named. We lounge and type. We watch Netflix. We chill. There are no hard feelings here.

But a portable computer must often sacrifice loungability for other priorities. At-desk ergonomics. High-end performance. The cooling necessary to raise the performance ceiling. Sheer iconoclasm. And, most importantly: non-sweaty palms.

The Keyboard In The Front Club merely says to the many and varied laptop manufacturers: &quot;surprise us!&quot; And, &quot;do it a good one!&quot; We have no dogma. If the keyboard is split down the middle, or hovering in mid-air, or purely mental, is that not what we mean by &quot;keyboard in the front?&quot; Have we challenged convention today Then we are happy. Are our palms un-sweaty while our portable computers grant us teraflops? Then we are glad.

Please send me $20 if you want to join the club.

Thanks,
Paul 
</pre>]]>
      </description>
    </item>
    <item>
      <title>
        Four projects
      </title>
      <link>https://pauljmiller.com/posts/four-projects-in-may.html</link>
      <pubDate>Fri,  3 May 2019 00:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/four-projects-in-may.html</guid>
      <description>
        <![CDATA[<p>I want to get a programming job. So far I've taught myself programming, but I've always wanted to try programming collaboratively with other people in a job place. I think I'd grow a lot, and I think I could be involved in more ambitious projects that way.</p>
<p>To get a job, I need to have a portfolio so that when prospective employers skim my work they see evidence of some amount of desire and ability to program.</p>
<p>I also need to be good at algorithms to actually land many of the fancier programming jobs. But I can start practicing those again when I'm in the midst of applying for jobs. Right now, I think I need the portfolio to get a foot in the door.</p>
<p>I've picked four projects to do, because they're my favorite projects right now. I've thought about them a lot, started / stopped working on them in a million different languages and frameworks. But I haven't ever declared any of them &quot;good enough&quot; to share with the world. This month I will!</p>
<p>Here are the projects.</p>
<h3>Code on tape</h3>
<p>Everyone says it's good to read code in order to learn how to code. <a href="https://github.com/futurepaul/code-on-tape">Code On Tape</a> is a tool that makes it easy to record audio notes about a piece of code, in sync with highlights of the code you're talking about. Traditionally this has been done with screen recording, but I think there's an opportunity with audio and a minimal recording format to make smaller files for distribution (akin to podcasts) and a more mobile-friendly viewing experience.</p>
<h3>Calculator 2</h3>
<p>With most calculators, you provide the data and the algorithm. To get the area of a circle, you enter the radius (the data, in this example), you square it, and then you multiply that by pi. Most of what you just did was algorithm input. With <a href="https://github.com/futurepaul/calculator-2">Calculator 2</a>, you only provide the data and the app provides the algorithm. So now, instead of remembering algorithms, you just pick them from a list, insert your variables, and you're done. It's a &quot;declarative&quot; rather than an &quot;imperative&quot; calculator, if that makes sense.</p>
<h3>Fragment Notes</h3>
<p>My favorite application of all time, Notational Velocity, is dying. <a href="https://github.com/futurepaul/fragment">Fragment Notes</a> is designed to replace the key functions of Notational Velocity (searching, skimming, and creating notes), while punting on the text editing part. Like Notational Velocity, Fragment is filesystem-friendly. Which means backup is simple, syncing is simple, and you can use any regular text editor to open the files. Database lock-in is evil!</p>
<h3>My Own Personal Blog</h3>
<p>Static site generators are a solved problem, but by building my own I believe I can eventually create a user interface for a static site generator that can make this amazing tool available to more people. Right now, the main requirement for this project is that it can easily build my own personal site, hence the name: <a href="https://github.com/futurepaul/my-own-personal-blog">My Own Personal Blog</a>.</p>
]]>
      </description>
    </item>
    <item>
      <title>
        Want to end monopolies? Stop granting them
      </title>
      <link>https://pauljmiller.com/posts/patents-are-monopolies.html</link>
      <pubDate>Sat, 16 Mar 2019 00:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/patents-are-monopolies.html</guid>
      <description>
        <![CDATA[<p><em>I wrote this last year, whenever it was <em>The Verge</em> was doing that series on breaking up big tech. Now that <em>The Verge</em> is hanging out with politicians at southy south, <a href="https://www.theverge.com/2019/3/9/18257965/elizabeth-warren-break-up-apple-monopoly-antitrust">some of whom who are talking a big game</a>, I thought I'd share one of my arguments as to why breaking up big tech might be unnecessary.</em></p>
<p><em>Oh, and also, <a href="https://www.theverge.com/2019/3/12/18261894/microsoft-foxconn-law-suit-royalty-payments-interest">Microsoft is a gross patent troll</a>. That is all.</em></p>
<p>I don't know if it's lame to say this, but I hate antitrust law. I don’t appreciate how it's written, I don't applaud its various applications throughout history, and I find nothing redeemable in the current hubbub about Facebook, Google, and Amazon.</p>
<p>This company's too big! What do we do? We ruin it, so we can have more &quot;competition.&quot; Competition isn't a glorious prize in and of itself. I don't want to watch a football game where one of the quarterbacks has his arm stapled to his side just to make things &quot;fair.&quot; Companies that best serve the most customers tend to &quot;win,&quot; and when they win they often win <em>big</em> thanks to network effects, vertical integration, and economies of scale. And yes, they fend off and discourage and consume their competitors when they can.</p>
<p>In my view, antitrust proponents are Johnny-come-latelies, swinging the sword of government, hacking down winners for the temerity of staying on top. &quot;Now that society has accrued the modern-life-defining benefits of your company, we'd like to destroy you so your less-successful competitors enjoy the reward of the market you defined.&quot;</p>
<p>Anyways, I'm probably too emotional about all of this. It just feels like stealing, is all.</p>
<p>So let's talk about something else: patents.</p>
<p>Patents are a time-limited monopoly on an idea. But it's not a naturally occurring monopoly. In most walks of life, ideas are spread, mutated, and copied freely. The only way to have honest idea monopoly is to keep it a perfect secret, and even then <a href="https://en.wikipedia.org/wiki/Multiple_discovery">there's a good chance someone knows it</a>. Patents only work because governments grant and enforce them. And while I don't like the idea of governments breaking up monopolies, I like even less the idea of governments granting them.</p>
<p>Do you know who would be terrified if we got rid of patents?</p>
<p>Pharmaceutical companies, yes.</p>
<p>But do you know who else?</p>
<p>Facebook, Google, Amazon, and nearly every other technology company at the top of its heap.</p>
<p>For instance, Google's search dominance was built in part on a patented algorithm called PageRank. Google's exclusivity on PageRank expired in 2011, long after it had an unassailable monopoly in search.</p>
<p>Amazon, more infamously, patented one-click buying back in 1999 and sued Barnes &amp; Noble over the &quot;technology&quot; in 2000. This was such obvious bullshit that I'm surprised the patent office didn't shut down in shame then and there.</p>
<p>Facebook has a litany of patents, most notably a handful of patents originated by Friendster that cover the basics of social networking.</p>
<p>None of these companies, have rested on their past successes. From a cursory glance at FreshPatents.com: Facebook recently patented &quot;Commercial breaks for live videos,&quot; Google nabbed &quot;Mobile interstitial ads,&quot; and Amazon now owns &quot;Prioritization of items of delivery.&quot; The list of interesting, novel, and super dumb patents is endless.</p>
<p>To Facebook and Google's credit, both companies tend to use patents defensively more than offensively. Google, in its epic proxy patent war with Apple. Facebook, most recently, to retaliate against BlackBerry's patent suits.</p>
<p>But all sorts of companies, large and small, use patents to fend off competition and shore up power. Microsoft (ab)used its patent portfolio for years in attempts to destroy the open source &quot;cancer&quot; of Linux. Apple sues everyone all the time. IBM uses its ancient Prodigy patents to hassle companies like Priceline and Groupon.</p>
<p>Ma Bell, one of antitrust's most famous kills, got its start how? A patent on phones. Which, if we're being honest, is a pretty cool thing to have a patent for.</p>
<p>But you know what? Someone else invented the phone just around exactly the same time Alexander Graham Bell did. But Bell got the patent, and Bell got the profits. So anyone who's about to defend patents as an incentive for innovation: what if you're, like, super wrong about that?</p>
<p>My fear is that were a viable competitor to arise and take on Facebook, Google, Amazon, Apple, Qualcomm, Nvidia, Samsung, or whichever large tech company you'd most like to see disrupted, that new company would be destroyed by all the incumbent patents it can't match.</p>
<p>Who's to say for sure that if Facebook felt threatened by a social networking newcomer it wouldn't reach into its Friendster-derived patent bag and slap down the new contender — through patent lawsuits, patent licensing, or the threat of &quot;let us buy you or we'll sue you.&quot; It gives me great hope that Linux survived Microsoft's onslaught, but not every disruptive innovation will be as resilient.</p>
<p>In my opinion, patents aren’t an incentive for inventors, they’re a terror for inventors. Instead of simply creating something and putting it out in the world, you have to first hire a patent lawyer to see if it’s allowed. And because technology companies have become patent printing presses with armies of patent lawyers and stacks of obvious, meaningless patents, it’s probably <em>not</em> allowed.</p>
<p>All this to say, antitrust is lame. Let's do something weird. Let's get rid of patents. Or at least technology patents. Or maybe just make technology patents only last one year. If we still have horrible, non-disruptable corporations after that, I'll buy you lunch and we can discuss the morality of monopoly busting to your heart's content.</p>
]]>
      </description>
    </item>
    <item>
      <title>
        Maybe the web should die
      </title>
      <link>https://pauljmiller.com/posts/maybe-the-web-should-die.html</link>
      <pubDate>Thu, 17 Sep 2015 12:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/maybe-the-web-should-die.html</guid>
      <description>
        <![CDATA[<p>iOS 9 came out yesterday, and Apple snuck in a functionality called &quot;content blockers&quot; for Safari. Developers can make content blockers do all sorts of things, but mostly what they do is block ads. As of today, three of the top four paid apps on the app store are content blockers.</p>
<p>For obvious reasons, many of my former colleagues in the online, ad-supported content-creation industry, have been wringing their hands over this.</p>
<p>Nilay Patel, EIC of <em>The Verge</em> wrote a <a href="http://www.theverge.com/2015/9/17/9338963/welcome-to-hell-apple-vs-google-vs-facebook-and-the-slow-death-of-the-web">blood-soaked piece</a> about how this is all a proxy war between Google, Apple, and Facebook. Apple wants to kill Google, Google needs the web to make money, so Apple kills the web with content blockers and pushes people toward native app experiences it controls. Facebook picks up any stragglers in this scenario.</p>
<p>From a user perspective, ads on the web are garbage. Tracking scripts are almost as bad. Most web content is delivered with a heaping pile of both. Megabytes, and multiple latency-inducing roundtrips, are the price of viewing most popular web content today on sites like <em>The Verge</em>, <em>Buzzfeed</em>, etc.</p>
<p>Ad-blockers are an easy, painless solution to this problem from a user perspective. From a publisher perspective, they're a nightmare.</p>
<p>In a world of ad-blockers, online publishers become the music industry when it ran into Napster. Or the TV industry when it ran into TiVo.</p>
<p>Yesterday I argued on Twitter: &quot;if you like something, and dodge that something's creator's chosen method of monetization, you're killing that something&quot;</p>
<p>Saying &quot;adapt or die,&quot; as many people who run ad-blockers say to anyone who will listen, is basically armed robbery: &quot;give me your content, or give me your content and die.&quot;</p>
<p>I've been torn over ad-blockers for a long time. I know it would be hypocritical of me to run one, because ad supported websites like <em>Engadget</em> and <em>The Verge</em> have paid my bills in the past. But, also, ads are horrible and <a href="https://blog.yourkarma.com/i-hate-ads">my least favorite thing in any medium</a>.</p>
<p>But I finally figured out the Third Way: stop using all these garbage websites all the time.</p>
<p>I click <em>Buzzfeed</em> links and <em>Verge</em> links and <em>Awl</em> links and <em>Polygon</em> links for the same reason anybody does: there's a hole in my heart, and I hope 300-400 words of web content will fill it. If I want to learn anything of lasting importance, I read it in a book. If I want to be entertained, I watch a movie on Netflix. If I want to learn how to do something, I read it on some developer's self-hosted blog. If something is truly valuable it's usually free or paid-for. Ad-supported things are usually built not because they are necessary, but because they will generate more clicks and therefore more ad revenue.</p>
<p>Just think about it: where do you see the <em>most</em> ads? Where do you see the <em>worst</em> ads? Where do you see so many garbage ads all at once that you can barely find the &quot;content&quot;? It's those clickbait lists under the &quot;Sponsored Links&quot; section.</p>
<p>&quot;<a href="http://www.womensforum.com/trending/child-stars-grew-up-hot/">14 Child Stars Who Are Now Super Hot</a>&quot;</p>
<p>&quot;<a href="http://www.lifedaily.com/25-celebrities-that-you-forgot-committed-horrible-crimes/">24 Celebs You Forgot Committed Horrible Crimes: #19 is Shocking</a>&quot;</p>
<p>These pages are so full of garbage it's actually truly difficult to consume the &quot;content&quot; that brought me there. Oh, and that content is a gallery, so that each picture counts as a whole page view.</p>
<p>Most ad-supported websites on the internet are just a kinder, gentler, less offensive, slightly more entertaining version of these spammy clickbaiters. They're designed to make you <em>forget</em> you're being clickbaited. But they earn money from a complex mathematical formula that looks like like this: (page views) x (audience quality). If you're rich, and you click a lot, that site wins.</p>
<p>When I read a book or watch a movie or listen to an album, I usually get the sense that the creator of that thing values my time and attention as much I do. Values it as in &quot;attempts not to squander,&quot; not &quot;ooh, I can monetize this.&quot;</p>
<p>In a <a href="http://www.theawl.com/2015/02/the-next-internet-is-tv">really great piece</a> exploring this topic (subtitled: &quot;Websites are unnecessary vestiges of a time before there were better ways to find things to look at on your computer or your phone.&quot;), John Herrman explains how content creators are moving to native platforms like Facebook and Snapchat because that's where the eyeballs are. These &quot;enormous middlemen apps,&quot; says Herrman, &quot;have <strong>no special interest in publishing beyond value extraction through advertising</strong>&quot; (his emphasis).</p>
<p>And see, that's my worry, that's my problem. More than half the time when I'm at <em>Buzzfeed</em> and <em>The Verge</em> (I keep using <em>Buzzfeed</em> and <em>The Verge</em> as examples because I visit them a lot apparently), I get the distinct feeling that this publication has &quot;<strong>no special interest in publishing beyond value extraction through advertising</strong>&quot;. And if that's the case, then it's really important that I, as a human being with presumably better things to do, should avoid publications that make me feel this way.</p>
<p>I guess what I'm saying is this: I want to stop reading ad-supported websites. I don't want to steal their content by browsing with an ad-blocker, I want to <em>ignore</em> their content. I need a content blocker that blocks <em>content</em> too. Will I miss out on some stuff that's truly impressive, truly hilarious, truly insightful? Undoubtedly. But I'll also miss out on a lot of garbage, and a ton of garbage ads. So that will be nice.</p>
<p>Will I do any of this? No, probably not. Sites like <em>Buzzfeed</em> and <em>The Verge</em> are too enticing. I am weak. Which means I probably shouldn't run an ad-blocker, because then I'm just being a hypocritical jerk in addition to being weak.</p>
<p>But man, wouldn't it be nice to live in a world where I never have to read something that was written for the sole purpose of traffic and revenue? Where I only read things that need to exist, or are worth money on their own merits? Imagine this: words, on the internet, worth paying for.</p>
<p>The web doesn't have to be terrible. And, in fact, there are a lot of great parts of it. But online publications seem to have coalesced around the worst elements: huge ads, disposable content, auto-play videos, Like and Tweet buttons which follow you around the internet, hidden embedded pixels that try and guess your eye color so they can sell you shampoo more effectively. It's sites like these that make me regret how permissive HTML is.</p>
<p>The reason there's no solid revenue alternative to advertising for most of these websites is that most of what they put out is junkfood clickbait designed to increase revenue through ads. They can't monetize it because it's worthless. Is that ironic? It could be ironic.</p>
<p>P.S. I've recently signed up for <a href="https://www.google.com/contributor/welcome/">Google Contributor</a>, which is akin to something I asked for a while ago: to &quot;bid on my own eyeballs.&quot; There are two main issues with Google Contributor:</p>
<ol>
<li>It doesn't seem to actually do anything, I still see tons of garbage ads everywhere, served to me by Google. Apparently Mashable accepts Contributor, but I hate Mashable, it's a terrible repository of clickbait for people who live in San Francisco.</li>
<li>It rewards pageviews, which was really the whole point of this rant. Advertising is value extraction through pageviews, and so is Google Contributor. It's clearly the wrong kind of incentive. See: Mashable.</li>
</ol>
]]>
      </description>
    </item>
    <item>
      <title>
        E-sports for the uninformed
      </title>
      <link>https://pauljmiller.com/posts/e-sports-for-the-uninformed.html</link>
      <pubDate>Fri, 13 Feb 2015 12:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/e-sports-for-the-uninformed.html</guid>
      <description>
        <![CDATA[<p><em>I wrote this post almost a full year ago (the text file is timestamped May 27th, 2014). Pro play just started up again, and everything in here is still relevant. I realize now that this article probably has the wrong balance of jargon and dumbed-down-ness. Like, if you understand half of the RPG slang I have in here, you probably know more about League of Legends than I do. Still, I had to try.</em></p>
<p>Last year, 32 million people watched the <em>League of Legends</em> Season 3 World Championship. Every weekend, millions tune into &quot;regular season&quot; matches between their favorite teams. Any given moment, tens of thousands of &quot;LoL&quot; diehards are watching their favorite streamer on Twitch.tv slay scrubs on &quot;solo queue.&quot; The NFL doesn't start back up until September. You do the math. I'm going to teach you how to extract Real Sports Moments from this inscrutable &quot;esport,&quot; based on my own ill-founded knowledge of the subject, until you have something better to do.</p>
<p>Step 1: pick a stream</p>
<p>It's not hard to find a <em>League of Legends</em> livestream. Simply visit Twitch.tv and click on that first big link on the left that says &quot;League of Legends.&quot; Outside of the occasional <em>Dota 2</em> tournament (<em>Dota 2</em> is very similar to <em>League of Legends</em>, and most of the following tips can be applied), <em>League of Legends</em> holds the perennial top spot on Twitch for most concurrent viewers. Typically in the mere ~80k range, viewership spikes to 200k+ whenever a professional match is happening. There are actually five major leagues worldwide, in addition to an amateur league (the Challenger Series) which happens in parallel. While the highest level of play is currently in South Korea, China, and Europe, I prefer the North American league because the stream is in HD and the hours are predictable and EST-friendly.</p>
<p>If there aren't any pro matches happening when you try to tune in, you can find an archive of broadcasts on the <a href="http://www.twitch.tv/riotgames/profile/pastBroadcasts">Riot Games Twitch page</a>, or browse through a prettier (but spoiler-filled) collection of matches at the <a href="http://na.lolesports.com/">official site</a>.</p>
<p>Step 2: back a team</p>
<p>This is the least important step of the process, and I encourage you to switch loyalties on a whim. You know how that one friend of yours doesn't know anything about football, and every Super Bowl he roots for the team with the &quot;best uniform&quot;? And you know how you loathe him, but secretly envy his ability to derive enjoyment from watching a contest with none of the potential heartache of a &quot;true&quot; fan? This is your chance to <em>be that guy</em>!</p>
<p>Basically, one team starts on the bottom left and has blue health bars, and the other team starts on the top right and has red health bars. I typically root for blue as a default, because blue = good, red = bad in typical video game scenarios. Still, it's important to hold this choice loosely. Unlike many professional sports, <em>League of Legends</em> matches have what's called a &quot;snowball effect,&quot; where by default the strong get stronger and the weak get weaker. This means that if a team gets out to an early lead, they'll most likely win the match, and so it's a safe bet to root for the team with an edge by the 5-10 minute mark if you're looking for minimal disappointment.</p>
<p>Of course, after a year or so of watching professional <em>League</em>, I've got some favorites. TSM, for instance, has a number of qualities I look for in a professional esports team. On average, TSM players are better looking, and better dressed, than the competition. They wear matching varsity jackets and grey skinny jeans, in a sport dominated by schlubby hoodies and logo-emblazoned motocross apparel. TSM also has Bjergsen, voted MVP of the 2014 LCS Spring Split, and my vote for &quot;who wore it best&quot; IRT the varsity jacket / skinny jean combo.</p>
<p>Step 3: count the creeps</p>
<p>I suppose this is the point in the guide where I should give you a basic idea of the &quot;point&quot; of a <em>League of Legends</em> match. But, really, it's not the most important thing. Watching <em>LoL</em> matches for the results is like watching soccer for &quot;all the goals they score all the time,&quot; except in <em>LoL</em> there's only one goal scored (destroying the opponent &quot;Nexus,&quot; at the back of their color-coded base), and the team that scores the goal wins instantly. Everything else is posturing, positioning, and grinding.</p>
<p>Basically, <em>League of Legends</em> gameplay is an accelerated version of an RPG level grind. Each player gains gold and experience by killing monsters (and each other), spends the gold on better gear, and levels up their powers with the experience. The most basic unit in the game is a &quot;minion,&quot; which stream endlessly from each base along mirrored &quot;lanes.&quot; The number of minions and other creatures killed by a player is called their &quot;creep score,&quot; and it's a good shorthand for how much relative gold and experience -- and therefore power -- they've accumulated. The creep score (typically referred to as &quot;CS&quot;) is listed next to the player's avatar icon at the bottom of the screen.</p>
<p>Different players will have wildly different CS, and that typically denotes their differing roles on the team. Typically a team will have a couple &quot;carrys&quot; (most CS), a &quot;jungler&quot; (a lot of CS), a &quot;tank&quot; (less CS), and a support (least CS). These roles aren't set in stone (there's an ever-evolving &quot;meta&quot; which dictates how teams are composed), and I'm actually not sure I got the order right anyway. What's important is that one or two players on each team will be &quot;stacked&quot; with the most gear and levels, while their teammates work hard to keep them alive and &quot;fed&quot; (more gear, more levels). And then they all fight.</p>
<p>Step 4: root for kills</p>
<p>Here's where the magic happens. Specifically, Bjergsen magic. You know that classic RPG feeling you get when you grind a few levels, buy some new gear, and suddenly those monsters which were so scary ten minutes ago seem to melt under your oversized sword blows? This is why I watch <em>League</em>. Inevitably, somebody gets &quot;fed&quot; (like, for instance, Bjergsen) and somebody gets melted. This is always satisfying.</p>
<p>There are innumerable factors that go into a successful melting, and the more you watch <em>League</em> the more you'll pick up on, but I'll walk you a few of the basics to help boost your initial satisfaction.</p>
<p>First, a player &quot;wins his lane,&quot; &quot;counter jungles,&quot; or &quot;ganks&quot; somebody. To get the snowball rolling, all he needs is an edge somewhere. This can be achieved by killing minion waves while keeping his mirror matchup from doing the same, trespassing into enemy area and stealing &quot;camps&quot; (stationary minions on set spawn timers), or simply finding vulnerable players and killing them. Once he pulls ahead, it becomes even easier to do all of the above activities -- each of which also harm opposing players.</p>
<p>Once a player builds a clear lead, the opponent must make a difficult decision: do they invest their limited resources in damage-dealing items, in hopes to catch their terrorizer off guard and defeat him, or do they build &quot;tanky&quot; and merely hope to survive? Obviously, this being a video game played by men in their early 20s, they typically pick the damage option. This results in what's known as a &quot;squishy&quot; hero.</p>
<p>To be honest, this is what used to frustrate me about <em>League of Legends</em>. Now I see it as a virtuous cycle. Exciting comebacks, a mainstay of most professional sporting leagues, are incredibly rare in <em>League</em>. Ultimately, I'm rooting for someone to dominate. A close match can be entertaining in its own way, but ultimately a win comes when one team gains a clear advantage and pummels the opponent into submission. Really, match dynamics are more like MMA or boxing than traditional team sports. You're rooting for a KO.</p>
<p>Step 5: complain about the casters</p>
<p>An age-old tradition in obsessive sports spectating is hating on the announcers. There's so much satisfaction to be found in feeling smugly superior to a sport's &quot;professional&quot; experts. This satisfaction is multiplied by the inherent silliness of a man whose job is to yell excitedly about what's happening in a fantasy-themed action RPG.</p>
<p>This is no easy task, of course. A <em>League of Legends</em> caster needs to have an encyclopedic knowledge of hundreds of avatars, players, items, and strategies. Then they need to inform the viewer of relevant facts pertaining to ten players, each juggling a subset of these avatars, items, and strategies, in real time, as the game unfolds. More astonishingly, a good caster can explain the specific spells and abilities being used by different players during a fight which, to my untrained eye, looks like a series of unrelated explosions and lens flares.</p>
<p>On top of all this complexity is the pronoun problem: a player is a &quot;he,&quot; but his avatar could be a &quot;he,&quot; &quot;she,&quot; or &quot;it.&quot; When his avatar attacks another avatar, the pronoun possibilities explode, and the poor, put-upon caster frequently retreats to the vaguest possible terms to refer to the parties involved.</p>
<p>Basically, a caster is set up to fail, and failing is <em>hilarious</em>. A caster has absolutely no chance of making the game &quot;accessible&quot; to the uninitiated. I have no idea what it means that &quot;Kha'Zix&quot; is trying to build his &quot;Blade of the Ruined King,&quot; and probably never will, because five thousand other things just happened during that sentence. Things that happen in <em>League</em> are so alien that many casters have difficulty spitting out sensical analogies to or summaries of the melee, resulting garbled phrases along the lines of &quot;boom goes the dynamite.&quot;</p>
<p>Step 6: ignore chat</p>
<p>All the difficulties in realtime match analysis I just listed? Now imagine them undertaken by 200,000 racist, sexist, illiterate 13-year-olds in an IRC chatroom. The accompanying Twitch.tv chat is my least favorite part of the current esports scene, and most of the time I just pretend it doesn't exist. I'm sure there are other calm, mature fans of <em>DotA</em>, <em>League</em>, and <em>StarCraft</em>, but they're difficult to find in the Twitch chat spamfest. You've been warned.</p>
<p>Step 7: root for the humans</p>
<p>Ultimately, I find nearly all esports fascinating and compelling because of one shared element: human players. The qualities specific to professional video games include fast reflexes (like that of a NASCAR driver), manual dexterity (akin to a piano player), an extensive memory (sort of like chess), and the endurance to stay sharp throughout a match which can last anywhere from 20 minutes to an hour.</p>
<p>The high production values of the NA LCS makes these and other human factors apparent. You can see the nerves of young players, practically shaking before a match begins. The fatigue and pain, as they massage their aching hands with heat packs. Bravado as they strut on stage to a cheering crowd. Disappointment, as they slump in their chairs and stare blankly at their LCDs in defeat. Social awkwardness, as they fist bump, hug, and shake hands</p>
<p><em>... LOL THAT'S WHERE I LEFT OFF. Way to be a finisher, Paul. Way to see it through to the end like a real pro. I guess, as a wrap up, I'd say... hmm, not really sure what to say. Guess that's why this is a cliffhanger! So draw your own conclusions, I'm done.</em></p>
]]>
      </description>
    </item>
    <item>
      <title>
        Call me when you're Turing complete
      </title>
      <link>https://pauljmiller.com/posts/call-me-when-youre-turing-complete.html</link>
      <pubDate>Thu, 22 Jan 2015 12:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/call-me-when-youre-turing-complete.html</guid>
      <description>
        <![CDATA[<p><em>Editor's note: I wrote this at E3 in 2012. I don't think it makes a strong or clear enough point, and I'm guessing that's why I or my editor killed it. What I love about it though is how games like Shadow of Mordor and No Man's Sky are showing the power of simulation and procedural generation in making compelling AAA games. I can't say &quot;see I told you so&quot; because I never did, but still: see?</em></p>
<p>When I think about &quot;next-gen&quot; games, my mind typically rushes to graphics. Square Enix's <em>Final Fantasy</em> tech demo at E3 is the current winner in this regard, with Ubisoft's <em>Watch_Dogs</em> and Epic's Unreal Engine 4 running close behind. And it's true, the next generation of consoles are going to have graphics that will make current standouts like <em>Uncharted</em> and <em>Gears of War</em> look quaint. I'm excited about this; I love looking at things, especially pretty things. But ultimately graphics are iterative, just like most of the game mechanics that have arrived in this console generation. What sort of game mechanics will help the next generation of games take a left turn and offer experiences that are entirely new?</p>
<p>When I think <em>really hard</em> about &quot;next-gen&quot; games, I think about <em>Dwarf Fortress</em>. In the game you build a simulated society, brick by brick. It's like <em>The Sims</em> meets <em>Minecraft</em>. Your dwarves live entire simulated lives under your care, mining, crafting, building, farming, sleeping, eating, and fighting. They care about each other, they care about beer, they care what quality of materials the furniture in their room is made out of. Dwarves frequently go insane, or starve themselves to death in grief, or carve their stories into the walls of your fortress.</p>
<p><em>Dwarf Fortress</em> is in ASCII. It's ugly. It's impossibly difficult to play. It's simulating so much that it can struggle with &quot;frame rate&quot; as your fortress grows in complexity. I typically play it for a couple days, sinking hours into referencing tutorials and building porous fortresses that typically fall to the first wave of hostile elves — or elephants. Then I give up, Google to see if there are any <em>Minecraft</em> mods yet that offer a decent subset of <em>Dwarf Fortress</em>, and then it's 4am and I have to work the next day.</p>
<p>Something I love about <em>Minecraft</em> and <em>Dwarf Fortress</em> is that they're what's called &quot;Turing Complete,&quot; meaning that they're capable of sufficiently complex simulations to allow you to build a computer within the game — or at least a calculator. All this really requires is switches, and a way to chain those switches together in a way that they can be manipulated by inputs and by each other. In <em>Dwarf Fortress</em> you can use flowing water and wooden gates to get your Turing on, in <em>Minecraft</em> there's redstone wiring and switches — Notch was heavily influenced by <em>Dwarf Fortress</em>, and made a point of making his game Turing Complete, a &quot;feature&quot; that was a bit more incedental in <em>Dwarf Fortress</em>.</p>
<p>Of course, I've never built a computer in either game, and have no plans to. But I think the fact that I <em>can</em> makes a statement about what sort of game it is. I feel like the virtual world of Neal Stephenson's <em>Snow Crash</em> would have no problem with Turing, and in William Gibson's <em>Neuromancer</em>, the entire virtual world is basically made out of representations of computers. But imagine building a computer with your friends in <em>World of Warcraft</em>, or in <em>Grand Theft Auto</em>'s &quot;open world&quot;.</p>
<p>In <em>Mass Effect</em>, you have a few hundred choices to make through the game, and a handful of potential outcomes at the end — which puts it in the top echelon for choice in console games. In <em>Dwarf Fortress</em>, the story writes itself, it's infinitely varied, and there is no end. I'm not about abandoning story, like in <em>Sim City</em> or <em>Civilization</em>, I just want the story to be the game itself, and granularly impacted by my every action — I don't want glorified checkpoints with &quot;sandbox&quot; in between.</p>
<p>I don't think these ideas are new, but they're commonly associated with indie and fringe games, not the elusive next-gen consoles from Microsoft and Sony that could be in our homes sometime late next year. What simulation needs is a serious game studio and some serious hardware to pull it from the ghetto.</p>
]]>
      </description>
    </item>
    <item>
      <title>
        I made a blog
      </title>
      <link>https://pauljmiller.com/posts/i-made-a-blog.html</link>
      <pubDate>Thu, 22 Jan 2015 00:45:59 +0000</pubDate>
      <guid>https://pauljmiller.com/posts/i-made-a-blog.html</guid>
      <description>
        <![CDATA[<p>This was long overdue. There are things I think about, and now I can publish all of them on the internet. Not just, you know, the sort of thing that belongs on Engadget, The Verge, or the Karma blog. But stuff that belongs under a sort of banner like &quot;Paul's blog&quot; so you really know what to expect.</p>
<p>I think I'll start out by putting up some of the not-published writing I've done. There are lots of reasons that things I've written don't get published, but there's usually one super-reason: they weren't good enough to publish. But this is a blog, so I'm lowering my standards.</p>
<p>I hope that you enjoy the things I put up here, and, as a long overdue / badly placed sidenote: <em>thank you for reading</em>. I've been really blessed in my life to find an audience for my words and thoughts, and I don't take it for granted. You're the real MVP.</p>
]]>
      </description>
    </item>
    </channel>
</rss>