<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tom den Boon</title>
    <description>The latest articles on DEV Community by Tom den Boon (@tom_denboon_8633d24a0b84).</description>
    <link>https://dev.to/tom_denboon_8633d24a0b84</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2192858%2F7d410444-fe1e-4b5b-b089-ac96eed9fffc.jpg</url>
      <title>DEV Community: Tom den Boon</title>
      <link>https://dev.to/tom_denboon_8633d24a0b84</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tom_denboon_8633d24a0b84"/>
    <language>en</language>
    <item>
      <title>I got tired of re-screenshotting my app every time I made a change . So I built a workflow that does it for me.</title>
      <dc:creator>Tom den Boon</dc:creator>
      <pubDate>Mon, 06 Apr 2026 11:37:29 +0000</pubDate>
      <link>https://dev.to/tom_denboon_8633d24a0b84/i-got-tired-of-re-screenshotting-my-app-every-time-i-made-a-change-so-i-built-a-workflow-that-2958</link>
      <guid>https://dev.to/tom_denboon_8633d24a0b84/i-got-tired-of-re-screenshotting-my-app-every-time-i-made-a-change-so-i-built-a-workflow-that-2958</guid>
      <description>&lt;p&gt;Ship a mobile app and suddenly you need screenshots everywhere. App Store listings. Your website's &lt;a href="https://www.volm.app/features" rel="noopener noreferrer"&gt;feature pages&lt;/a&gt;. FAQs. Social media. Each one lives in a different place, and each one goes stale the moment you push an update.&lt;/p&gt;

&lt;p&gt;My app's theme engine (powered by &lt;a href="https://monkeytype.com/" rel="noopener noreferrer"&gt;Monkeytype&lt;/a&gt;) supports &lt;strong&gt;190 themes&lt;/strong&gt;. I'm working towards making the website available in all of them, which means every screenshot on every feature page needs a variant per theme. That's 50 screenshots across 13 features. At 190 themes, that's &lt;strong&gt;9,500 screenshots&lt;/strong&gt; total. And that number grows with every new feature and every new theme added.&lt;/p&gt;

&lt;p&gt;I needed the screenshots to live in the codebase, regenerate on demand, and flow into everything downstream without me touching Canva or Figma.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup: A TypeScript Monorepo
&lt;/h2&gt;

&lt;p&gt;The prerequisite is a monorepo. Mine is TypeScript with a React Native app alongside a web app, but the principle applies anywhere your mobile code, web code, and asset pipeline can share context.&lt;/p&gt;

&lt;p&gt;The relevant structure looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;monorepo/
├── apps/
│   ├── mobile/       # React Native app
│   ├── web/          # Website
│   ├── remotion/     # Remotion compositions
│   └── maestro/      # Test flows + screenshot automation
├── packages/         # Shared UI, themes, config
└── assets/           # Screenshots, icons, media
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important bit: themes, typography tokens, SVG assets (muscle illustrations, exercise videos, etc.), and the component library are all importable from anywhere in the project. That matters later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maestro
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://maestro.mobile.dev/" rel="noopener noreferrer"&gt;Maestro&lt;/a&gt; is a mobile UI testing framework. I use it for testing, but it has a feature most people overlook: &lt;strong&gt;it can take screenshots as part of any test run&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here's what I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wrote a flow for every &lt;a href="https://www.volm.app/features" rel="noopener noreferrer"&gt;feature&lt;/a&gt; in the app.&lt;/li&gt;
&lt;li&gt;Added screenshot commands at the key moments in each flow.&lt;/li&gt;
&lt;li&gt;Built a deterministic seed that makes every screenshot consistent and reproducible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flow used for the cover image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.tom.logro&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;launchApp&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;runFlow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./setup/seed-data.yaml&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;tapOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tab-progress"&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;takeScreenshot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;screenshots/features/progress-dashboard/${THEME_ID}/dashboard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Seed
&lt;/h3&gt;

&lt;p&gt;The seed is what makes this work. Before any flow runs, a setup script populates the app with deterministic data: specific exercises, programs, workout history, and stats. Because the data is idempotent, screenshots come out identical every run. Same numbers, same layouts, same everything.&lt;/p&gt;

&lt;p&gt;Each flow opens the app with a deep link that triggers the seed and sets the theme:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.tom.logro&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;openLink&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;volm://?seed=true&amp;amp;theme=${THEME_ID}"&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;waitForAnimationToEnd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60000&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertVisible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tab-home'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;seed=true&lt;/code&gt; parameter tells the app to populate itself with deterministic data on launch. &lt;code&gt;THEME_ID&lt;/code&gt; is passed in when running the suite, so the same flows produce screenshots for any theme.&lt;/p&gt;

&lt;p&gt;This also means the screenshots look good, because the data was &lt;em&gt;designed&lt;/em&gt; to look good. You're not screenshotting a blank app or a test account with three entries.&lt;/p&gt;

