Style book

Every reusable piece of Bytestream, rendered once, in the tokens the build uses. The rules behind each one live in design/patterns.md; this page is the picture. Match these before inventing.

Tokens

Six colours and nothing else. Every translucent value is one of void, now or paper pulled back. No purple, no third accent, no hex codes in the interface.

voidapp background
studiosidebar, cards, tiles
stageband under the picture
papertext, wordmark
nowselected, progress, now-line
liveLIVE pill only
paperDimsecondary text · paper .6
hairlinedividers · white .08
rowHoverpaper .08
rowActivenow .12
focusfield border · now .45
voidAlphaoverlay gradient, pills on video

src/ui/tokens.ts · nowAlpha() paperAlpha() voidAlpha() are functions on the palette, not new colours.

Type

Two faces. Barlow Condensed 600 is the brand voice: wordmark, on-picture names, tile names, section labels. It carries Latin only, so anything set in it answers for names it cannot spell. Inter for everything else. Times in tabular numerals.

Wordmark · condensed, .12em, 34 desktop / 28 phone
Bytestream
Screen title · 32 / 700
Guide
Channel name on the picture · condensed 26 / 20 compact
NHK World-Japan
Channel name in a row · 20 / 600
France 24
Channel name in the tile · condensed, sentence case
Al Jazeera English
Body · 16 / 400
Tonight's programmes for 329 channels, refreshed every 6 hours.
Meta · 14, paperDim
Newsline 21:00–21:30 · Japan · News · Next Asia Insight 21:30
Section label · condensed 11, .18em, uppercase
Live channels

Spacing & radius

A 4-point scale. Screen gutter 12 phone, 24 desktop. Rail card gap 12. Radii: pill 4, card 6, frame 8, stage 10, panel 12.

4
8
12
16
24
32
48
4 pill
6 card
8 frame
10 stage
12 panel

Motion & focus

Sparingly. Tab switches cut. Rail selection border fades 120 ms. Sheets settle in 220 ms ease-out-cubic. The tuning pulse (1.2 s) is the only loop. No scroll reveals. Focus ring: 2px now, offset 2, keyboard only; text fields warm their border instead.

tuning pulse

Sidebar & tab bar

One product, two frames. Desktop (≥768): a 248 sidebar, wordmark, then Search with its ⌘K hint, then Watch / Guide / Atlas / Saved. Active row: now label and a 3px bar on the left edge. Phone: a 56 tab bar, glyph over label, now with a 2px underline.

src/ui/Chrome.tsx · Wordmark.tsx

Destination glyphs

16px in both frames. Saved is the one glyph that changes shape when you stand in it, because it is the save control: the heart fills when the channel is yours. Sidebar, tab bar and the overlay's save toggle are one symbol in two states.

Watch
Guide
Atlas
Saved
Saved, active
Theater (masks)
Lamp
Fullscreen

Screen tabs

