Color, type, radius, shadow, and component tokens — read from tokens/*.tokens.json, the same source scripts/build.mjs generates the CSS, Tailwind preset, and Swift enum from.
The starting point for anything new. Copy tokens/template.tokens.json, edit the values, run npm run build — this is what a brand-new app gets with no other decisions made yet.
Already-shipping products. Each keeps its own color identity on purpose — only the token structure is shared with the default, not the palette.
Why the system is built this way. General principles first — the part that applies regardless of which app or brand — then the specific history of how it was learned.
A token value needs to exist in three shapes: a CSS custom property, a Tailwind theme key, and a Swift Color/CGFloat. Maintaining all three by hand invites drift — there is exactly one hand-edited file per brand (tokens/<name>.tokens.json), and a build script derives the rest. A value can only be wrong in one place: the source JSON.
The build writes straight into the paths each package actually imports from — no separate staging directory, no manual copy step to forget. A copy step with no enforcement is a drift vector waiting to happen.
Web apps add this as a dependency pinned to a tag; native apps add it as a package pinned to a version. A token change here should never silently change a shipped app's UI — the app opts in by bumping its pin, on its own schedule.
A freshness check fails the build if committed generated output doesn't match what the tokens would produce — whether because a token edit wasn't rebuilt, or because a generated file was hand-edited directly (which would just be silently overwritten and lost on the next real rebuild).
dark: {...} sibling under color per brand the first time an app actually needs one.Extending the schema speculatively is how it stops being simple. Grow it when an app needs it, not before.
An audit of the 6 existing apps (3 web: AIResumeMaker/Bootstrap, futurepath-retirement/Tailwind, NYCSchoolsInfo/MUI; 3+1 iOS: TinyFeelings, TinyMinds, TinyTales, NYCSchoolsInfo) found no shared tooling at all — every repo was an independent checkout, and the only attempt at consistency (the three Tiny* apps hand-copying Swift color/radius/shadow constants between each other, per their own code comments) had already drifted: TinyMinds' shadow (radius:30,y:8) didn't match its siblings' (radius:12,y:4) despite one file's comment claiming they were unified. Each app's marketing website also disagreed with its own app on the "primary" brand color in 2 of 3 cases.
The failure mode wasn't "nobody defined tokens" — several apps had a Theme.swift or theme.ts. It's that the propagation mechanism was copy-paste, which has no way to detect or prevent drift after the fact. That's what the Default section above replaces.
TinyFeelings and TinyTales already agreed with each other on primary color (#E37A3F/#C6612A), shadow (radius:12, y:4), and font pairing (system serif for titles, system default for body). TinyMinds was the outlier on all three, plus its own corner-radius scale (20 vs. the other two's 18) — despite a code comment in TinyFeelings claiming the family was already unified. TinyMinds was changed to match, not the other way around, since two apps already agreeing outweighs one. One color, primaryTerracotta, doubled as the "Language" domain-badge color — checked via grep that nothing outside the two definition files actually renders that alias before recoloring it, so there was no risk of colliding with domainCreative's existing orange. All three marketing sites also got the same primary color fix — none of the three previously matched its own app.
This exercise is also what tokens/tiny.tokens.json formalizes, and it surfaced two real bugs in the build script itself, both fixed generically, not patched around:
"Inter", but the Tiny brand has no custom font file — all three apps render via SwiftUI's system serif/default designs — so its token value is a full CSS stack (-apple-system, BlinkMacSystemFont, ...). Quoting an entire stack as one string produces invalid CSS. The fix detects a stack (contains a comma) or a bare keyword (ui-serif, -apple-system, etc.) and passes it through unquoted."Segoe UI", whose quotes terminated the Swift literal early and produced a syntax error. Now generated via JSON.stringify(value), which escapes the same way Swift string literals need.Both were caught by actually building and inspecting the output after adding the first brand whose tokens didn't look like the two that came before — exactly the kind of edge case a schema should be exercised against before calling it done.
A survey of all 6 apps found no shared Firebase conventions at all — each app has its own dedicated Firebase project, its own hand-written init module in four different shapes, and its own Firestore data-model convention. The same copy-paste-per-app pattern this repo fixes for design tokens, just not yet addressed for Firebase.
One low-risk convention worth adopting when an app is next touched: excluding service-account*.json/*firebase-adminsdk*.json from git so an Admin SDK private key can never be committed by accident — not every app repo has this today.
Not attempted: a shared Firebase init package. Unlike design tokens, an app's Firebase init is entangled with its specific project ID, schema, and auth methods — there's no single shape all apps fit yet. Revisit if two apps genuinely need to share a project.