&lt;p&gt;For theme switching, I pass a theme parameter when running the flows. Maestro runs the full suite once per theme, and I get a complete set of screenshots for each.&lt;/p&gt;

&lt;p&gt;Now when I update a screen, I run the Maestro flows and everything updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;App Store screenshots&lt;/strong&gt; regenerate automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The website&lt;/strong&gt; pulls the same images for &lt;a href="https://www.volm.app/features" rel="noopener noreferrer"&gt;feature pages&lt;/a&gt; and FAQs, across all 190 themes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Everything stays in sync&lt;/strong&gt; because there's one source of truth: the flows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No re-screenshotting. No re-exporting. No "wait, is this the latest version?" I trigger this manually for now. It's not wired into CI. But even running it by hand saves a stupid amount of time. I can be genuinely confident in this part of the pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat: Seeded Data Doesn't Always Look Real
&lt;/h3&gt;

&lt;p&gt;The tricky part is that the flow has only been running for seconds. So your "active workout" screenshot shows a timer at 0:10 because Maestro literally just navigated there. Real users don't have a workout that's ten seconds old. You can work around some of this with clever seed design, but certain screens will always betray the fact that no human was actually using the app. It's a trade-off I'm fine with, but worth knowing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remotion
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.remotion.dev/" rel="noopener noreferrer"&gt;Remotion&lt;/a&gt; is a React-based framework for generating images and video programmatically. Because compositions are just React components, they can import everything from the monorepo: design tokens, components, and those Maestro-generated screenshots.&lt;/p&gt;

&lt;p&gt;So far I've used it for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;App Store screenshot slides.&lt;/strong&gt; Composing the raw screenshots into device frames with marketing copy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One social media post.&lt;/strong&gt; A branded carousel for Instagram. I've only made one so far, so I can't claim this is a proven workflow, but I was happy with how it turned out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The cover image for this post.&lt;/strong&gt; The Maestro flow above ran once per theme, Remotion composed all 190 screenshots into a single grid sorted by color.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remotion without an LLM in the loop is painful compared to visual tools. The feedback cycle is just too slow. Where it works is when you point something like Claude Code at your repo and iterate on compositions, because the LLM already has access to your actual tokens and assets. That makes the loop fast enough to be worth it. Without that, I'd probably just use Canva.&lt;/p&gt;

&lt;p&gt;The real value isn't the output quality. It's that the assets are &lt;em&gt;generated from the same source&lt;/em&gt; as everything else. Update the app, run the flows, regenerate the Remotion compositions. Nothing drifts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pipeline
&lt;/h2&gt;

&lt;p&gt;Here's how it connects:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnmgdj6s60n0ln9bpw8p5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnmgdj6s60n0ln9bpw8p5.png" alt="Screenshot automation pipeline: develop feature, run Maestro flows, screenshots stored in repo, then consumed by Remotion and the website"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One repo. One set of screenshots. No duplicated assets. Update anything upstream, everything downstream regenerates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Maestro setup is a real investment.&lt;/strong&gt; Building deterministic test data and configuring flows for every screen took serious time. Keeping the seed up to date as the app evolves is ongoing work too. This is infrastructure, not a weekend project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remotion is only practical with AI tooling.&lt;/strong&gt; If you're not using an LLM to write and iterate on compositions, the feedback loop is too slow compared to Canva or Figma. They exist for a reason.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's not in CI yet.&lt;/strong&gt; I run this manually when I need fresh screenshots. I'll wire it into a deploy pipeline at some point, but even running it by hand cuts out most of the work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The ROI is in reuse.&lt;/strong&gt; You won't see the payoff from the first asset you produce. You'll see it the fifth time you add a feature and everything updates without you thinking about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who This Is For
&lt;/h2&gt;

&lt;p&gt;If you're a solo developer or small team and your screenshots keep going stale across multiple surfaces, this is worth the setup cost. If you're already in a TypeScript/React monorepo, you have most of the foundation.&lt;/p&gt;

&lt;p&gt;Start with Maestro. Get your screenshots automated and seeded. That alone will save you more time than you expect. Remotion can come later if you want it. App Store slides are a good first project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;See the results on the &lt;a href="https://www.volm.app/features" rel="noopener noreferrer"&gt;feature pages&lt;/a&gt;, &lt;a href="https://play.google.com/store/apps/details?id=com.tom.logro" rel="noopener noreferrer"&gt;Play Store&lt;/a&gt; / &lt;a href="https://apps.apple.com/us/app/volm-gym-workout-tracker/id6755092536" rel="noopener noreferrer"&gt;App Store&lt;/a&gt;, and &lt;a href="https://www.instagram.com/volm.app" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt; / &lt;a href="https://www.tiktok.com/@volm.app" rel="noopener noreferrer"&gt;TikTok&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>ai</category>
      <category>react</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
