Skip to main content

videorc-design

Videorc's UI design language — a native macOS desktop app on real window glass (vibrancy), built exclusively from shadcn/ui components: flush panes, toolbars, grouped lists, glass chips, and a Raycast-style ⌘K palette. Use whenever building, styling, reviewing, or planning ANY Videorc UI (new components, screens, dialogs, lists, toolbars, badges), when the user mentions "our design", "the design skill", "glass", "native look", or asks how something should look.

Source facts

Repository
TheOrcDev/videorc
Last source activity
October 5, 2026 at 23:57
Detected SKILL.md language
English
Stars
485
Forks
66

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
videorc-design
description
Videorc's UI design language — a native macOS desktop app on real window glass (vibrancy), built exclusively from shadcn/ui components: flush panes, toolbars, grouped lists, glass chips, and a Raycast-style ⌘K palette. Use whenever building, styling, reviewing, or planning ANY Videorc UI (new components, screens, dialogs, lists, toolbars, badges), when the user mentions "our design", "the design skill", "glass", "native look", or asks how something should look.
# Videorc Design Language (v2: the window family) The single source of truth for how Videorc looks and feels. Every UI task follows this skill. Videorc is a desktop app, not a web page: every window sits on the real macOS window material, panes are flush and split by hairlines, controls are desktop-sized, and colour is information. The reference is the Videorc logo: a glossy black-glass orb with chrome detail and one LED-red accent. Light mode is the porcelain twin of the same structure. **Status: shipped in plan 050 (2026-09-23).** `styles.css` implements the tokens below. `src/main/window-glass.ts` gives every window (main, Stream Manager, Captions, Notes, Preview) its material and title bar. The Preview frame's data-URL document mirrors the coats through `src/main/window-palette.ts`, and a parity test fails when they drift. Fix tokens and primitives, never restyle a screen ad hoc. ## Hard rules 1. **shadcn/ui only.** Every element is a shadcn/ui component or a composition of them, installed and customized per the `shadcn` skill. No other component libraries and no hand-rolled widgets when a primitive exists. audiocn (the owner's shadcn audio registry, `@audiocn`) counts as shadcn: its meters draw audio, fed by Videorc adapters, never by its Web Audio hooks or blocks. Base UI enters only inside its files (`docs/audiocn.md`). 2. **Real glass, never fake glass.** The OS draws the blur. No CSS `backdrop-filter` / `backdrop-blur` anywhere in the renderer: it wedged the compositor in June, and on the vibrancy windows it never reaches the screen (Chromium's own capture shows the blur, the display does not; plan 072). A guard test fails on it. No wallpaper underlays, no inline `color-scheme` on the root. 3. **Dark first, light supported.** Dark is the reference. Light is the same structure with the light token column, never a separately designed theme. 4. **Colour is information.** Chrome is monochrome. Saturated colour appears only in source/platform icons, status dots, and emphasis chips: red for record, live, and destructive; green for healthy; amber for attention. Never tint panels, rows, or text decoratively. 5. **Keyboard-first, quietly.** Primary actions show their shortcut as a key chip. Global hints live in the status bar, not on every surface. ## The window family Every window uses one material and one title-bar recipe (`window-glass.ts`): - **Material.** `vibrancy: 'under-window'`, with the effect state pinned to `active` so glass stays glass when the window is inactive, stripped to **clear glass** by the native addon (plan 091): Ghostex's strip on Electron's own vibrancy view, no tint, no wallpaper tinting, no saturation boost, a 60 pt blur. What shows through is the desktop as soft colour, and the coats decide the whole tone. `VIDEORC_GLASS_STYLE=material` keeps AppKit's own grey material as the A/B control for one release; `VIDEORC_GLASS=0` paints the solid palette instead. - **Title bar.** `titleBarStyle: 'hiddenInset'`. Traffic lights are centred in the header row, which is 40 px (28 px for Preview). A header row shares its line with the lights: it pads `pl-[88px]` through `useTrafficLightGutter()`, which drops to `pl-3` in native fullscreen. Header rows are drag regions, and their controls opt out with `[-webkit-app-region:no-drag]`. - **One dark-always window.** The Preview frames video, so main pins its NSWindow appearance to `darkAqua` through the native addon, and a light main window never lightens it. If the pin is unavailable, it falls back to solid dark. Stream Manager, Captions and Notes follow the app theme like main (#412). - **Covers.** One cover per region, Ghostex's numbers (plan 091, D3): how much of the solid tone a region paints over the clear blur. The sidebar covers 88% (dark) · 93% (light), the work area 83% · 86%: the sidebar is the heavier, more covered region, the work area shows more desktop. - The coats are derived from the covers (D4), never set by hand: `body` paints the lighter cover (`--glass-window`), the sidebar `<aside>` adds its delta (`bg-glass-sidebar`), content panes add theirs (`bg-glass-content`, 0 on macOS), so each region composites to exactly its cover. - Single-pane windows wrap their body in `WindowFrame`. - Never stack a third coat. - Windows keeps plan 050's Mica composite through its own covers. - **Accessibility.** `prefers-reduced-transparency` swaps the window coat for `--glass-solid` and drops the region coats (the addon leaves AppKit's solid material whole). `prefers-contrast: more` puts both covers at 95% and strengthens hairlines, chip rims, and the secondary text tier. - **Proof.** `pnpm probe:ui-glass --gate` measures every window over stand-in backdrops: transmission (the glass is real), sharpness (nothing behind is legible), contrast, pinned-dark luminance, the native effect view state, and since plan 091 neutrality (the stripped material passes the backdrop colour through), `nativeClear` (the strip holds) and `ghostexParity` (each region composites to its cover). It runs in `smoke:local-gates`. ## Tokens Implemented as shadcn CSS variables in `apps/desktop/src/renderer/src/styles.css` (oklch; that file is the live source). Values below are dark · light. Coats and surfaces - Base `--glass-base`: black `0.16 0.004 286` (`#0D0D0F`) · porcelain `0.985 0.001 286` (`#FAFAFB`), the OKLCH components every coat is cut from. Solid `--glass-solid` is that base, opaque. - Covers `--glass-cover-sidebar` / `--glass-cover-work`: 0.88 / 0.83 · 0.93 / 0.86 (Windows 0.34 / 0.5116 · 0.5 / 0.62). The coats `--glass-window`, `--glass-sidebar` and `--glass-content` are derived from them in `styles.css`. - Floating glass, three flat opaque tiers of the solid (plan 091, D6, Ghostex's web-modal recipe), each a 1 px rim (white 10% · black 10%) and a drop shadow, no sheen and no highlight: - popup `--glass-float` (menus, selects, popovers, hover cards, chart tooltips, toasts): black `#222224` (the solid plus 6% then 3% white, `color-mix` in sRGB) · porcelain `oklch(0.99 0 0)`; - dialog `--glass-float-dialog` (dialogs, the palette, the error panel): black `#1C1C1D` · porcelain; - tooltip `--glass-float-tooltip`: the black solid · porcelain. Opaque: without a frost, even 3% translucency lets white text under a menu read through. Deliberately darker than the glass over a bright desktop: `probe:ui-glass --surfaces` checks each tier reads its own token whatever is behind it. Text (three tiers, nothing else) - Primary `text-foreground`: titles and labels, weight 500–600. - Secondary `text-muted-foreground`: inline context, metadata, placeholders. - Tertiary `text-subtle`: section labels, hints, disabled. Hairlines and selection - Hairlines `border-border`: white 10% · black 12%, always 1 px. - Hover/selected row `bg-accent`: white 8% · black 6%, a full-row block with no outline. Pressed `bg-accent-pressed`: 12% · 10%. - Focus-visible: a 2–3 px ring, keyboard only. Colour - `--live` / `--destructive`: the logo's LED red. Record, on air, failed, destructive. Never chrome. - `--success`: healthy or connected. `--warning`: needs attention. `--info`: rare. - `--member`: a muted violet for paid membership (YouTube member, Twitch, Kick or X subscriber). It paints only the member row tint in chat (plan 154); never a chip tone, never text. - Use them through the tone utilities (`tone-success`, `tone-warning`, `tone-destructive`, `tone-live`, `tone-neutral`) and the chip utilities. Never as text colour on status copy. ## Desktop scale Everything except ⌘K uses the desktop scale. - **Layout.** There is no page column: content fills its pane edge to edge with a 16 px gutter. Panes are flush and split by 1 px hairlines. Inside a window there are no floating panels, no shadows, and no big cards. - **Toolbar** (`Toolbar`, 40 px): the page title (14 px / 600) on the window's drag band, and nothing else. No buttons in the toolbar's top-right corner (owner call, 2026-09-23): actions live with the content they act on. The Studio's Record / Stream / Stop and clock sit at the top of its inspector, right above Session; a page's own actions sit in its body (a filter bar, a section header, or the PageHeader row). The toolbar never scrolls; only `PaneBody` does. - **Sidebar.** - The top row holds the traffic lights and the ⌘K button. Windows has no traffic lights, so there the row leads with the app icon (16 px) and "Videorc" in 12 px regular, the Windows 11 title-bar convention. - Section labels are 11 px / 600, tertiary. - Rows are 28 px, with 14 px text and 16 px icons. - The account row sits at the bottom. On macOS the brand lives in About and the Dock, never in the sidebar (owner call, 2026-09-23). - **Status bar** (`StatusBar`, 26 px): connection and record/live state on the left. On the right, quiet 11 px shortcut hints, each still clickable: `⌘K Search`, `⌘P Preview`, `⇧⌘N Notes`, `⇧⌘J Stream Manager`. - **Sections** (`PanelSection`): flush. A 13 px / 600 header, a 12 px secondary description, a hairline between sections, and 16 px padding. No border, background, radius, or shadow. - **Pages with tabs** (Settings, plan 064; Orcle, plan 150): one segmented `TabsList` in a pinned strip under the toolbar (`border-b px-gutter py-2`). Only the panel under it scrolls, and the shell turns `PaneBody` scroll off for the page. The last tab used is remembered on this device, deep links open a named tab, and ⌘K lists every tab. - Each tab answers one question. - A tab body is a `ConfigGrid` of two sections with `CONFIG_GRID_PAIR`, or a `PageStack` for one. - Settings rows are `FieldGroup variant="grouped"`: label and description on the left, the control on the right. - **Locked means disabled, with one reason.** One `Alert` with its one action leads the tab, and every control under it is disabled. Never put an enabled-looking switch or button beside "isn't available". - Rules a streamer needs (limits, Premium versus free) go in the section's description, never in `text-subtle` footnotes. - **Lists, not card stacks.** Sets of like things (destinations, sources, devices, settings) are one `GroupedList` of `ListRow`s: 32 px rows (28 px compact) with hairline separators. Cards remain only for objects with a picture (scene thumbnails, library items): 8 px radius, white 4% fill, a 1 px hairline, no shadow. - **Radii.** Tiers only, never ad-hoc radius values per screen: - `rounded-panel`: 12 px. Containers and dialogs. - `rounded-row`: 8 px. Rows and cards. - `rounded-chip`: 6 px. Controls and key chips. - Tags use 7 px. Status chips are round. - Window corners belong to the OS. - **Controls.** The default height is 28 px for Button, Select trigger, and Input. Retune it once in `components/ui`, never per screen. Segmented choices use `Tabs`, a glass segmented control. - **Type.** The system stack (SF Pro). Body 14 px, metadata 12 px, section labels 11 px. Density comes from structure, not from smaller text. ## Stream Manager The live dashboard window (plan 055; code name `comments`, the old Chat window). It follows the window family and adds its own layout rules. Plan 057 made it chat first: one thin stats bar and fewer words. - **Tiers by container query.** The body is `@container/stream-manager`, never JS resize state (`lib/stream-manager-layout.ts`): - Wide (1,040 px and up): the stats bar, then Chat beside a right pane with an Activity / Orcle segmented control. - Medium (640 to 1,039 px): the stats bar, then one pane behind Chat / Activity / Orcle. - Narrow (under 640 px, 320 minimum): the same, with the stats bar down to its main slots. - Every pane renders once; only its placement changes. - **The title row carries the title only,** with no mode badge: the stats bar says ON AIR, and History has its own bar. Controls live in the status bar: each provider's chat state on the left; Keep on top, Highlight, Clear and Open Preview as icons on the right, folded into ⋯ under 640 px. - **One thin stats bar** (32 px, `components/stream-manager/stats-bar.tsx`), never tiles or cards: - The three main slots lead it: by default the ON AIR clock, viewers and stream health. They are never clipped at any width. - The rest follow after a hairline as a number and a short unit ("89,860 followers +83 · 8 subs · $20 · 22 msg/min"). They sit in a clipped, wrapping row, so a stat that does not fit drops off the end whole. - Numbers are monochrome and tabular. Tone lives in the chip and the dots, and the ON AIR chip is the only emphasis. Mini sparklines (the shadcn `chart`) appear at Wide only. - Details are one hover away (`HoverCard`): the per-platform split, peak, fps, drops, each destination's state. - Drag a stat to move it; right-click the bar to show or hide stats, move one, or reset (`lib/stream-manager-stats-layout.ts`, kept in `localStorage`). The clock and the viewer count cannot be hidden or leave the main slots. - **Quiet when fine, specific when not.** Mid-stream there is no time to read. A healthy state is a dot or a number; words appear only when something needs the streamer: - health shows "X failed" or "12 dropped/min" instead of the bitrate; - a provider shows "read-only" or "reconnect to send"; - the composer names only what a send skips, and a finished send says nothing; - every removed caption survives in a hover card or a tooltip. - **Never an unmeasured zero.** A stat exists only when its source does, and an unreadable number shows "–" with the reason on hover. The viewer count is never hidden while live. - **Chat keeps the big-text rows** (plan 055, decision 5), virtualized with `@tanstack/react-virtual`. While live, a row's time appears on hover. Filters are inline chips from 640 px and one Filters menu below it. A row paints at most one background, lowest to highest: a member's own message `bg-member/8` (plan 154), Orcle's "Talking about this" `bg-accent`, a paid message `bg-warning/10` with its ring; an on-stream row keeps its button fill. The Member chip stays on every tinted row and text stays monochrome. - **Activity rows** lead with who: a row about one named person (a follow, sub, gift, tip or raid) shows their avatar circle, with initials until it loads (plan 071). Counts the platform never named, announcements and destinations keep the event glyph tile (the window-scoped registry `components/stream-manager/activity-icons.tsx`). Either way the platform icon sits bottom-right. Then comes the name and a short fact on one line ("Resub · 14 months"), the viewer's words, and a ⋯ menu. Filter chips carry their counts. - **Proof.** `pnpm probe:comments-window` sweeps 320/480/640/800/1040/1280. It fails on any overflow, a stats bar taller than one row, main stats apart or clipped, a stat cut at the bar's edge, a hidden viewer count, a button in the title row, or an unreachable control. ## ⌘K palette scale The command palette alone keeps the Raycast scale: - `rounded-panel` float glass (the Dialog's `glass-float-dialog`; `Command` itself paints nothing). - An 18–20 px borderless search input with a leading 24 px icon. - 40 px rows: icon, title, secondary context, an optional alias key chip, then right-aligned metadata. - A footer with the primary action and its key chip. Nothing else in the app uses this scale. ## Glass chips Every badge, status pill, tag, and key chip is glass (`ui/badge.tsx`, `status-badge.tsx`, `ui/kbd.tsx`, `status-dot.tsx`). The chip utilities (`glass-chip`, `glass-chip-tinted`, `glass-dot`, `glass-keycap`) are defined once in `styles.css`. | Part | Dark | Light | | ------------- | ---------------------------------- | --------------- | | Fill | vertical gradient white 10% → 3.5% | white 70% → 45% | | Rim | 1 px white 13% | 1 px black 8% | | Top highlight | `inset 0 1px 0` white 12% | white 90% | | Drop | `0 1px 2px` black 30% | black 6% | - **Neutral** (`Badge` default/secondary): primary text. - **Tag** (`Badge` outline): 20 px, 7 px radius, 11 px, secondary text. For `9:16`, counts, `Idle`, `beta`. - **Status** (`Badge` success/warning/neutral, `StatusBadge`, `StatusDot`): - Monochrome text. A 6 px dot in the tone colour carries the status, with a 2 px halo and a soft glow. - A leading icon replaces the dot and takes the tone. - `StatusBadge` is 22 px and fully round. - **Emphasis** (`Badge` destructive/live, an error `StatusBadge`): tinted glass, a tone gradient with a tone rim and tone-mixed text. Only for failed, on air, and destructive. - **Key chip** (`Kbd`): a glass keycap with a brighter top edge and a dark bottom edge. - No `backdrop-filter`, no motion, no ad-hoc pills. A rounded, bordered `text-[10–12px]` span is a bug: use `Badge`. ## Floating surfaces Dialogs, popovers, hover cards, menus, selects, tooltips, toasts, and the palette are flat, opaque tiers of the window's solid tone (plan 072 made them opaque, plan 091 D6 made them flat): `border glass-float` for the popup tier, `border glass-float-dialog` for dialogs and the palette, `border glass-float-tooltip` for tooltips. One surface per float: a `Command` inside a Dialog or Popover stays transparent. Every toast is the same neutral popup glass: a type (success, warning, error, info) colours its
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub