Updates Design system App atlas

Design system

How ARND looks, and when

The code is the source of truth (lib/design, lib/themeTokens, components/ui); this page mirrors it and writes down the rules. A component without a when-to-use rule is just decoration. When code and this page disagree, one of them gets fixed the same day.

Color

Five themes ship (arnd-modern default, react95, neon-noir, paper, candy), each in light and dark. Swatches below are the default theme; the rules hold for all of them.

Brand and semantics

Accent · bellflower (light)
#504BF1
Accent · bellflower (dark)
#847FF7
Accent soft (light)
#ECEBFD
Success (light)
#0E7F5B
Success (dark)
#34D3A6
Live
#D7231B / #FF5A4D
Gold · ratings
#A87A00 / #F0C44A
Danger
#D93036 / #FF6369

Performer vibes

Eight identity colors a performer's surfaces wear (hero wash, genre chip, glyph, poster tiles). Derived from genre, overridable per artist in Edit Profile.

Brass
#F0A31F
Strings
#D96548
Vocal
#C05CBE
Keys
#7C8CF8
Percussion
#E4573D
Electronic
#38C8D8
Folk
#6FA86A
Pop
#F26BA4

Rules

Bellflower is the only UI accent. Primary actions, active states, links, focus. If a control is a different color, it needs a rule on this page.
Green means money or verified. Nothing else. Tip buttons, verified attendance, checked-in states, claim confirmations. Never decoration.
Vibes belong to performers. They color a performer's identity surfaces and never the app's own chrome. The Follow button is bellflower, not the artist's color.
Live red means happening right now. The live dot, on-site markers, pulsing pins. Not errors (danger owns those), not emphasis.
No hardcoded hex in screens. Every color goes through useThemeTokens() or a vibe. Hardcoded tints were the single biggest source of drift found in the July audit.
Every text pair clears WCAG AA (4.5:1) in every theme, both modes. Measured, not eyeballed; candy and paper accents were re-tuned for exactly this.

Shape and type

Radius scale

sm 8
md 12
lg 16
xl 20
2xl 24
pill
Cards and callouts: lg (16). Icon tiles and buttons: md (12). Chips and counts: pill. Sheets and heroes: xl (20) and up.
No literal radii in screens. 14 and 18 were the two most common drift values; both are gone.

Type ramp

Inter 600 · 11 · tracking 1.4 · capsEyebrow label
Inter 400 · 13 · line 19Body copy on cards and callouts.
Inter 700 · 16 · tracking -0.2Callout and card titles
Inter 700 · 27 · tracking -0.8Screen headlines
Display faces · poster surfaces onlyPoster headlines
Inter is the app's working face. Display faces (Baloo 2 in-app, Righteous on the site, plus the GigBanner poster set) appear only on poster surfaces.
Known debt: three screens still render Poppins where Inter is the standard. On the cleanup list; do not add more.

Components

The shared pieces in components/ui and components/composed, each with the only question that matters: when is it used, and when is it not.

CalloutCard, the one promo and info card

Every accent promo, invite, CTA, and info note in the app. One shape (radius 16, a 44x44 tile at radius 12, one type ramp), three volumes. Replaced twenty hand-rolled cards in the July audit.

🗺
● Happening now
6 live sets around you
Open the map to see what's on nearby
loud · solid accent, poster arc · max ONE per screen, the time-sensitive headline action
🎤
You play?
Your page could be on this map
See a sample performer page. A park counts.
soft · tinted, 1px accent border, solid tile · the default invite and CTA
Thanks for testing ARND early
Passive info that should recede while staying on-brand.
quiet · tinted, no border, tile optional · settings notes and disclosures
loud: one per screen, maximum. If two things shout, nothing does.
soft: the default whenever the card asks the user to act. Whole card pressable; dismiss sits top-right as a sibling control.
quiet: anything that explains rather than asks. tone="success" flips the family green, for confirmations only.
Never hand-roll an accent-tinted box. If CalloutCard cannot express it, the component grows, not the screen.

Buttons

