<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Large-scale AI apps in production]]></title><description><![CDATA[Learnings and practical tips from running an AI-powered app that reached 300M downloads]]></description><link>https://eliot.blog</link><image><url>https://substackcdn.com/image/fetch/$s_!3B0V!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54abc69b-26ba-42d9-ad06-8144138c3834_1216x1216.png</url><title>Large-scale AI apps in production</title><link>https://eliot.blog</link></image><generator>Substack</generator><lastBuildDate>Mon, 13 Apr 2026 18:25:19 GMT</lastBuildDate><atom:link href="https://eliot.blog/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Eliot Andres]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[eliotandres@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[eliotandres@substack.com]]></itunes:email><itunes:name><![CDATA[Eliot Andres]]></itunes:name></itunes:owner><itunes:author><![CDATA[Eliot Andres]]></itunes:author><googleplay:owner><![CDATA[eliotandres@substack.com]]></googleplay:owner><googleplay:email><![CDATA[eliotandres@substack.com]]></googleplay:email><googleplay:author><![CDATA[Eliot Andres]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Agentic Coders Anonymous Paris, first edition]]></title><description><![CDATA[Last Monday, I organized the first edition of Agentic Coders Anonymous in Paris.]]></description><link>https://eliot.blog/p/agentic-coders-anonymous-paris-first</link><guid isPermaLink="false">https://eliot.blog/p/agentic-coders-anonymous-paris-first</guid><dc:creator><![CDATA[Eliot Andres]]></dc:creator><pubDate>Sun, 22 Feb 2026 20:30:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!TPq9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last Monday, I organized the first edition of Agentic Coders Anonymous in Paris. Inspired by <a href="https://steipete.me/posts/2025/claude-code-anonymous">Claude Code Anonymous</a> by Peter Steinbeger, the idea is simple: a meetup where every attendee presents their AI coding setup for 5 minutes.</p><p>Coding with AI moves so fast that it&#8217;s easy to feel left-out, so it was a great opportunity to exchange tips, techniques or new use cases.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TPq9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TPq9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic 424w, https://substackcdn.com/image/fetch/$s_!TPq9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic 848w, https://substackcdn.com/image/fetch/$s_!TPq9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic 1272w, https://substackcdn.com/image/fetch/$s_!TPq9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TPq9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic" width="410" height="307.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e4ad36e2-b293-417d-8003-d4ea8e785601.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:410,&quot;bytes&quot;:1161209,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/188701858?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TPq9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic 424w, https://substackcdn.com/image/fetch/$s_!TPq9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic 848w, https://substackcdn.com/image/fetch/$s_!TPq9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic 1272w, https://substackcdn.com/image/fetch/$s_!TPq9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4ad36e2-b293-417d-8003-d4ea8e785601.heic 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I learned a ton during that meetup! Here are a few interesting tidbits:</p><ul><li><p>Someone connected OpenClaw on a Mac mini and uses it to try-out app ideas. For iOS animations, he asks the agent to build 5 variants of the app. He then downloads each one on his phone to pick the best option</p></li><li><p>Someone is building <a href="https://twill.ai/">CRON jobs for agents</a>: e.g. when a Sentry alert pops up, the agent can investigate</p></li><li><p>Someone explained that they heavily use logs throughout their production Kubernetes cluster and have agents query them. No Datadog or Grafana as it would be expensive with that volume. When an issue arises, all it takes is to ask the agent to go investigate</p></li><li><p>The same person explained that they have one big machine where developers run their sessions on tmux (vs running in the Cloud)</p></li></ul><p>People also shared a bunch of great tools I never heard about:</p><ul><li><p><a href="https://github.com/raine/workmux">Workmux</a>: a tool for managing git worktrees and tmux windows as isolated development environments</p></li><li><p><a href="https://gitbutler.com/">Git Butler</a>: an agent orchestrator that makes running agents on multiple branches in parallel</p></li></ul><p>Given the pace of AI, I&#8217;m thinking of running this event about once a month. If you have a great setup you&#8217;d like to showcase, please send me a message! Since every attendee presents, spots are limited.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Trying out Coder (attempting to rebuild Ramp's background agents setup in a weekend, part 2)]]></title><description><![CDATA[Last weekend, I attempted to rebuild Ramp&#8217;s background agent setup using OpenCode and OpenCode Portal.]]></description><link>https://eliot.blog/p/trying-out-coder-attempting-to-rebuild</link><guid isPermaLink="false">https://eliot.blog/p/trying-out-coder-attempting-to-rebuild</guid><dc:creator><![CDATA[Eliot Andres]]></dc:creator><pubDate>Sun, 08 Feb 2026 20:22:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!paas!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last weekend, I attempted to <a href="https://eliot.blog/p/attempting-to-rebuild-ramps-background">rebuild Ramp&#8217;s background agent setup</a> using OpenCode and OpenCode Portal. I could finally close my laptop and have my agents run multiple tasks in parallel. However, there were a few shortcomings:</p><ol><li><p>The agents were not sandboxed, they were all running on the same Mac VM</p></li><li><p>The setup was not frictionless, requiring some fiddling to open a terminal on a machine or connect with VSCode </p></li><li><p>I had to secure the Cloudflare tunnel myself, OpenCode Portal doesn&#8217;t provide any auth</p></li></ol><p>After reading my article, a friend told me that <a href="https://coder.com/">Coder</a> could solve a lot of my problems. After struggling to look it up because of their impossible-to-google name, I spent the weekend trying their new Tasks feature. In a nutshell, you install Coder on a VM, it spins up a web UI where you can launch background tasks. Each task is launched inside its own Docker container (but you can also use Kubernetes).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!paas!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!paas!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png 424w, https://substackcdn.com/image/fetch/$s_!paas!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png 848w, https://substackcdn.com/image/fetch/$s_!paas!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png 1272w, https://substackcdn.com/image/fetch/$s_!paas!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!paas!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png" width="1456" height="726" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:726,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:439789,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/187316699?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!paas!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png 424w, https://substackcdn.com/image/fetch/$s_!paas!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png 848w, https://substackcdn.com/image/fetch/$s_!paas!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png 1272w, https://substackcdn.com/image/fetch/$s_!paas!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5607bce8-678b-4431-b220-e39e46b42d9b_2086x1040.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The Coder UI with two live tasks. Ugly annotations courtesy of the author</figcaption></figure></div><p>At your fingertips, the web UI shows the holy trinity of the vibe coder: Claude Code, Cursor, a terminal.</p><p>Coder has other nifty features. You can configure templates that control your agent environments (e.g dependencies, access tokens), presets for templates parameters (I have a preset with a branch I use often instead of main), the GitHub integration is quite smooth (even for GitHub Organizations), it can tell you why an environment is slow to start:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Yy4U!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Yy4U!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png 424w, https://substackcdn.com/image/fetch/$s_!Yy4U!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png 848w, https://substackcdn.com/image/fetch/$s_!Yy4U!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png 1272w, https://substackcdn.com/image/fetch/$s_!Yy4U!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Yy4U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png" width="1456" height="561" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:561,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:110923,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/187316699?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Yy4U!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png 424w, https://substackcdn.com/image/fetch/$s_!Yy4U!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png 848w, https://substackcdn.com/image/fetch/$s_!Yy4U!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png 1272w, https://substackcdn.com/image/fetch/$s_!Yy4U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fae5a50-2d07-4ef9-bb09-8d0c23e582f4_2444x942.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So what&#8217;s missing? The web UI is not usable on mobile for anything besides checking the status. But the beauty of open-source is that you can go and fix it with a pull request. You could also build your own UI since they have an API (if you do build a great one for iPhone, please ping me!). Also, they have a few interesting features,  such as pre-warming the environments, that require talking to their sales team.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!69wb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!69wb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg 424w, https://substackcdn.com/image/fetch/$s_!69wb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg 848w, https://substackcdn.com/image/fetch/$s_!69wb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!69wb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!69wb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg" width="135" height="293.88289036544853" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2621,&quot;width&quot;:1204,&quot;resizeWidth&quot;:135,&quot;bytes&quot;:203780,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/187316699?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!69wb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg 424w, https://substackcdn.com/image/fetch/$s_!69wb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg 848w, https://substackcdn.com/image/fetch/$s_!69wb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!69wb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5db2db56-2107-4e1c-8182-a58fe3c4a40b_1204x2621.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The web UI on an iPhone</figcaption></figure></div><p>We&#8217;re almost there! If you compare to <a href="https://engineering.ramp.com/post/why-we-built-our-background-agent">Ramp&#8217;s setup</a>, we&#8217;re missing a few items: instant startup (by the time you finish typing), spawning sub-agents (so an agent can try 10 ideas in parallel), a great mobile UI and a Slack interface. </p><p>As per <a href="https://steve-yegge.medium.com/welcome-to-gas-town-4f25ee16dd04">Gas Town</a>&#8217;s creator, I&#8217;m about to reach stage 7 of AI-Assisted coding: 10+ agents, hand-managed. Future will tell whether I reach stage 8, building my own agent orchestrator. Where does forking an existing orchestrator put you?</p>]]></content:encoded></item><item><title><![CDATA[PSA: the best Hacker News app for iOS is called "HACK"]]></title><description><![CDATA[No tracking, free and fast. What more do you need?]]></description><link>https://eliot.blog/p/psa-the-best-hacker-news-app-for-ios</link><guid isPermaLink="false">https://eliot.blog/p/psa-the-best-hacker-news-app-for-ios</guid><dc:creator><![CDATA[Eliot Andres]]></dc:creator><pubDate>Sun, 01 Feb 2026 20:34:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!WLbw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve tried many Hacker News client over the years, but for the past 3 years I stuck to a single one.</p><p>The app is: free, fast, without any tracking or analytics (I checked), has notifications for posts, Algolia search and is extremely customizable.</p><p>You can select how minimalist you want the home page to be, what gestures are on, how the web pages should open. How I configured my home page as well as a sample of the numerous settings:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WLbw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WLbw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png 424w, https://substackcdn.com/image/fetch/$s_!WLbw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png 848w, https://substackcdn.com/image/fetch/$s_!WLbw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png 1272w, https://substackcdn.com/image/fetch/$s_!WLbw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WLbw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png" width="1456" height="1583" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1583,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:787928,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/183370701?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WLbw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png 424w, https://substackcdn.com/image/fetch/$s_!WLbw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png 848w, https://substackcdn.com/image/fetch/$s_!WLbw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png 1272w, https://substackcdn.com/image/fetch/$s_!WLbw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61ac7eee-35f4-4aad-b0e7-773fa4ea45f4_2412x2622.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>How do I know it doesn&#8217;t collect any data? I checked with Proxyman. I can&#8217;t guarantee it there&#8217;s no secret exfiltration method, but I found the app setup interesting. Since there&#8217;s no official Hacker News API, the app has to work with Hacker News&#8217; HTML directly: it fetches all the selectors required to parse the content at startup. No server required. Here&#8217;s an example:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qD6R!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qD6R!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png 424w, https://substackcdn.com/image/fetch/$s_!qD6R!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png 848w, https://substackcdn.com/image/fetch/$s_!qD6R!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png 1272w, https://substackcdn.com/image/fetch/$s_!qD6R!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qD6R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png" width="490" height="445.07757404795484" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1288,&quot;width&quot;:1418,&quot;resizeWidth&quot;:490,&quot;bytes&quot;:427669,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/183370701?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qD6R!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png 424w, https://substackcdn.com/image/fetch/$s_!qD6R!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png 848w, https://substackcdn.com/image/fetch/$s_!qD6R!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png 1272w, https://substackcdn.com/image/fetch/$s_!qD6R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa62e38aa-8b92-4247-be00-e0c0426d1d98_1418x1288.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Get <a href="https://apps.apple.com/us/app/hack-for-hacker-news-yc-reader/id1464477788">Hack on iOS</a> (also <a href="https://play.google.com/store/apps/details?id=com.pranapps.hack&amp;hl=en">available on Android</a>, although I didn&#8217;t try it). I have no affiliation with the developer, besides the tips I sent. Dear developer, if you read this blog post, thank you!</p>]]></content:encoded></item><item><title><![CDATA[Attempting to rebuild Ramp's background agent system in a weekend (on a Mac VM)]]></title><description><![CDATA[Like many people, I was blown away by Ramp&#8217;s article on background agents. They use a setup where agents:]]></description><link>https://eliot.blog/p/attempting-to-rebuild-ramps-background</link><guid isPermaLink="false">https://eliot.blog/p/attempting-to-rebuild-ramps-background</guid><dc:creator><![CDATA[Eliot Andres]]></dc:creator><pubDate>Sun, 25 Jan 2026 21:20:43 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b1d86688-a8df-4e0c-abcf-63b42e5ac445_1941x1052.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Like many people, I was blown away by Ramp&#8217;s <a href="https://engineering.ramp.com/post/why-we-built-our-background-agent">article on background agents</a>. They use a setup where agents:</p><ul><li><p>run on remote VMs (so you can close your laptop)</p></li><li><p>spawn on-demand before you finish typing your prompt (so you can try any idea quickly)</p></li><li><p>have access to all of Ramp&#8217;s tools (Sentry, Datadog)</p></li><li><p>can spawn sub-agents (in a new VM) and are multiplayer (other humans can view the agent&#8217;s work)</p></li><li><p>are multi-interface: Slack, web UI, voice</p></li></ul><p>If you follow Steve Yegge&#8217;s (<a href="https://steve-yegge.medium.com/welcome-to-gas-town-4f25ee16dd04">Gas Town</a>&#8217;s author) classification, Ramp&#8217;s developers are at the final level of agent building:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://steve-yegge.medium.com/welcome-to-gas-town-4f25ee16dd04" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6bMp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4534099-c010-42f4-96b5-76f0945f3be0_1529x1353.png 424w, https://substackcdn.com/image/fetch/$s_!6bMp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4534099-c010-42f4-96b5-76f0945f3be0_1529x1353.png 848w, https://substackcdn.com/image/fetch/$s_!6bMp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4534099-c010-42f4-96b5-76f0945f3be0_1529x1353.png 1272w, https://substackcdn.com/image/fetch/$s_!6bMp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4534099-c010-42f4-96b5-76f0945f3be0_1529x1353.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6bMp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4534099-c010-42f4-96b5-76f0945f3be0_1529x1353.png" width="482" height="426.38461538461536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4534099-c010-42f4-96b5-76f0945f3be0_1529x1353.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1288,&quot;width&quot;:1456,&quot;resizeWidth&quot;:482,&quot;bytes&quot;:220629,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://steve-yegge.medium.com/welcome-to-gas-town-4f25ee16dd04&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://markferree.substack.com/i/185649875?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4534099-c010-42f4-96b5-76f0945f3be0_1529x1353.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!6bMp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4534099-c010-42f4-96b5-76f0945f3be0_1529x1353.png 424w, https://substackcdn.com/image/fetch/$s_!6bMp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4534099-c010-42f4-96b5-76f0945f3be0_1529x1353.png 848w, https://substackcdn.com/image/fetch/$s_!6bMp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4534099-c010-42f4-96b5-76f0945f3be0_1529x1353.png 1272w, https://substackcdn.com/image/fetch/$s_!6bMp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4534099-c010-42f4-96b5-76f0945f3be0_1529x1353.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Steve Yegge&#8217;s <a href="https://steve-yegge.medium.com/welcome-to-gas-town-4f25ee16dd04">classification</a>. Image from <a href="https://substack.com/inbox/post/185649875">Mark Ferree</a></figcaption></figure></div><p>Over the weekend, I attempted to rebuild Ramp&#8217;s system by wiring open-source tools. For this first version, I reduced the scope: no multiplayer, can&#8217;t spawn new VMs. But I added a twist: I wanted to test features in our iOS app, therefore I needed to run macOS.</p><p>Last night, I asked Claude to benchmark our iOS app&#8217;s build time. It researched optimizations, measured the impact of each option and gave me a shiny report. By the time I woke up I ended up with a magic flag that resulted in a +10% speedup.</p><p>The setup leverages <a href="https://github.com/cirruslabs/tart">Tart</a> to manage the macOS VM, <a href="https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/">Cloudflare Tunnels</a> to connect to services running inside the VM with no hassle, <a href="https://github.com/anomalyco/opencode">OpenCode</a> for the agent and the beautiful <a href="https://github.com/hosenur/portal">OpenCode Portal</a> to interact with it.</p><p>I also use the native Mac Screen Sharing app to connect to the UI. I&#8217;m not planning on relying on it much, but it&#8217;s very handy to debug issues.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NMXf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NMXf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png 424w, https://substackcdn.com/image/fetch/$s_!NMXf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png 848w, https://substackcdn.com/image/fetch/$s_!NMXf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png 1272w, https://substackcdn.com/image/fetch/$s_!NMXf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NMXf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png" width="1456" height="823" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:823,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:526974,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/185755013?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NMXf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png 424w, https://substackcdn.com/image/fetch/$s_!NMXf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png 848w, https://substackcdn.com/image/fetch/$s_!NMXf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png 1272w, https://substackcdn.com/image/fetch/$s_!NMXf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94325042-23be-4ec2-a5a1-225906debb80_2194x1240.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Overview of the background agents setup</figcaption></figure></div><p>A few gotchas: make sure you run your Mac VM on the instance&#8217;s local SSD (but be careful it&#8217;s ephemeral), AWS has a <strong>24-hour</strong> minimum for Mac Instances (hence a ~$30 minimum charge), Cloudflare Tunnels will expose your agent web UI to the public internet <a href="https://github.com/search?q=trycloudflare.com&amp;type=code">if you&#8217;re not careful</a>.</p><p>So what&#8217;s missing? To reach Ramp&#8217;s level we&#8217;re missing a few key elements: multiplayer, per-user accounts / isolation and spawning new VMs instantly. That last one might be tricky since Apple enforces the 24h billing rule.</p><p>This setup may seem a tad complex, but boy does it feel good to wake up after my agents waited for Xcode to build, not me.</p>]]></content:encoded></item><item><title><![CDATA[Building Google-Docs-like live collaboration for a cross-platform app used by millions (in Rust)]]></title><description><![CDATA[Imagine yourself with 3 different clients (iOS, Android and web), each written in a different language, each already used by millions of users.]]></description><link>https://eliot.blog/p/building-google-docs-like-live-collaboration</link><guid isPermaLink="false">https://eliot.blog/p/building-google-docs-like-live-collaboration</guid><dc:creator><![CDATA[Eliot Andres]]></dc:creator><pubDate>Sun, 18 Jan 2026 21:24:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!S5k6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine yourself with 3 different clients (iOS, Android and web), each written in a different language, each already used by millions of users. Now imagine that you wanted those clients to communicate together. Not simply client &lt;&gt; server, but that if a user edits an image on iOS, that image would display in the exact same way on Android. Instantly. Reliably. Same for text. Oh and AI effects too.</p><p>That&#8217;s the situation we faced about 2 years ago at <a href="https://www.photoroom.com/">Photoroom</a>. We provide editing tools for e-commerce images and we wanted guarantee our users that their content was always in sync, even when their teammates where working on it at the same time. </p><p>The good news is that we were already sharing our rendering code between platforms (<a href="https://www.photoroom.com/inside-photoroom/building-cross-platform-image-renderer">read about it in our 2021 article</a>). The bad news is that it was written in C. Not the best language to decode payloads back and forth over the network.</p><p>We ended up picking Rust and built a cross-platform live-collaboration engine. It&#8217;s been live (no pun intended) on all 3 platforms for a little while now. Here&#8217;s a quick demo:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;5d1de0c5-ebb9-40d7-91ec-fea3c044cc08&quot;,&quot;duration&quot;:null}"></div><h2>Why Rust? Why not React Native?</h2><p>Besides attempting to make it to the home page of Hacker News, we picked Rust because&#8230; it would be easier to hire than for C++. We know how attractive the language can be to experienced developers. We also considered Golang, but its runtime makes it more complicated to run on the web.</p><p>This may seem like a lot of pointless work to run on 3 platforms when solutions like React Native exist. We strongly believe in providing the very best image editing experience to our users, and we don&#8217;t think it&#8217;s possible to do so with React Native (but this stance might change in the future).</p><h2>How it works </h2><p>In a nutshell, the Rust code is compiled on iOS, Android and the web. The rendering of the UI is done natively (SwiftUI, Compose, React), same for the network calls (URLSession, OkHttp, fetch), same fore rendering (Metal, OpenGL, WebGL/WebGPU  through wgpu). But all the logic is inside the Rust code.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!S5k6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!S5k6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png 424w, https://substackcdn.com/image/fetch/$s_!S5k6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png 848w, https://substackcdn.com/image/fetch/$s_!S5k6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png 1272w, https://substackcdn.com/image/fetch/$s_!S5k6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!S5k6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png" width="1456" height="887" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:887,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:429374,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/184104096?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!S5k6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png 424w, https://substackcdn.com/image/fetch/$s_!S5k6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png 848w, https://substackcdn.com/image/fetch/$s_!S5k6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png 1272w, https://substackcdn.com/image/fetch/$s_!S5k6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc96ddb0-e9e6-48d1-b5af-a0283ed3fe94_2410x1468.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Wait, that&#8217;s a bit lightweight for an explanation, isn&#8217;t it? We&#8217;re quite proud of the work we did, that&#8217;s why we detailed the nitty-gritty <a href="https://www.photoroom.com/inside-photoroom/building-live-collaboration-in-rust-for-millions-of-users-part-1">in a 5-parts blog post series</a>.</p><p>If this sort of work sounds exciting to you, we&#8217;re hiring a head of cross-platform to provide a seamless experience to millions of users. <a href="https://jobs.ashbyhq.com/photoroom/dc994a7c-e104-46e1-81c3-b88d635398b9">Learn more here</a>.</p>]]></content:encoded></item><item><title><![CDATA[Why you should change your mobile app version format to [year].[week].[iteration] ]]></title><description><![CDATA[Why we did it and the downsides]]></description><link>https://eliot.blog/p/why-you-should-change-your-mobile</link><guid isPermaLink="false">https://eliot.blog/p/why-you-should-change-your-mobile</guid><dc:creator><![CDATA[Eliot Andres]]></dc:creator><pubDate>Sun, 11 Jan 2026 21:38:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7ERB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a software engineer, I&#8217;ve been trained to think that there&#8217;s only one way to version software: <a href="https://semver.org/">semantic versioning</a>.</p><p>At <a href="https://www.photoroom.com/">Photoroom</a>, we used to increment the major version number on big releases to celebrate. Recently, however, we moved our mobile apps to a versioning scheme like like 2025.51.01 (so <em>[year].[weekNumber].[iteration]</em>)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jyt-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jyt-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png 424w, https://substackcdn.com/image/fetch/$s_!jyt-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png 848w, https://substackcdn.com/image/fetch/$s_!jyt-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png 1272w, https://substackcdn.com/image/fetch/$s_!jyt-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jyt-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png" width="434" height="254.85576923076923" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:855,&quot;width&quot;:1456,&quot;resizeWidth&quot;:434,&quot;bytes&quot;:159802,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/184229963?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jyt-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png 424w, https://substackcdn.com/image/fetch/$s_!jyt-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png 848w, https://substackcdn.com/image/fetch/$s_!jyt-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png 1272w, https://substackcdn.com/image/fetch/$s_!jyt-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa010c11-564a-43b9-aac1-9368f2b941c8_1706x1002.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The main reason is convenience. At a glance you can know whether a user contacting support is on an old version or not or if a coworker reporting a bug forgot to update. </p><p>It&#8217;s also quite useful to understand version distribution. You can see below that most users on iOS are on version 2025.50.03 (meaning the third iteration of the 50th week of the year) and are progressively upgrading to 2025.51.01:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7ERB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7ERB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png 424w, https://substackcdn.com/image/fetch/$s_!7ERB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png 848w, https://substackcdn.com/image/fetch/$s_!7ERB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png 1272w, https://substackcdn.com/image/fetch/$s_!7ERB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7ERB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:835295,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/184229963?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7ERB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png 424w, https://substackcdn.com/image/fetch/$s_!7ERB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png 848w, https://substackcdn.com/image/fetch/$s_!7ERB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png 1272w, https://substackcdn.com/image/fetch/$s_!7ERB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b497646-51af-4b49-afe8-609c9f2b8a74_3000x1688.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Version distribution, with Android on the left and iOS on the right</figcaption></figure></div><p>One convenient thing you can do is deprecate some routes by looking at the version number to know which clients are older than one year/some duration, here&#8217;s some pseudocode:</p><pre><code>version = request.headers["pr-app-version"]
weeksSinceAppWasReleased = parseWeeksSinceAppRelease(version)
if weeksSinceAppWasReleased &gt;= 52:
   return {error: "APP_OUTDATED", errorMessage: "Your app is outdated, please visit the app store to update"}
