●MAX — Rork Max generates native Swift apps for iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessage●PUBLISH — Rork Max ships 2-click App Store publishing and runs $200/month●RN — The standard Rork builds native iOS/Android apps with React Native (Expo) — the quicker path to a working app●PRICE — Rork is free to start, with paid plans from $25/month●FUND — Rork raised $2.8M from a16z; the platform now sees 743k+ monthly visits with 85% growth●FLOW — Describe your app in plain English and Rork generates deployable code that can use the camera, notifications, and more●MAX — Rork Max generates native Swift apps for iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessage●PUBLISH — Rork Max ships 2-click App Store publishing and runs $200/month●RN — The standard Rork builds native iOS/Android apps with React Native (Expo) — the quicker path to a working app●PRICE — Rork is free to start, with paid plans from $25/month●FUND — Rork raised $2.8M from a16z; the platform now sees 743k+ monthly visits with 85% growth●FLOW — Describe your app in plain English and Rork generates deployable code that can use the camera, notifications, and more
Stopping the Slow Drift of Colors and Spacing on Every Regeneration with a Single Source of Design Tokens
Every time Rork regenerates a screen, button colors and spacing shift a little. Here is a design that freezes your tokens in one place and steers generated output to always reference them.
One day I lined up the screenshots of a shipped app and felt something was off. Inside the same app, only the settings-screen button had a noticeably larger corner radius. Tracing it back, that one screen had been rebuilt in Rork the week before. With each generation the radius had crept from 12 to 16, and the primary blue had drifted ever so slightly brighter — quietly.
One screen, you fix by hand. But when you run several apps as an indie developer, that "creep" accumulates until the outline of your brand goes blurry. Generative AI excels at filling in what you did not specify, so it plausibly reconstructs the "unspoken" parts — colors and spacing — every time. That reconstruction was the true source of the drift on each regeneration.
Why generated visuals shift every time
The styles in the Expo apps Rork generates are usually written as raw numbers right inside components: borderRadius: 12, padding: 16, color: "#2563EB". These are scattered across every screen, and on regeneration the AI re-estimates them from context as "roughly this much." Any value not explicit in the instruction gets reconstructed at a slightly different number each time.
So the root of the drift is that authority over appearance is dispersed across countless components. As long as that authority is scattered, regeneration drifts. There is one direction for the fix: gather the appearance decisions into one place.
Consolidate tokens into a single source
The first step is to freeze your "design vocabulary" — color, spacing, radius, typography — into one file. This is the one file you do not let the AI regenerate; a human owns it.
// tokens.ts — the only place that decides this app's appearance// Not regenerated by AI. Every change is a hand edit here.export const tokens = { color: { brand: "#2563EB", brandPressed: "#1D4ED8", bg: "#FFFFFF", text: "#0F172A", textMuted: "#64748B", danger: "#DC2626", }, radius: { sm: 8, md: 12, lg: 16, pill: 999 }, space: { xs: 4, sm: 8, md: 12, lg: 16, xl: 24, xxl: 32 }, font: { body: 16, title: 22, caption: 13 },} as const;export type Tokens = typeof tokens;
Components no longer hold raw numbers. They always go through tokens.
Now the decision "the blue button's radius is 12" exists in exactly one spot in the world. There is no room left for regeneration to re-estimate borderRadius.
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦Why colors, spacing, and corner radii drift on regeneration, and a single-source token design that stops it
✦A prompt convention that makes the AI reference tokens every time, plus a CI script that flags deviations
✦An operating rule that keeps brand consistency across six apps without slowing down screen regeneration
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
Creating the file is not enough. When you have Rork generate a screen, fix a prompt convention that forbids writing raw style values. The instruction I use looks roughly like this.
Styles must reference values from tokens.ts. Do not write raw numbers or color codes directly
If a new color or spacing is needed, do not write it in the component; first propose it as a candidate addition to tokens.ts
If existing tokens can express the look, reuse them instead of inventing a new value
Placing those three lines at the top of every generation instruction visibly raised the rate at which output references tokens. AI follows "where to look" more obediently than it follows prohibitions.
Detect deviations in CI
Even so, raw numbers slip into output. Relying on human review alone misses them, so detect them mechanically. Drop in a light script that fails if a bare color code or magic number appears inside a component.
// check-tokens.mjs — scan components for raw style valuesimport { readFileSync } from "node:fs";import { globSync } from "glob";const files = globSync("src/components/**/*.tsx");const hexColor = /#[0-9a-fA-F]{3,8}\b/;// Disallowed outside tokens.ts (white may be an operational exception)let violations = 0;for (const f of files) { const lines = readFileSync(f, "utf8").split("\n"); lines.forEach((line, i) => { if (line.includes("tokens.")) return; // token-referencing lines exempt if (hexColor.test(line) && !line.includes("#FFFFFF")) { console.log(`${f}:${i + 1} raw color code: ${line.trim()}`); violations++; } });}if (violations > 0) { console.log(`\nFAIL: ${violations} raw style values found. Move them into tokens.ts`); process.exit(1);}console.log("OK: no raw style values");
Run this before push and any raw #3B82F6 that slipped in during regeneration shows up in a list. When flagged, replace the value with an existing token from tokens.ts, or register it formally as a new token. The point is not to "fix" the drift but to place a mechanism that "notices" the moment drift enters.
A caution when keeping consistency across many apps
Running six apps in parallel, you will want to share tokens fully across all of them. But in my experience, over-sharing means one app's brand change ripples into the other five, which actually slows you down.
What worked in practice is sharing only the structure while each app holds its own values. Keep the key names and the number of steps in radius and space (sm/md/lg…) aligned across all apps, but close the actual colors and numbers inside each app's tokens.ts. That way, porting a new screen to another app lets the components run as-is, while each app grows its own brand color independently.
Numbers that paid off in production, and a pitfall I hit
After putting this into real operation, the effect showed up in numbers in a few places. Before tokenizing, I spent about 10 minutes reviewing the look every time I regenerated a single screen, visually checking that colors and spacing matched the previous version. After consolidating into tokens, that comparison nearly vanished and review time shrank to two or three minutes. In a week where I touch several screens a day, that difference stacks up into a real change.
Let me share a pitfall I hit myself. At first, even after adopting tokens, the drift would not stop, and I chased the cause for half a day. Checking the production build, one generated component imported tokens.color.brand while, right beside it, also wrote the same color "#2563EB" raw. Since they looked identical, no runtime error appeared and review missed it. That is exactly why the CI detection below is needed: the human eye does not register "the same color" as an anomaly.
Another pitfall was slicing the tokens too finely. When I prepared ten spacing steps where six would do, the AI hesitated over which to pick, and consistency actually dropped. I recommend keeping the number of steps small. Personally, six spacing steps from xs to xxl and four radius steps was the grain that was easiest to judge for both AI and human. Even on screens where I drop in an AdMob banner, fewer spacing steps made layout breakage easier to predict and cut how often I had to retake App Store screenshots.
As a guiding rule: when you feel the urge to add a new token, pause and first ask whether an existing step can stand in. Tokens grant more freedom the more you add, but the more freedom you grant, the more the regeneration drift returns.
Your next move
From your current app's components, extract just the colors into tokens.ts first. Color is where drift is most visible, so the effect is easiest to feel. Then wedge check-tokens.mjs in before push, and from the next regeneration you escape the state of "drifting without noticing."
It is a humble bit of plumbing, but it pays off the longer an app lives. I would be glad if it helps anyone facing the same trouble.
Share
Thank You for Reading
Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.