Tabs across the top of a screen with more than one face (the Studio's Channel / Control room). now label with a 2px underline on the active one, paperDim otherwise, a hairline under the row.

ChannelControl roombytestream.tv/jake

Frame & overlay

16:9, radius 8, studio when there is no picture. Controls sit on the picture in a bottom-anchored overlay over a soft void gradient: channel name in the condensed face, then Programme 21:00–21:30 · Country · Category · Next … with the LIVE pill right-aligned, then the progress line, then the control row. One shape, two scales, everywhere. Auto-hides; a pointer move brings it back.

LIVE
Backstreets, Liguria
Night loop 22:31–22:43 · Italy · Travel · Next 22:43 Kitchen radio

src/ui/Overlay.tsx · Transport.tsx · ProgressBar.tsx · LivePill.tsx

Transport

Left cluster: previous channel, back 15, the amber play disc, forward 15, next channel. Right: save heart (desktop), speaker, 72px volume line (desktop), CC, masks, lamp, fullscreen. Desktop glyphs 18 with a 28 disc; phone 20 with a 36 disc. Mute is on every layout. No control is ever removed to make something fit.

Masks amber = theater on. Lamp filled = ambience on, never a second amber.

State patterns

Tuning: the frame stays studio, a 2px now hairline pulses across the bottom of the picture, inside the frame, in front of the video, out of the layout flow. Off air and unplayable: one true line in paperDim, centred. Empty catalog: a title and one retry link in now. The progress line goes bare in all three.

Tuning…
Off air
Plays in the app, not in a browser
Couldn't reach the catalogTry again
Tap for sound
paused: the last frame holds, never a blank

Pills

LIVE: live fill, paper text, 12/700, radius 4, 4×8, only while the stream is playing. Rewound more than 10 s it becomes the outline Back to live. The amber outline pill marks a state in now (Looping, recall). A hairline pill is quiet fact (Locked, No listings).

LIVE Back to live Looping Channel locked 18+ Tap for sound

Rail card

176 desktop / 140 phone. 16:9 tile in studio with the logo centred at 60% width, or the name in the brand face when there is no logo (then no caption: the name is already the label). Selected: 2px now border, name in now, and on web the logo swaps for a captured live frame. Hover: name in paper.

BBC World
France 24
18+
DW
Al Jazeera English

src/ui/RailCard.tsx · ChannelTile.tsx · ChannelNameMark.tsx

Guide row

Tile, channel name, programme title, time range in tabular numerals, amber programme progress. The playing row on desktop fills now with void text. A channel the guide does not carry (only while a query narrows the screen) shows No listings, no time range and no bar: the absence is the distinction.

NHK World-Japan
Newsline
21:00–21:30
France 24
France 24
The Debate
20:45–21:30
Arirang
Arirang TV
No listings
South Korea · General

src/ui/ChannelRow.tsx · MetaLine.tsx

Row highlight

One row language for Spotlight results and picker options. Rows bleed to the panel's edges. Hover is rowHover (neutral); active is rowActive with the title in now (warm). Counts sit in a fixed 56px right column, tabular.

Japan 142
Jordan 9
Kazakhstan 27
Kenya 31

List handle

One 36×4 pill, fully round, paper .28, no chevron, no label. Three rests and nothing between them: default, up, down. Drag walks neighbours; release snaps; tap steps. Hover paper .6 on pointer. 220 ms ease-out-cubic on every breakpoint. e / Shift+E.

rest · hover  ·  src/ui/ListHandle.tsx

Buttons

Primary: now fill, void text, 600, height 40, radius 6. Quiet: hairline border, paper text. Disabled at .4. The Studio's marquee uses the same two at 48 with fully round ends. Copy is a verb: Upload to Bytestream, Get a stream key, never Submit.

Copy

Inputs & chips

One field pattern, variants. field wears its box always; inline (the trailing filter on a chip row, desktop) is bare at rest and puts the chip's clothes on only while focused or holding text. Focus warms the border to focus; no ring on text fields. Chips are 36 tall; a set chip turns now and grows a clear button that never opens the picker.

Country Japan ×

src/ui/SearchField.tsx · FilterChip.tsx · FilterPanel.tsx · PickerSheet.tsx

Switch

The one non-text control of the input family. now track on, hairline off, paper thumb, no hover response. Same three colours, no fourth.

Show adult channels

Poster tile (Studio)

16:9, radius 8, the encode's still. A one-line state under the caption: amber dot for on air and for anything in motion (encoding, uploading, pulsing), paper dot for in review, none for rejected. In-motion tiles keep the still behind a void veil with the state on top and the meter along the bottom edge. Rejected sits at half opacity.

Kitchen radio, Sunday
On air · 5:36
Encoding
Rooftop timelapse
A few minutes
Untitled 3
Rejected · music rights
Drop a video here
or choose a file

Readouts & meters

A readout is a value you copy, not type: void box, hairline, tabular, with its one action in now at the right; long values ellipsise, the action never wraps. A big number is the condensed face at 44 with its unit in paperDim; the 2px meter under it fills now.

Serverrtmp://live.bytestream.tv/liveCopy Stream key••••••••••••••••••••Reveal
17:40 of 30:00 approved

Timeline sheet · parked 2026-09-22

Built for the Studio channel home and taken off it the same day; kept to return to. A bottom-docked sheet on the list handle carrying the loop strip: every segment of the N00bstream loop sized to runtime with its still, the creator's own outlined in now, a now-line at wall-clock, ghost segments for videos still in review or encoding, a dashed amber slot for the next upload, a tabular axis, and the unlock meter beneath. Headline Your timeline. Working component with the rests live: component-timeline-sheet.html.

Your timeline
On now Backstreets, Liguria · yours · 7:12 of 12:04Loop 41:20 · 9 videos · 3 creators
Sunday market, Lisbon
6:30 · Ana
Backstreets, Liguria
12:04 · you · 1,284 starts
Set 12
4:12 · Kofi
Garage sessions
9:02 · Kofi
Bread, 5am
3:54 · Ana
Kitchen radio, Sunday
5:36 · in review
Rooftop timelapse
3:11 · encoding
Your next
video here
00:0010:0020:0030:0041:20
Channel locked
17:40 of 30:00 approved · 12:20 or one live stream opens bytestream.tv/jake

Open question for its return: a visitor's strip carries titles and creators only; yours, starts, the lock and the slot are owner facts.

Usage

The style book measured against Laws of UX (Jon Yablonski), fetched 2026-09-22. For each law: what Bytestream already does, then the rule to keep or the place it falls short. Cognitive Bias is the umbrella the others sit under and is not a rule of its own here.

LawIn BytestreamKeep / fix
Aesthetic-Usability EffectA dark room with film grain, one warm light, real stills in every tile. The player is the product and everything else is a rail under it.Grain and warmth earn trust only while the picture plays. An empty studio tile with a type-only name is where the effect runs out; keep stills first, logos second, type last.
Choice Overload9,461 playable channels never appear as one list. Shelves cut by category, country and language; Spotlight answers a query; the Guide shows only what is on now.The Categories index and Atlas are the two places a viewer meets the whole catalog at once. Both need a first row that decides for them (starred countries, seeded channels).
ChunkingFour destinations. The overlay is three lines: name, meta, controls. The timeline strip breaks a 41-minute loop into nine titled segments sized to runtime.A shelf row is the chunk; a shelf longer than a screen should end with a Show-all card, not run on.
Cognitive LoadNo hex codes, no jargon in the interface. Times as 21:00–21:30. One control surface for the player, not two. One row language for every list.The OBS server and key readouts are the heaviest thing in the Studio; they stay in a box with a Copy action so nothing has to be read, only pressed.
Doherty ThresholdTune-in is measured, not guessed: one YouTube player reused, HLS remembers the working stream, the next host is preconnected. Sheets settle in 220 ms. The tuning pulse says something is happening within the first frame.Anything over 400 ms shows a state, never a blank. Paused holds the last frame. A reload is not a stream failure.
Fitts's LawThe list handle draws 36×4 but its target is 48×36. Phone transport glyphs are 20 with a 36 disc and 8 gaps, inside a 320 handset. Chips are 36 tall.Desktop transport is ten 18 px glyphs at 14 px gaps; the save heart gets 28 px of clearance from the speaker so a mute press cannot catch it. Any new control on that row must keep that gap.
FlowTheater clears the chrome. The overlay hides itself; a pointer move brings it back. Arrow keys walk the rail; Enter selects; Space toggles play. Channel changes never re-mount the picture.A route change exits theater and the stream never re-tunes on a layout change. Keep it that way: every Watch state is a layout state, never a route.
Goal-Gradient EffectThe Studio's unlock meter: 17:40 of 30:00 approved, with the remainder spelled out and the reward named (bytestream.tv/jake). The loop strip's dashed slot reads Your next video here.The meter moves only on approval, so a creator with three videos in review sees no progress. Show the pending minutes on the meter in a ghost fill.
Hick's LawFour destinations, one search. The picker is a searchable list, not a grid of every country. A tap on a rail card tunes; there is no second confirm.The desktop transport row is the one place with ten choices side by side. It survives because every glyph is a standard: no invented icon lives there.
Jakob's Law⌘K opens search. A 16:9 frame with a bottom overlay and a crimson LIVE pill is what every player looks like. The Studio is a channel home with tabs, like the sites creators already use. Stream server + key is the OBS convention.The comedy/tragedy masks for theater are ours alone. They read only because they sit where the widescreen icon usually sits and turn amber when on.
Law of Common RegionPanels: the overlay's void gradient, the studio-toned cards, the stage band under the picture, the popover with its own border. Rows bleed to the panel's edges so a highlight is a row, not a stripe.Spotlight's field has no box of its own because the panel's border already draws the region. Never put a box inside a box.
Law of ProximityThe LIVE pill sits on the programme line, above the progress bar it describes. The save heart rides the title line on a phone, away from mute. The clear button lives inside its chip.The unlock meter sits directly under the number it measures; move one and move both.
Law of PrägnanzThe handle is a bare pill: it goes both ways, so it carries no arrow. A progress line with nothing to report draws the empty track, not a made-up position. The wordmark is the word alone.The chevron on the handle lasted one afternoon. Resist adding a glyph to say what the shape already says.
Law of SimilarityOne row language for Spotlight and the picker. One rail card. Sidebar row, tab bar item and overlay save toggle share the heart in the same two states. Every field is one pattern with variants.A new list must reuse ChannelRow or the row highlight; a new switch must be the SettingsSheet switch.
Law of Uniform ConnectednessThe progress line and its head are one amber stroke. The tuning hairline follows the frame's own radius. The now-line on the timeline runs from the axis through the strip.The desktop playing Guide row fills amber end to end, tile to time: one connected object, not a highlighted name.
Mental ModelIt is a television, not a dashboard: channels, tonight, LIVE, off air. The N00bstream is a channel you tune into, so a creator's video 'airs' rather than 'publishes'.The word 'Off air' is a claim about the broadcast, so the Guide says 'No listings' when it is the guide that is empty. Keep the two vocabularies apart.
Miller's LawFour destinations, one search. Nine segments on a loop strip. The transport's left cluster is five.The desktop transport's right cluster is seven; it holds because it is two groups (sound, picture) with a gap between.
Occam's RazorTheater and the phone lost their own transport layouts; there is one. The desktop sheet and the phone sheet share one clock. The lamp is web-only rather than present-and-inert.The Studio channel home and control room both carry upload and go-live. One of them should own the action and the other should link to it.
Paradox of the Active UserNo onboarding. 'Tap for sound' appears where the tap is needed and dismisses on first tap. The OBS box says exactly where to paste. Any common video format is accepted.Every keyboard shortcut also has a visible control; keys are a bonus, never the only door.
Pareto Principle329 channels carry a programme guide against 9,461 playable, and they lead every shelf. The starred countries lead Atlas. Recommendations open with Top picks.When a query narrows the Guide, rows with a programme still come first and the quiet rows gather in a tail.
Parkinson's LawA run of the pipeline is bounded: encoding 'takes a few minutes', a reviewer 'then' puts it on air, and the state line says which step it is on.Give every waiting state a time shape, even a rough one; an unbounded 'Processing' invites the creator to keep refreshing.
Peak-End RuleThe peak is the first frame of a channel: the tuning pulse, then the picture, then LIVE lights. The end is never a black rectangle: paused holds a frame, off air says so and moves on after a second.The Studio's peak is the first approval. Make it visible: the video's state turns amber and the loop strip gains a segment.
Postel's LawSearch matches on name, country, category and language. Uploads accept any common format and normalise through Mux. The relay answers for sources that will not play in a browser with the true reason.The condensed face is Latin-only, so a name it cannot spell falls to Inter in the tile. Accept every script; send one clean line back.
Selective AttentionAmber means now and appears once per screen. Crimson means LIVE and appears once. Everything else is paper, dim or hairline, so the eye finds the one warm thing.A second amber on a screen is a bug. The lamp is filled paper when on precisely so it is never mistaken for the masks.
Serial Position EffectSearch leads the sidebar because it is how you get anywhere in 9,000 channels; Saved ends it. Seeded channels lead a shelf; the Show-all card ends it. The playing channel's row leads the Guide.The loop strip's first segment is the one a visitor reads; the creator's next-video slot is last on purpose, it is the invitation.
Tesler's LawGoing live from OBS needs a server and a key; that cannot be reduced, so it is presented as two copyable readouts and one sentence. Rights attestation on upload is one screen, once.Do not hide irreducible steps behind 'advanced'. Put them in a box, label them plainly, give each one action.
Von Restorff EffectLIVE is the only crimson thing in the app. The selected rail card is the only amber border. The creator's own segments are the only outlined ones on the timeline strip.Because these are the only differences, they carry meaning. A decorative border or a third accent would dilute all three at once.
Working MemoryThe recall pill remembers the last channel. The channel picker keeps its scroll. A tuned channel survives a reload. Filter chips show what is set without opening the picker.A creator's state lines (In review, Encoding, Uploading 412 MB of 660 MB) are the memory; never collapse them to a single 'Processing'.
Zeigarnik EffectUploading and encoding tiles keep the still behind a veil with the state on top and a meter along the edge. The unlock meter is unfinished by design. The dashed slot on the timeline is an open task.The activity log in the control room closes the loop: every started thing gets a finished line, so nothing stays open in the creator's head.

Five to act on: the desktop transport row is at the edge of Fitts and Hick; pending minutes should show on the unlock meter (Goal-Gradient); upload and go-live live in two places (Occam); waiting states need a time shape (Parkinson); the first approval needs a visible peak (Peak-End).