</code></pre><p><strong>The downsides</strong></p><p>As App Store version have to be incremental, so once you try this setup, you can&#8217;t go back.</p><p>When we implemented it, I also worried that such long version numbers would be a bit scary for users on the app store listing page, but it seems they don&#8217;t mind. On my side, I&#8217;m still a bit worried when I see Uber&#8217;s super long version number:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LYaP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LYaP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png 424w, https://substackcdn.com/image/fetch/$s_!LYaP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png 848w, https://substackcdn.com/image/fetch/$s_!LYaP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png 1272w, https://substackcdn.com/image/fetch/$s_!LYaP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LYaP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png" width="1456" height="273" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:273,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:85520,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/184229963?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LYaP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png 424w, https://substackcdn.com/image/fetch/$s_!LYaP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png 848w, https://substackcdn.com/image/fetch/$s_!LYaP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png 1272w, https://substackcdn.com/image/fetch/$s_!LYaP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98493915-7b33-4173-a296-5b3fa7d44e0f_2072x388.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Overall, I&#8217;d recommend this setup in a heartbeat if you run a mobile app at scale.</p><p>This article was cross-posted on <a href="https://www.photoroom.com/inside-photoroom/why-you-should-change-your-mobile-app-version-format-to-year-week-iteration?_storyblok_published=133027566450940">Photoroom&#8217;s blog</a></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Our Setup for A/B Testing LLMs with Millions of Users]]></title><description><![CDATA[At Photoroom, we leverage LLMs under the hood of various features: prompt expansion, search, validation.]]></description><link>https://eliot.blog/p/our-setup-for-ab-testing-llms-with</link><guid isPermaLink="false">https://eliot.blog/p/our-setup-for-ab-testing-llms-with</guid><dc:creator><![CDATA[Eliot Andres]]></dc:creator><pubDate>Sun, 04 Jan 2026 19:16:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!00Jq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>At <a href="https://www.photoroom.com/">Photoroom</a>, we leverage LLMs under the hood of various features: prompt expansion, search, validation. We help millions of busy sellers, so we know that every added second of latency means more frustration. Therefore, we&#8217;re constantly tuning the latency-smartness trade-off of a model. A model that does 90% of the job but is 3x faster usually means a better conversion rate.</p><p>We usually run A/B tests comparing: export rate, time to export, paywall conversion, some forms of user ratings, export retention.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://eliot.blog/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Eliot's blog - AI in production! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>This became such a habit that we thought it would be useful to share our setup.</p><h3>Our A/B testing setup</h3><p>On every single request we receive, we fetch the LLM models from our A/B test provider (today we use Amplitude Experiments):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!00Jq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!00Jq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png 424w, https://substackcdn.com/image/fetch/$s_!00Jq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png 848w, https://substackcdn.com/image/fetch/$s_!00Jq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png 1272w, https://substackcdn.com/image/fetch/$s_!00Jq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!00Jq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png" width="1668" height="1042" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1042,&quot;width&quot;:1668,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:158028,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/183363697?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff03b12-95e3-4ab0-b873-417564878103_1766x1042.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!00Jq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png 424w, https://substackcdn.com/image/fetch/$s_!00Jq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png 848w, https://substackcdn.com/image/fetch/$s_!00Jq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png 1272w, https://substackcdn.com/image/fetch/$s_!00Jq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ea45d7-3721-40f6-a896-da14f92bd640_1668x1042.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A payload will usually look like this:</p><pre><code><em>{llm: "google/gemini-2.5-flash", fallbackLLM: "openai/gpt-4.1-nano"}</em></code></pre><p>The benefits of this system are that product managers are independent when picking the models for each feature (assuming the provider has been implemented first). Since the flag is fetched for every user on every request, updates are instantaneous. </p><p><strong>Why a fallback?</strong> The LLM operations are so key to our app that we can&#8217;t be down every time OpenAI/Gemini is down. Therefore, every time we specify a model, we also pick its counterpart at another provider. In case you haven&#8217;t noticed, LLM providers&#8217; status page tend to look like a Christmas tree light strip (underlying how hard it is to run inference at scale):</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pHow!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F810e5758-be18-439a-888c-45853f236328_1388x684.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pHow!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F810e5758-be18-439a-888c-45853f236328_1388x684.png 424w, https://substackcdn.com/image/fetch/$s_!pHow!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F810e5758-be18-439a-888c-45853f236328_1388x684.png 848w, https://substackcdn.com/image/fetch/$s_!pHow!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F810e5758-be18-439a-888c-45853f236328_1388x684.png 1272w, https://substackcdn.com/image/fetch/$s_!pHow!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F810e5758-be18-439a-888c-45853f236328_1388x684.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pHow!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F810e5758-be18-439a-888c-45853f236328_1388x684.png" width="428" height="210.9164265129683" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/810e5758-be18-439a-888c-45853f236328_1388x684.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:684,&quot;width&quot;:1388,&quot;resizeWidth&quot;:428,&quot;bytes&quot;:94899,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/183363697?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F810e5758-be18-439a-888c-45853f236328_1388x684.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pHow!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F810e5758-be18-439a-888c-45853f236328_1388x684.png 424w, https://substackcdn.com/image/fetch/$s_!pHow!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F810e5758-be18-439a-888c-45853f236328_1388x684.png 848w, https://substackcdn.com/image/fetch/$s_!pHow!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F810e5758-be18-439a-888c-45853f236328_1388x684.png 1272w, https://substackcdn.com/image/fetch/$s_!pHow!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F810e5758-be18-439a-888c-45853f236328_1388x684.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">OpenAI&#8217;s status page, screenshotted early 2026</figcaption></figure></div><p>Another reason is that even when the API is up, the error rate is between 0.1% and 1%. So you definitely need a fallback (or some form of retries).</p><p>But wait! <strong>Won&#8217;t the fallback impact the results?</strong> Even when factoring-in outages, the number of requests falling back is below 1-2%, so we usually don&#8217;t take it into account in the A/B test (but we could, by adding the model in the generation event)</p><p>What about added latency? We clocked it at a 20ms median. This is because we call our A/B test provider on every request.</p><h2>Conclusion</h2><p>You&#8217;re most likely using the wrong LLM for your use case. Given how fast the models are improving, you can probably pick a newer generation and it&#8217;ll be either faster or cheaper with the same performance. </p><p>The only way to make this happen at your company is to make it stupidly easy to try out a new model. For that you need 1. instant changes (no deploy needed), 2. reliability and 3. a clear outcome to measure.</p><p><em>This blog post was cross-posted on <a href="https://www.photoroom.com/inside-photoroom/our-setup-for-a-b-testing-llms-with-millions-of-users">Photoroom&#8217;s blog</a></em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://eliot.blog/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Eliot's blog - AI in production! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[The best cable in the world (for developers)]]></title><description><![CDATA[After years of use, I thought I'd share]]></description><link>https://eliot.blog/p/the-best-cable-in-the-world-for-developers</link><guid isPermaLink="false">https://eliot.blog/p/the-best-cable-in-the-world-for-developers</guid><dc:creator><![CDATA[Eliot Andres]]></dc:creator><pubDate>Tue, 30 Dec 2025 20:26:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!k0dQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We all dream of the day when USB-C will become the default standard for all devices. The reality is that you probably still own a few incompatible devices.</p><p>This cable is my &#8220;peace of mind&#8221; go-to: I throw a single one in my bag instead of four different ones. People at the office call it &#8220;the magic cable&#8221;: it can transfer data and power from any device to any device:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!k0dQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!k0dQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg 424w, https://substackcdn.com/image/fetch/$s_!k0dQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg 848w, https://substackcdn.com/image/fetch/$s_!k0dQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!k0dQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!k0dQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg" width="2964" height="3716" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3716,&quot;width&quot;:2964,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2344070,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://eliotandres.substack.com/i/182954664?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca8cec81-8ea2-4aaf-85c2-c7cc31d2f800.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!k0dQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg 424w, https://substackcdn.com/image/fetch/$s_!k0dQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg 848w, https://substackcdn.com/image/fetch/$s_!k0dQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!k0dQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e95066b-f196-4259-b9c2-6afc0b733ec9_2964x3716.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I bought (and lost) a lot of those cables over the years, with no preference on the vendor. Just look for &#8220;multi-usb cable&#8221; online</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aKpH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa07a1ea-60b8-4090-b960-1d616935f168.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aKpH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa07a1ea-60b8-4090-b960-1d616935f168.heic 424w, https://substackcdn.com/image/fetch/$s_!aKpH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa07a1ea-60b8-4090-b960-1d616935f168.heic 848w, https://substackcdn.com/image/fetch/$s_!aKpH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa07a1ea-60b8-4090-b960-1d616935f168.heic 1272w, https://substackcdn.com/image/fetch/$s_!aKpH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa07a1ea-60b8-4090-b960-1d616935f168.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aKpH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa07a1ea-60b8-4090-b960-1d616935f168.heic" width="1456" height="1092" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aa07a1ea-60b8-4090-b960-1d616935f168.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:860749,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliotandres.substack.com/i/182954664?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa07a1ea-60b8-4090-b960-1d616935f168.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aKpH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa07a1ea-60b8-4090-b960-1d616935f168.heic 424w, https://substackcdn.com/image/fetch/$s_!aKpH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa07a1ea-60b8-4090-b960-1d616935f168.heic 848w, https://substackcdn.com/image/fetch/$s_!aKpH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa07a1ea-60b8-4090-b960-1d616935f168.heic 1272w, https://substackcdn.com/image/fetch/$s_!aKpH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa07a1ea-60b8-4090-b960-1d616935f168.heic 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Make sure you don&#8217;t buy the one below however. While they can sometimes charge multiple devices at once, these won&#8217;t be compatible with data transfer (needed for CarPlay, mobile hotspot, app development).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!g0ZK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F688c6ece-f851-4dd0-affe-8d3dc334c976_318x320.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!g0ZK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F688c6ece-f851-4dd0-affe-8d3dc334c976_318x320.jpeg 424w, https://substackcdn.com/image/fetch/$s_!g0ZK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F688c6ece-f851-4dd0-affe-8d3dc334c976_318x320.jpeg 848w, https://substackcdn.com/image/fetch/$s_!g0ZK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F688c6ece-f851-4dd0-affe-8d3dc334c976_318x320.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!g0ZK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F688c6ece-f851-4dd0-affe-8d3dc334c976_318x320.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!g0ZK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F688c6ece-f851-4dd0-affe-8d3dc334c976_318x320.jpeg" width="318" height="320" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/688c6ece-f851-4dd0-affe-8d3dc334c976_318x320.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:320,&quot;width&quot;:318,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;3 in 1 Multi USB Cable Charger Cable Multi Tip 1.2 m Nylon Braided Cable Universal with Micro USB Type C Lightning Connect...&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="3 in 1 Multi USB Cable Charger Cable Multi Tip 1.2 m Nylon Braided Cable Universal with Micro USB Type C Lightning Connect..." title="3 in 1 Multi USB Cable Charger Cable Multi Tip 1.2 m Nylon Braided Cable Universal with Micro USB Type C Lightning Connect..." srcset="https://substackcdn.com/image/fetch/$s_!g0ZK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F688c6ece-f851-4dd0-affe-8d3dc334c976_318x320.jpeg 424w, https://substackcdn.com/image/fetch/$s_!g0ZK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F688c6ece-f851-4dd0-affe-8d3dc334c976_318x320.jpeg 848w, https://substackcdn.com/image/fetch/$s_!g0ZK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F688c6ece-f851-4dd0-affe-8d3dc334c976_318x320.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!g0ZK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F688c6ece-f851-4dd0-affe-8d3dc334c976_318x320.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>]]></content:encoded></item><item><title><![CDATA[Scaling Django to 10+ million active users on a single VM]]></title><description><![CDATA[This article was written at the end of 2024.]]></description><link>https://eliot.blog/p/scaling-django-to-10-million-active-users</link><guid isPermaLink="false">https://eliot.blog/p/scaling-django-to-10-million-active-users</guid><dc:creator><![CDATA[Eliot Andres]]></dc:creator><pubDate>Fri, 15 Nov 2024 20:30:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tSek!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>This article was written at the end of 2024. We have since then migrated our infrastructure to Kubernetes</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GGEw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GGEw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png 424w, https://substackcdn.com/image/fetch/$s_!GGEw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png 848w, https://substackcdn.com/image/fetch/$s_!GGEw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png 1272w, https://substackcdn.com/image/fetch/$s_!GGEw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GGEw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png" width="1456" height="498" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:498,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:153798,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/188067667?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GGEw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png 424w, https://substackcdn.com/image/fetch/$s_!GGEw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png 848w, https://substackcdn.com/image/fetch/$s_!GGEw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png 1272w, https://substackcdn.com/image/fetch/$s_!GGEw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff52eed34-c11a-4c71-90ab-d1b64ee3db4e_1496x512.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We&#8217;ve been using Django Rest Framework (DRF) for 5 years now at <a href="https://www.photoroom.com/">Photoroom</a>. We leverage it to sync users&#8217; projects across clients (iOS, Android, Web), allow team members to collaborate (comments, reactions) and manage billing. </p><p>For the first few years, we scaled this backend on a single VM using a few simple tricks. In this article, we&#8217;ll share our learnings scaling it to 10+ million monthly active users and ~500 queries per second.</p><h1>General architecture</h1><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cid0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cid0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png 424w, https://substackcdn.com/image/fetch/$s_!cid0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png 848w, https://substackcdn.com/image/fetch/$s_!cid0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png 1272w, https://substackcdn.com/image/fetch/$s_!cid0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cid0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png" width="1456" height="484" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:484,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:648078,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/188067667?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cid0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png 424w, https://substackcdn.com/image/fetch/$s_!cid0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png 848w, https://substackcdn.com/image/fetch/$s_!cid0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png 1272w, https://substackcdn.com/image/fetch/$s_!cid0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F899fcd49-124f-4bf2-ba53-0019bd4e7562_2710x900.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The backend architecture we leveraged for the first few years</figcaption></figure></div><p>As shown in the image above, the setup is dead-simple and quite standard: a reverse proxy (Traefik) in front of DRF. Like all of our servers, the VM is behind Cloudflare&#8217;s network to protect it against DDOS and monitor against attacks (more on that later).</p><p>The VM boasts a whopping 60 cores, and it started to be quite busy as you can see:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tSek!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tSek!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png 424w, https://substackcdn.com/image/fetch/$s_!tSek!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png 848w, https://substackcdn.com/image/fetch/$s_!tSek!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png 1272w, https://substackcdn.com/image/fetch/$s_!tSek!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tSek!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png" width="1456" height="400" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:400,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:505943,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/188067667?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tSek!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png 424w, https://substackcdn.com/image/fetch/$s_!tSek!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png 848w, https://substackcdn.com/image/fetch/$s_!tSek!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png 1272w, https://substackcdn.com/image/fetch/$s_!tSek!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03cb6f5e-12dd-4a9b-8289-4e3106270733_2894x796.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Screenshot of htop opened during peak traffic time</em></figcaption></figure></div><p>For background tasks, we leverage Celery. We have 3 levels of priorities for our workers:</p><ul><li><p><strong>Blocking (P1)</strong>: for tasks that require an response before the request completes, with a latency target of ~100ms. Example: uploading a few assets in parallel before responding</p></li><li><p><strong>High priority</strong>: for tasks that need to complete in a timely manner but can run late from time to time. Examples: sending notifications after an action is completed or sending events for analytics</p></li><li><p><strong>Background</strong>: for long running background tasks, some of which can run for a long time (up to a few minutes). For example: sending aggregated analytics, periodic cleanups.</p></li></ul><h1>Performance &amp; monitoring</h1><p>If you&#8217;ve played with Django, you probably already know to leverage <code>select_related() / prefetch_related()</code> and carefully add indexes before deploying. But all the carefulness in the world won&#8217;t protect you against unexpectedly slow queries. Responses might be fast when the first requests start hitting a route, then get much slower as the table grows.</p><p>To prevent those issues, we always carefully monitor for any slowness using an APM (Application Performance Monitoring, for instance Datadog or Dynatrace). Each request is traced and we can analyze the slow paths. Slowness stems from too many many factors: from slow database queries, unoptimized libraries, external services that misbehave.</p><p>We have alerts on latency, error rate and throughput. The first 2 are thresholds while the latter leverages anomaly detection. We also have a strict no-error-policy on the Stripe webhooks and get alerted if there&#8217;s a single error, regardless of the reason.</p><p>The practice of always analyzing and monitoring results in a rather decent performance, with a large majority of the requests below 100ms:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Mwy4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Mwy4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png 424w, https://substackcdn.com/image/fetch/$s_!Mwy4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png 848w, https://substackcdn.com/image/fetch/$s_!Mwy4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png 1272w, https://substackcdn.com/image/fetch/$s_!Mwy4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Mwy4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png" width="1112" height="504" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:504,&quot;width&quot;:1112,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:161045,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/188067667?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Mwy4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png 424w, https://substackcdn.com/image/fetch/$s_!Mwy4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png 848w, https://substackcdn.com/image/fetch/$s_!Mwy4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png 1272w, https://substackcdn.com/image/fetch/$s_!Mwy4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ec0f-ab65-4d81-89fd-77a16876d8b6_1112x504.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Screenshot of the latency breakdown, all routes over 2 days</em></figcaption></figure></div><h1>Authentication</h1><p>In the early days, we picked Firebase for authentication. It saved us countless hours of implementation and maintenance for login mechanism on our 3 platforms (iOS, Android, web). And most likely avoided a few security vulnerabilities. But we ran into a limitation.</p><p>As we reached the 100M downloads mark, we ran into a surprise: <strong>you can&#8217;t have more than 100M anonymous users in Firebase</strong>. We leverage anonymous auth to allow our users to explore the app without logging-in, while maintaining a stable user identifier across all of our services. At some point we also made the mistake of adding Firebase auth on our website, adding a few millions visitors to the tally.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tVn1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tVn1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png 424w, https://substackcdn.com/image/fetch/$s_!tVn1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png 848w, https://substackcdn.com/image/fetch/$s_!tVn1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png 1272w, https://substackcdn.com/image/fetch/$s_!tVn1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tVn1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png" width="1286" height="394" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:394,&quot;width&quot;:1286,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:69577,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/188067667?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tVn1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png 424w, https://substackcdn.com/image/fetch/$s_!tVn1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png 848w, https://substackcdn.com/image/fetch/$s_!tVn1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png 1272w, https://substackcdn.com/image/fetch/$s_!tVn1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc2c0848-5737-47d5-9b93-77ac40d9e7f5_1286x394.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Firebase Auth&#8217;s documentation, accompanied by an emoji depiction of the author&#8217;s face when he discovered the limitation</em></figcaption></figure></div><p>We now have alerts and deletion scripts to remove anonymous users who haven&#8217;t been active for the past 3 months. Knowing who has been active required a few changes: we didn&#8217;t have any reason to store data from non-registered users in our backend. We now have a custom routes that monitors active users.</p><p>As it&#8217;s relying on Google&#8217;s services, our app is also mostly unusable in mainland China. I&#8217;m also a bit worried about adding OIDC and SAML: they are part of &#8220;Identify Platform&#8221;, which would cost us as hefty $70k / month (list price)</p><p>Despite those limitations, we don&#8217;t regret picking Firebase as it has proven reliable and a huge time-saver.</p><h1>Leveraging Cloudflare&#8217;s cache</h1><p>We serve around 600TB of data per month, mostly images. This backend proxies them, but we&#8217;re in the process of splitting this use case into an independent FastAPI service to ease up on the load. Most of the image requests don&#8217;t reach Django, as they are cached by Cloudflare. If we were to use Vercel for the same volume, it would cost us $150k/month just for the traffic [1].</p><p>We also cache the content of the homepage of the app, so it is close to the user and the first load is quicker. This sometimes had unexpected consequences: someone updates the homepage from our backoffice, accidentally adds botched content/json, goes back home. A few hours later the cache refreshes and users all around the world start reporting crashes on startup &#128546;.</p><p>An astute reader might raise that an app should never crash decoding JSON. I would oppose that we also use that JSON for rendering images and fonts dynamically, which tends to be more error-prone. Regardless, we&#8217;ve since taken actions to much strongly validate the content. We also ensure that Photoroom employees get served un-cached content to be able to spot any issue faster. We also have a Slack command to bust the Cloudflare cache in case it got poisoned with bad content.</p><h1>Scaling Postgresql</h1><p>Most people on Hacker News will tell you that Postgres is the only database you&#8217;ll need. It&#8217;s been true for us. Scaling has mostly been a breeze and it has been mostly forgiving. We still had implement a few tricks.</p><p><strong>Trick 1</strong>: this one is obvious, but we use a managed DB. Duplicating the DB for test is a breeze. Figma did this, scaling to the maximum of RDS until they were large enough to hire DB experts[3]. Life is too short to manage your database</p><p><strong>Trick 2</strong>: We disabled long running queries. There is generally no reason for a mobile app to make the user wait more than 15 seconds (user would most likely be gone by then). If not monitored, long running queries can block migrations and other queries. Therefore we prevent queries with the flag <code>POSTGRESQL_STATEMENT_TIMEOUT</code>. Don&#8217;t forget to disable the flag for migrations however.</p><p><strong>Trick 3:</strong> We disabled counts on pagination. Indeed, running a count in Postgres, especially on fast-changing data, can be quite costly. Most very large apps do so, for instance Gmail. We simply query <code>pageSize + 1</code> items to let the client know if there&#8217;s a <code>next</code> page [2]</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0fsu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0fsu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png 424w, https://substackcdn.com/image/fetch/$s_!0fsu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png 848w, https://substackcdn.com/image/fetch/$s_!0fsu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png 1272w, https://substackcdn.com/image/fetch/$s_!0fsu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0fsu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png" width="1456" height="296" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:296,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:111481,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/188067667?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0fsu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png 424w, https://substackcdn.com/image/fetch/$s_!0fsu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png 848w, https://substackcdn.com/image/fetch/$s_!0fsu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png 1272w, https://substackcdn.com/image/fetch/$s_!0fsu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc5d6e8d-fe19-44c5-9c4a-35062041c555_1488x302.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"><em>Example of Gmail showing &#8220;of many&#8221; instead of the total count</em></figcaption></figure></div><p><strong>Trick 4</strong>: We acknowledge that we can&#8217;t hire people who are both backend experts and database tuners, so we work with an agency with experts on the topic. They tend to be expensive and the level of competency of the person assigned to you varies, but it&#8217;s overall useful</p><p><strong>Trick 5</strong>: Periodic backups with point in time recovery. In case someone messes up badly, we can revert to a few minutes before the incident. Knowing this makes me sleep better at night.</p><p>Our dream setup would be to be able to replicate the database with anonymized data + replicate a realistic load pattern, but we have yet to find a simple way to do this</p><h2>Collaborating with developers on 3 platforms</h2><p>Photoroom is available on iOS, Android and the web. While we&#8217;re working hard on moving most of the REST communication in <a href="https://www.photoroom.com/inside-photoroom/building-google-docs-like-live-collaboration-for-a-cross-platform-app-used-by-millions-in-rust-">our Rust multi-platform engine</a>, for a little while each platform still has to write code to communicate with the Django backend.</p><p>In the early day, we simply put specs on Notion. Unsurprisingly, this didn&#8217;t work very well. We now expose OpenAPI specs, documenting the routes, parameters and responses. We leverage <a href="https://drf-spectacular.readthedocs.io/en/latest/">drf-spectacular</a> for this. We also stick to the REST patterns as much as possible, which makes the inner workings of the API more predictable.</p><p>We can also monitor the traffic the apps send through custom request headers. For complex serialized json, we also add the name of the platform who serialized it in case some botched JSON goes through the schema validation (botched can also mean non-existing assets, wrong ordering, inconsistent positioning, things that are harder to validate)</p><p>Headers to know the platform and who serialized a project. <code>pr-app-version</code> and <code>pr-platform</code></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JWYL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JWYL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png 424w, https://substackcdn.com/image/fetch/$s_!JWYL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png 848w, https://substackcdn.com/image/fetch/$s_!JWYL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png 1272w, https://substackcdn.com/image/fetch/$s_!JWYL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JWYL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png" width="1456" height="270" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:270,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:56262,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://eliot.blog/i/188067667?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JWYL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png 424w, https://substackcdn.com/image/fetch/$s_!JWYL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png 848w, https://substackcdn.com/image/fetch/$s_!JWYL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png 1272w, https://substackcdn.com/image/fetch/$s_!JWYL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a307e5-29e2-40a6-90e8-3500ed7fad72_2048x380.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"><em>Breakdown of the </em><code>pr-platform</code><em> header. pg represents our Rust cross-platform engine</em></figcaption></figure></div><h2>Mistakes we made</h2><ul><li><p>One day we DDOSed ourselves when a developer misconfigured a deployment and it kept calling a route every 10ms</p></li><li><p>We periodically run cleanups for inactive free users&#8217; data. The homepage content of the app is owned by user 0 in the DB. The first time we ran the cleanup, we accidentally deleted the official content since user 0 hadn&#8217;t been &#8220;active&#8221; for a while.</p></li><li><p>On another Django project, we accidentally deployed it in another region than the database it was talking to. If you&#8217;re looking for ways to make all your REST requests 200ms slower, I recommend this technique</p></li></ul><h2>Good decisions we took</h2><ul><li><p>Adding an APM from the very first day, allowing us to debug and investigate slow queries. Today, we couldn&#8217;t leave without it</p></li><li><p>Adding a linter to prevent non-concurrent indexes adding. Adding index without the <code>CONCURRENTLY</code> keyword locks the table, leading to unnecessary downtime.</p></li><li><p>Dedicating time to continuously cleaning and improving the codebase + writing a post mortem on every downtime</p></li></ul><h2>Conclusion and what&#8217;s next</h2><p>Overall, Django Rest Framework has been reliable and very forgiving. As Photoroom is crossing the 200 million mobile downloads mark, most our challenges are ahead. Among others, we&#8217;ll need to:</p><ul><li><p>Update the deployment procedure, using a single VM won&#8217;t scale much more</p></li><li><p>Partition or rework the way we store projects, with the largest Postgresql table being close to 1.5TB</p></li><li><p>Update our architecture to support real-time collaboration on top of Django</p></li></ul><p>If this challenge is of interest to you, we&#8217;re looking for a Django backend engineer (remote in Europe). Your scope will include this backend as well as the backends that power GenAI features in Photoroom. Email eliot@photoroom.com with your resume, along with a Django trick you learned over the year. You must have extensive Django experience to apply.</p><p>[1] Vercel charges us an hefty $250 / TB for our traffic country mix. 250 * 600TB = $150k. Those are list prices, you might be able to get discounts.</p><p>[2] You can view more tricks like this one in <a href="https://www.youtube.com/watch?v=A_bkbAv9TQs">Squeezing Django performance for 14.9 million users on WhatsApp</a> by Rudi Giesler</p><p>[3] <a href="https://www.figma.com/blog/how-figmas-databases-team-lived-to-tell-the-scale/">https://www.figma.com/blog/how-figmas-databases-team-lived-to-tell-the-scale/</a></p>]]></content:encoded></item><item><title><![CDATA[Building a 42-inch E Ink Art Frame]]></title><description><![CDATA[Recently, we wanted to find a way to display Generative AI art in our office at Photoroom.]]></description><link>https://eliot.blog/p/e-ink-frame</link><guid isPermaLink="false">https://eliot.blog/p/e-ink-frame</guid><dc:creator><![CDATA[Eliot Andres]]></dc:creator><pubDate>Sat, 11 Mar 2023 13:03:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!WpVx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, we wanted to find a way to display Generative AI art in our office at Photoroom. A large TV would have done the job, but we wanted to go for something more original.</p><p>So when someone informed me that the E Ink Corporation was selling <a href="https://shopkits.eink.com/en/product/detail/42''MonochromeePaperDisplay(VB3300-RBA)">42-inch E Ink panels</a>, I was instantly nerd-sniped. That was the perfect project to fuel my non-traditional display addiction. After the <a href="https://www.photoroom.com/inside-photoroom/photoroom-hackathon-3">flip-dot display salvaged from a UK bus,</a> the quest for an even bigger build was on.</p><h1>The result</h1><p>The frame changing from one image to another. <em>The GIF above doesn&#8217;t help with quality, <a href="https://www.youtube.com/shorts/v3bHBpHfCyw">HD video available here</a></em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LKIo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d52f09-2695-42e9-ad90-2af32838b62d_255x455.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LKIo!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d52f09-2695-42e9-ad90-2af32838b62d_255x455.gif 424w, https://substackcdn.com/image/fetch/$s_!LKIo!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d52f09-2695-42e9-ad90-2af32838b62d_255x455.gif 848w, https://substackcdn.com/image/fetch/$s_!LKIo!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d52f09-2695-42e9-ad90-2af32838b62d_255x455.gif 1272w, https://substackcdn.com/image/fetch/$s_!LKIo!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d52f09-2695-42e9-ad90-2af32838b62d_255x455.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LKIo!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d52f09-2695-42e9-ad90-2af32838b62d_255x455.gif" width="320" height="570.9803921568628" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/36d52f09-2695-42e9-ad90-2af32838b62d_255x455.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:455,&quot;width&quot;:255,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!LKIo!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d52f09-2695-42e9-ad90-2af32838b62d_255x455.gif 424w, https://substackcdn.com/image/fetch/$s_!LKIo!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d52f09-2695-42e9-ad90-2af32838b62d_255x455.gif 848w, https://substackcdn.com/image/fetch/$s_!LKIo!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d52f09-2695-42e9-ad90-2af32838b62d_255x455.gif 1272w, https://substackcdn.com/image/fetch/$s_!LKIo!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d52f09-2695-42e9-ad90-2af32838b62d_255x455.gif 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Cables are missing in this picture</em></figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WpVx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WpVx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg 424w, https://substackcdn.com/image/fetch/$s_!WpVx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg 848w, https://substackcdn.com/image/fetch/$s_!WpVx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!WpVx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WpVx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg" width="1000" height="1038" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1038,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!WpVx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg 424w, https://substackcdn.com/image/fetch/$s_!WpVx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg 848w, https://substackcdn.com/image/fetch/$s_!WpVx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!WpVx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb64cf009-543d-49ae-99c1-3980a45231f5_1000x1038.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>First version. In the process of building it, I broke the top half of the display</em></figcaption></figure></div><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_Mnu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98a2a855-2431-4aa0-acda-3c9722ded076_1230x980.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_Mnu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98a2a855-2431-4aa0-acda-3c9722ded076_1230x980.jpeg 424w, https://substackcdn.com/image/fetch/$s_!_Mnu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98a2a855-2431-4aa0-acda-3c9722ded076_1230x980.jpeg 848w, https://substackcdn.com/image/fetch/$s_!_Mnu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98a2a855-2431-4aa0-acda-3c9722ded076_1230x980.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!_Mnu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98a2a855-2431-4aa0-acda-3c9722ded076_1230x980.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_Mnu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98a2a855-2431-4aa0-acda-3c9722ded076_1230x980.jpeg" width="1230" height="980" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/98a2a855-2431-4aa0-acda-3c9722ded076_1230x980.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:980,&quot;width&quot;:1230,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!_Mnu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98a2a855-2431-4aa0-acda-3c9722ded076_1230x980.jpeg 424w, https://substackcdn.com/image/fetch/$s_!_Mnu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98a2a855-2431-4aa0-acda-3c9722ded076_1230x980.jpeg 848w, https://substackcdn.com/image/fetch/$s_!_Mnu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98a2a855-2431-4aa0-acda-3c9722ded076_1230x980.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!_Mnu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98a2a855-2431-4aa0-acda-3c9722ded076_1230x980.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h1>The process</h1><h2>Sourcing components</h2><p>Some advanced Google-fu was used to find a supplier shipping to Europe. Minimum order quantity: 3 pieces. After a bit of back and forth, the components arrived.</p><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yanE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82168e8a-433a-4a63-b3cb-413095a78c32_1230x881.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yanE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82168e8a-433a-4a63-b3cb-413095a78c32_1230x881.jpeg 424w, https://substackcdn.com/image/fetch/$s_!yanE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82168e8a-433a-4a63-b3cb-413095a78c32_1230x881.jpeg 848w, https://substackcdn.com/image/fetch/$s_!yanE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82168e8a-433a-4a63-b3cb-413095a78c32_1230x881.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!yanE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82168e8a-433a-4a63-b3cb-413095a78c32_1230x881.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yanE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82168e8a-433a-4a63-b3cb-413095a78c32_1230x881.jpeg" width="1230" height="881" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/82168e8a-433a-4a63-b3cb-413095a78c32_1230x881.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:881,&quot;width&quot;:1230,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:252499,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!yanE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82168e8a-433a-4a63-b3cb-413095a78c32_1230x881.jpeg 424w, https://substackcdn.com/image/fetch/$s_!yanE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82168e8a-433a-4a63-b3cb-413095a78c32_1230x881.jpeg 848w, https://substackcdn.com/image/fetch/$s_!yanE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82168e8a-433a-4a63-b3cb-413095a78c32_1230x881.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!yanE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82168e8a-433a-4a63-b3cb-413095a78c32_1230x881.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Can you guess it&#8217;s fragile?</em></figcaption></figure></div><p>The supplier provided the displays as well as the necessary driving board.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2vyi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6c7bc6-2133-432b-baff-12ca378d4749_1230x1255.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2vyi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6c7bc6-2133-432b-baff-12ca378d4749_1230x1255.jpeg 424w, https://substackcdn.com/image/fetch/$s_!2vyi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6c7bc6-2133-432b-baff-12ca378d4749_1230x1255.jpeg 848w, https://substackcdn.com/image/fetch/$s_!2vyi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6c7bc6-2133-432b-baff-12ca378d4749_1230x1255.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!2vyi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6c7bc6-2133-432b-baff-12ca378d4749_1230x1255.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2vyi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6c7bc6-2133-432b-baff-12ca378d4749_1230x1255.jpeg" width="1230" height="1255" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a6c7bc6-2133-432b-baff-12ca378d4749_1230x1255.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1255,&quot;width&quot;:1230,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!2vyi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6c7bc6-2133-432b-baff-12ca378d4749_1230x1255.jpeg 424w, https://substackcdn.com/image/fetch/$s_!2vyi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6c7bc6-2133-432b-baff-12ca378d4749_1230x1255.jpeg 848w, https://substackcdn.com/image/fetch/$s_!2vyi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6c7bc6-2133-432b-baff-12ca378d4749_1230x1255.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!2vyi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6c7bc6-2133-432b-baff-12ca378d4749_1230x1255.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h1>Framing</h1><p>While the pink packaging certainly has its own charm, we decided to go for something more minimalist. Finding a frame shop that could handle this &#8220;special&#8221; project was not easy. Some straight-out didn&#8217;t answer but one of them was interested in that unconventional build.</p><p>So we (well, mostly he) set on to custom build a framing system that could enclose the panel without breaking it and without using glue to make repairs / adjustments easy.</p><p>The first build we created didn&#8217;t turn out great: the display was slipping between the layers. In the second version, we found a way to keep it sturdy.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XsTQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F090d077c-8711-41a0-99a2-bbcc12c45aa1_3024x3151.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XsTQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F090d077c-8711-41a0-99a2-bbcc12c45aa1_3024x3151.jpeg 424w, https://substackcdn.com/image/fetch/$s_!XsTQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F090d077c-8711-41a0-99a2-bbcc12c45aa1_3024x3151.jpeg 848w, https://substackcdn.com/image/fetch/$s_!XsTQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F090d077c-8711-41a0-99a2-bbcc12c45aa1_3024x3151.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!XsTQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F090d077c-8711-41a0-99a2-bbcc12c45aa1_3024x3151.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XsTQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F090d077c-8711-41a0-99a2-bbcc12c45aa1_3024x3151.jpeg" width="1456" height="1517" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/090d077c-8711-41a0-99a2-bbcc12c45aa1_3024x3151.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1517,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!XsTQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F090d077c-8711-41a0-99a2-bbcc12c45aa1_3024x3151.jpeg 424w, https://substackcdn.com/image/fetch/$s_!XsTQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F090d077c-8711-41a0-99a2-bbcc12c45aa1_3024x3151.jpeg 848w, https://substackcdn.com/image/fetch/$s_!XsTQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F090d077c-8711-41a0-99a2-bbcc12c45aa1_3024x3151.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!XsTQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F090d077c-8711-41a0-99a2-bbcc12c45aa1_3024x3151.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tQ-D!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc35a5114-a97f-41f3-9ccb-3065eb1ae234_2360x2720.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tQ-D!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc35a5114-a97f-41f3-9ccb-3065eb1ae234_2360x2720.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tQ-D!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc35a5114-a97f-41f3-9ccb-3065eb1ae234_2360x2720.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tQ-D!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc35a5114-a97f-41f3-9ccb-3065eb1ae234_2360x2720.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tQ-D!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc35a5114-a97f-41f3-9ccb-3065eb1ae234_2360x2720.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tQ-D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc35a5114-a97f-41f3-9ccb-3065eb1ae234_2360x2720.jpeg" width="1456" height="1678" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c35a5114-a97f-41f3-9ccb-3065eb1ae234_2360x2720.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1678,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!tQ-D!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc35a5114-a97f-41f3-9ccb-3065eb1ae234_2360x2720.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tQ-D!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc35a5114-a97f-41f3-9ccb-3065eb1ae234_2360x2720.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tQ-D!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc35a5114-a97f-41f3-9ccb-3065eb1ae234_2360x2720.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tQ-D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc35a5114-a97f-41f3-9ccb-3065eb1ae234_2360x2720.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Controlling the display</h2><p><em>The display controller can be talked to using USB, so I added a Raspberry Pi on the back. It exposes a small webserver that can receive images to display.Back of the frame. Notice how the ribbon cables don&#8217;t align: I think I picked the wrong controller board variant</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2Ff5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc682b3ac-b6ed-464d-806d-47b941f11d22_1692x708.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2Ff5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc682b3ac-b6ed-464d-806d-47b941f11d22_1692x708.png 424w, https://substackcdn.com/image/fetch/$s_!2Ff5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc682b3ac-b6ed-464d-806d-47b941f11d22_1692x708.png 848w, https://substackcdn.com/image/fetch/$s_!2Ff5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc682b3ac-b6ed-464d-806d-47b941f11d22_1692x708.png 1272w, https://substackcdn.com/image/fetch/$s_!2Ff5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc682b3ac-b6ed-464d-806d-47b941f11d22_1692x708.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2Ff5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc682b3ac-b6ed-464d-806d-47b941f11d22_1692x708.png" width="1456" height="609" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c682b3ac-b6ed-464d-806d-47b941f11d22_1692x708.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:609,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!2Ff5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc682b3ac-b6ed-464d-806d-47b941f11d22_1692x708.png 424w, https://substackcdn.com/image/fetch/$s_!2Ff5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc682b3ac-b6ed-464d-806d-47b941f11d22_1692x708.png 848w, https://substackcdn.com/image/fetch/$s_!2Ff5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc682b3ac-b6ed-464d-806d-47b941f11d22_1692x708.png 1272w, https://substackcdn.com/image/fetch/$s_!2Ff5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc682b3ac-b6ed-464d-806d-47b941f11d22_1692x708.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0EnT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dd18a59-221c-4d5a-be5c-8fea2f5c9fcf_1000x1148.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0EnT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dd18a59-221c-4d5a-be5c-8fea2f5c9fcf_1000x1148.jpeg 424w, https://substackcdn.com/image/fetch/$s_!0EnT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dd18a59-221c-4d5a-be5c-8fea2f5c9fcf_1000x1148.jpeg 848w, https://substackcdn.com/image/fetch/$s_!0EnT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dd18a59-221c-4d5a-be5c-8fea2f5c9fcf_1000x1148.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!0EnT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dd18a59-221c-4d5a-be5c-8fea2f5c9fcf_1000x1148.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0EnT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dd18a59-221c-4d5a-be5c-8fea2f5c9fcf_1000x1148.jpeg" width="1000" height="1148" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4dd18a59-221c-4d5a-be5c-8fea2f5c9fcf_1000x1148.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1148,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!0EnT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dd18a59-221c-4d5a-be5c-8fea2f5c9fcf_1000x1148.jpeg 424w, https://substackcdn.com/image/fetch/$s_!0EnT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dd18a59-221c-4d5a-be5c-8fea2f5c9fcf_1000x1148.jpeg 848w, https://substackcdn.com/image/fetch/$s_!0EnT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dd18a59-221c-4d5a-be5c-8fea2f5c9fcf_1000x1148.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!0EnT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dd18a59-221c-4d5a-be5c-8fea2f5c9fcf_1000x1148.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Preprocessing images</h2><p>The display can only display 16 levels of gray. Displaying images without preprocessing leads to a blocky pattern on gradients in images. Thankfully a few techniques exist. One of them, closer to dark magic than science to me, is called <a href="https://ieeexplore.ieee.org/document/3288">Blue Noise dithering</a>. It consist of adding a blue noise pattern to an image and then thresholding. Simple yet impressive, see for yourself.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p1Je!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6553959a-111c-4eff-933e-3ee58100e4fe_1024x512.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p1Je!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6553959a-111c-4eff-933e-3ee58100e4fe_1024x512.jpeg 424w, https://substackcdn.com/image/fetch/$s_!p1Je!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6553959a-111c-4eff-933e-3ee58100e4fe_1024x512.jpeg 848w, https://substackcdn.com/image/fetch/$s_!p1Je!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6553959a-111c-4eff-933e-3ee58100e4fe_1024x512.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!p1Je!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6553959a-111c-4eff-933e-3ee58100e4fe_1024x512.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p1Je!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6553959a-111c-4eff-933e-3ee58100e4fe_1024x512.jpeg" width="1024" height="512" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6553959a-111c-4eff-933e-3ee58100e4fe_1024x512.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:512,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!p1Je!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6553959a-111c-4eff-933e-3ee58100e4fe_1024x512.jpeg 424w, https://substackcdn.com/image/fetch/$s_!p1Je!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6553959a-111c-4eff-933e-3ee58100e4fe_1024x512.jpeg 848w, https://substackcdn.com/image/fetch/$s_!p1Je!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6553959a-111c-4eff-933e-3ee58100e4fe_1024x512.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!p1Je!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6553959a-111c-4eff-933e-3ee58100e4fe_1024x512.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Before/after dithering using blue noise. Notice the pattern in the sky</em></figcaption></figure></div><h2>Displaying images</h2><p>If you have ever used a kindle, you&#8217;ll know that every few pages it refreshes itself to avoid ghosting. We had the same problem where the previous image would appear slighly faded out, mixed with the new image. The trick is to run a full black then full white image. We found that running 2 full white images did a good enough job, without disrupting the experience too much (<a href="https://www.youtube.com/shorts/v3bHBpHfCyw">see video</a>)</p><h1>Next steps</h1><p>The first version of this project now sits in the office. There are a few ideas we&#8217;d like to try:</p><ul><li><p>Make it battery-powered: right now it still requires a power cord. It would allow putting it on a wall without cables</p></li><li><p>Ask ChatGPT to generate prompts for us, turning it into our very own art curator</p></li></ul><h1>Acknowledgements</h1><p>A huge thank you to Charly for the idea and support in this building process, to Nico for the framing and to Florian for the dithering code.</p><p><em>This blog post has been <a href="https://news.ycombinator.com/item?id=37835995">discussed on Hacker News</a></em></p>]]></content:encoded></item></channel></rss>