Primary action → Secondary 🎁 Tip artist 🎁 Tip
Button primary / secondary · TipButton solid / soft (always the green gift)
One primary per view. Everything else is secondary or a text link. Labels are sentence case, say what happens ("Get on the map", "Save my pitch"), and truncate rather than wrap.
Tipping is always the green gift, one TipButton component at any size or emphasis. Never a bespoke tip control; the green is the money signal.
One press feel. Every tap runs through PressableScale's single spring, gated by reduce-motion. No screen hand-rolls press animation.

Chips, badges, and the honesty label

🎙 Jazz · Vocal ✓ Free 4 ⚗ Sample artist page ✓ 81 verified
vibe genre chip · trust chip · count pill · flask sample label · verified sticker
The flask means "not real yet". Sample artist pages, sample gigs, preview inboxes: anything demonstrative wears the flask before the user can act on it. Hard rule.
The verified sticker stays inked: white card, near-black border, slight tilt, identical in both color modes. It is a stamp, not a badge.
Hand-placed tilt (1.5 to 5 degrees) belongs to poster surfaces and stickers only. Forms and settings sit straight.

Poster art: GigBanner and ArtistCover

GigBanner draws every show's poster procedurally: the family is picked content-aware from the title and the result is deterministic per show. No stock photos, no gray placeholders, ever.
ArtistCover gives every performer a generated cover (pulse, halo, or field) in their vibe color, deterministic per artist, overridable in Edit Profile.
Real captures live in the App atlas; this page stays schematic on purpose so it never rots.

Map pins

StateTreatmentRule
DefaultDot pin in the show's genre colorGenre color is the base identity, web and native alike
Live nowPulsing ring in live redOnly while the set is inside its window or the artist is on site
Starting soonAmber ringWithin the pre-show window
TrendingFlame markerComputed from activity, never hand-assigned

States: loading, empty, error

Loading is a skeleton, not a spinner-then-flash. Lists show shaped placeholders (FeedCardSkeleton, Skeleton).
Empty states are branded and honest (EmptyState): icon circle, one human line, one action. A genuinely quiet catalog says "quiet out there", which is different from "nothing matches this filter".
Errors are reachable and retryable. Live-data failures surface the error card with a retry. The app never silently swaps in demo data.

Two kinds of screens

The clearest ruleset in the app: every screen is either a poster or a tool.

Poster surfacesUtility surfaces
WhichWelcome, performer pitch, persona chooser, gig posters, page heroes, celebrationsForms, settings, lists, sheets, detail screens
CanvasBrand surface (near-black) or a committed color fieldTheme background, hairline borders
TypeDisplay faces, big, tightInter, the standard ramp
ColorVibe colors, watermark glyphs, tilted stickersBellflower accent only, straight edges
FeelA show poster taped to a poleA sharp tool that gets out of the way
Entry screens pitch, forms work. The persona chooser used to wear form chrome and read like step zero of a survey; it now wears the poster language. That change is this rule, applied.
Never mix: no display type inside a form, no gray survey cards on an entry screen.

Honesty patterns

ARND's product is trust, so these are design rules with the same force as layout rules.

Never render success for something that did not happen. No "sent" for an undelivered pitch, no "you tipped" for money that never moved. If the real thing is not wired yet, the UI says what actually happened: "saved on this device".
Samples wear the flask, before the user can act on them.
Counts are measured or absent. "RSVPs sync soon" beats a fabricated zero. The feed banner counts only real upcoming sets, and hides at zero instead of shouting about nothing.
Device-local features say so, in plain language, where the action happens.
Money moves person to person through the artist's own payment app, and the UI never implies ARND holds it.

Voice

Human and feature-first. "Your shows on the map fans browse nearby", never "leverage our discovery platform".
Sentence case everywhere except eyebrow labels.
No em-dashes, anywhere. Commas, colons, periods.
Every changelog entry ships with a why. A change without a why does not ship.

The mark

A waveform on a bellflower squircle. Transparent corners so it sits on any surface.

ARND app icon

See all of it applied on real screens in the App atlas, and how it got this way in the changelog.