@telepath-computer/television 0.1.96 → 0.1.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/canonical/v1/styles.css +1 -1
- package/dist/cli.cjs +763 -451
- package/dist/skills/television/SKILL.md +2 -2
- package/dist/skills/television-theme/SKILL.md +349 -0
- package/dist/web/assets/index-DOzy-86J.js +513 -0
- package/dist/web/assets/index-DXZ2UyQf.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-CbAck40c.js +0 -522
- package/dist/web/assets/index-mQBKuH90.css +0 -1
|
@@ -130,7 +130,7 @@ The help text is intentionally written to surface non-obvious semantics — idem
|
|
|
130
130
|
|
|
131
131
|
Commands group into four intents:
|
|
132
132
|
|
|
133
|
-
- **Screen commands** — create, inspect, remove, or switch screens (`create-screen`, `list-screens`, `get-screen`, `remove-screen`, `focus-screen`, `focus-status`).
|
|
133
|
+
- **Screen and display commands** — create, inspect, remove, or switch screens, or change the active display theme (`create-screen`, `list-screens`, `get-screen`, `remove-screen`, `focus-screen`, `focus-status`, `set-theme`).
|
|
134
134
|
- **Artifact creation and lifecycle commands** — create or maintain artifact content (`create-internal-artifact`, `edit-internal-artifact`, `commit-pending-artifact`, `abandon-pending-artifact`, `create-external-artifact`, `create-url-artifact`).
|
|
135
135
|
- **Artifact membership and removal commands** — place, unplace, inspect, retitle, or remove an existing artifact (`attach-artifact`, `detach-artifact`, `delete-artifact`, `get-artifact`, `list-artifacts`, `update-artifact`, `focus-artifact`).
|
|
136
136
|
- **Server and environment commands** — operate on the Television server itself (`serve`, `status`, `stop`, `storage-path`).
|
|
@@ -139,7 +139,7 @@ When the CLI rejects a command, follow the directive it prints rather than guess
|
|
|
139
139
|
|
|
140
140
|
## Read vs mutate
|
|
141
141
|
|
|
142
|
-
Read commands print JSON.
|
|
142
|
+
Read commands print JSON. Workflow commands print plain text. Most mutation commands also print plain text, but `tv set-theme` is intentionally silent on success.
|
|
143
143
|
|
|
144
144
|
Use read commands when you need authoritative state for planning or verification. Use mutation commands when you are intentionally changing Television state.
|
|
145
145
|
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: television-theme
|
|
3
|
+
description: Author a Television theme — capture intent as a skill, render to <storagePath>/themes/<name>/theme.css. The skill survives Television token-surface changes across releases.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Authoring a Television theme
|
|
8
|
+
|
|
9
|
+
A theme re-skins both the Television app chrome and the artifacts it serves. This skill tells an agent how to author one.
|
|
10
|
+
|
|
11
|
+
## The two artifacts
|
|
12
|
+
|
|
13
|
+
Authoring a theme produces **two things**:
|
|
14
|
+
|
|
15
|
+
1. **A skill that describes the theme.** Captures intent, design choices, and the recipe for rendering to CSS. Lives wherever your skills live (the system that loads `SKILL.md`-style instructions for agents). This skill doesn't dictate the location — use whatever convention is in place.
|
|
16
|
+
2. **The rendered theme folder** at `<storagePath>/themes/<name>/theme.css` (plus any assets the CSS references). This is what Television actually reads at runtime.
|
|
17
|
+
|
|
18
|
+
The split matters because Television's token surface evolves across releases. A flat `theme.css` will drift; a skill that captures intent can be re-invoked to re-render `theme.css` against whatever the current surface looks like.
|
|
19
|
+
|
|
20
|
+
## How theming works in Television
|
|
21
|
+
|
|
22
|
+
- A theme folder lives at `<storagePath>/themes/<name>/`:
|
|
23
|
+
```
|
|
24
|
+
<storagePath>/themes/<name>/
|
|
25
|
+
theme.css ← required entry stylesheet
|
|
26
|
+
<other files> ← optional fonts, background images, supplementary CSS
|
|
27
|
+
```
|
|
28
|
+
- `theme.css` is a **partial overlay** — only the tokens the theme overrides. Everything else falls through to Television's defaults. A minimal theme is ~20 lines.
|
|
29
|
+
- One theme is active at a time, server-wide. Activated via `tv set-theme <name>` (or `tv set-theme default` to clear). The server broadcasts a `theme-changed` event; every connected client re-skins live.
|
|
30
|
+
- The active theme's `theme.css` is watched on disk — saving the file re-applies within ~50ms across all clients. Iteration is tight.
|
|
31
|
+
- Both surfaces (TV app chrome and rendered artifacts) re-skin from the same `theme.css`. No separate "app theme" vs "artifact theme."
|
|
32
|
+
|
|
33
|
+
## Styling surface
|
|
34
|
+
|
|
35
|
+
Television's CSS has two layers: a **token contract** (semantic colors, palettes, scales) and a **component structure** (the chrome surfaces and content surfaces those tokens compose into). Themes work primarily by overriding tokens; targeted selector rules are escape hatches when the tokens can't fully express a design intent.
|
|
36
|
+
|
|
37
|
+
### What you're skinning
|
|
38
|
+
|
|
39
|
+
Television is a single-screen-at-a-time display for AI-generated artifacts. The structural pieces:
|
|
40
|
+
|
|
41
|
+
- **The app shell.** A single window that always shows one active screen. There's no home page; the active screen is the page.
|
|
42
|
+
- **`<screen-select>`** — a top-edge or corner control listing available screens; lets the user switch.
|
|
43
|
+
- **`<command-panel>`** — persistent chrome that floats over content (bottom or corner). Hosts global commands and the chat input + message stream. Uses paper material in dark tone by default.
|
|
44
|
+
- **`<screen-view>` → `<layout-view>`** — page container holding the scrollable canvas where artifact cards live.
|
|
45
|
+
- **`<artifact-view>`** — each artifact card. Glass-material title bar wrapping a paper-material content surface (the artifact's rendered HTML, in an iframe).
|
|
46
|
+
- **Popovers, dropdowns, modals** — paper-material panels for transient and modal UI.
|
|
47
|
+
|
|
48
|
+
### The material / tone / level system
|
|
49
|
+
|
|
50
|
+
Three orthogonal attributes describe every UI surface:
|
|
51
|
+
|
|
52
|
+
- **`material="paper" | "glass"`** — `paper` is opaque ("this is the content, read me"); `glass` is translucent with a backdrop-filter blur ("I'm chrome over content, peek through me"). Themes affect both: paper surfaces show your `--color-surface`; glass surfaces blend it with what's behind.
|
|
53
|
+
- **`tone="light" | "dark"`** — flips three things on every descendant of the surface: body text color (descendants inherit a light foreground when `tone="dark"`), hairline edge color, and the overlay hover/active tokens. Anything using `currentColor` (icons, tints, `color: inherit` headings) flips automatically. This is what makes dark mode work without per-component overrides.
|
|
54
|
+
- **`level="1" | "2" | "overlay"`** — shadow stack only. `1` = small drop-shadow (popovers, dropdowns), `2` = lifted card (artifact bodies), `overlay` = no shadow (persistent chrome bonded to viewport, like the command panel).
|
|
55
|
+
|
|
56
|
+
If you want a dark theme: set `color-scheme: dark` and rely on the existing `[tone="dark"]` rules in `materials.css` to flip foregrounds across descendants — you don't need to override every component.
|
|
57
|
+
|
|
58
|
+
### The token contract
|
|
59
|
+
|
|
60
|
+
Two source files in `packages/ui/styles/`:
|
|
61
|
+
|
|
62
|
+
- **`tokens.css`** — palette and scales. Raw values: `--neutral-50` through `--neutral-950`, color palettes (`--red-*`, `--blue-*`, etc.), `--alpha-50` through `--alpha-950`, `--tint-50` through `--tint-950`, type scale (`--text-base`, `--text-sm`, `--text-lg`), spacing (`--space-2` through `--space-64`), radii (`--radius-4` through `--radius-full`), control heights (`--control-height-xs/sm/md`), shadows (`--shadow-hairline`, `--shadow-control`), fonts (`--font-sans`, `--font-mono`, `--font-brand`).
|
|
63
|
+
- **`theme.css`** — semantic mappings most themes override.
|
|
64
|
+
|
|
65
|
+
Current `theme.css` content as of this skill build (always read live source for the latest — see below):
|
|
66
|
+
|
|
67
|
+
```css
|
|
68
|
+
:root {
|
|
69
|
+
--color-bg: var(--neutral-50);
|
|
70
|
+
--color-bg-muted: var(--neutral-100);
|
|
71
|
+
--color-surface: var(--white);
|
|
72
|
+
--color-surface-muted: var(--neutral-100);
|
|
73
|
+
--color-interactive: var(--neutral-200);
|
|
74
|
+
--color-interactive-hover: var(--neutral-300);
|
|
75
|
+
|
|
76
|
+
/* Borders use alpha so the same hairline reads on light, dark, or
|
|
77
|
+
image bgs without needing a tone-aware swap. */
|
|
78
|
+
--color-border: rgba(0, 0, 0, 0.10);
|
|
79
|
+
--color-border-muted: rgba(0, 0, 0, 0.06);
|
|
80
|
+
|
|
81
|
+
--color-text: var(--neutral-900);
|
|
82
|
+
--color-text-muted: var(--neutral-500);
|
|
83
|
+
--color-link: inherit;
|
|
84
|
+
--color-focus-ring: var(--neutral-500);
|
|
85
|
+
--color-overlay-backdrop: rgb(0 0 0 / 0.5);
|
|
86
|
+
--color-highlight: rgb(255 255 255 / 0.5);
|
|
87
|
+
--color-primary: var(--blue-500);
|
|
88
|
+
--color-danger: var(--red-600);
|
|
89
|
+
|
|
90
|
+
color-scheme: light;
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`color-scheme: dark` flips OS-level chrome (scrollbars, form controls) — set it for dark themes so native widgets don't fight the look.
|
|
95
|
+
|
|
96
|
+
### Reading the live token surface
|
|
97
|
+
|
|
98
|
+
The block above is a build-time snapshot. **For any nontrivial theme, also read the actual `tokens.css` and `theme.css` files at authoring time** to catch additions/renames/removals since this skill was last built.
|
|
99
|
+
|
|
100
|
+
Preferred — fetch from a running Television server:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Default local server URL is http://localhost:32848
|
|
104
|
+
curl http://localhost:32848/canonical/v1/styles.css | head -300
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The bundled canonical stylesheet inlines both `tokens.css` and `theme.css`. If you're talking to a non-default server, get the URL from `tv state` or from the connection the user is targeting.
|
|
108
|
+
|
|
109
|
+
Alternative — from a Television source checkout:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
cat <television-checkout>/packages/ui/styles/tokens.css <television-checkout>/packages/ui/styles/theme.css
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Tokens vs. selectors — pick the right tool
|
|
116
|
+
|
|
117
|
+
Themes have two complementary tools:
|
|
118
|
+
|
|
119
|
+
- **Override semantic tokens on `:root`** when you want a change to propagate everywhere it's relevant — every paper surface, every body text, every focus ring. One token edit, system-wide effect. Use this for the look's foundations: backgrounds, foregrounds, primary accents, border weights.
|
|
120
|
+
- **Override specific selectors** when the intent is local to a surface — the chat input gets a special background, the artifact title bar uses a custom font, the layout canvas gets a subtle background image. Selectors give surgical control; tokens can't always express what a design wants.
|
|
121
|
+
|
|
122
|
+
Both are first-class. A typical theme uses tokens for ~80% of its effect and selector-level rules for the rest. Don't avoid selectors out of orthodoxy; use them where they fit.
|
|
123
|
+
|
|
124
|
+
The one rule for selector-level rules: **comment them with their purpose.** When Television's component structure shifts in a future release, the comment is what lets an agent re-author the rule against the new structure. Without the comment, a stale selector is just dead CSS — nobody knows what it was for.
|
|
125
|
+
|
|
126
|
+
## Surface-by-surface guidance
|
|
127
|
+
|
|
128
|
+
A theme that touches `:root` tokens will affect every surface listed below. The notes here describe what each surface consumes so you know which tokens drive which look — useful for predicting how a token change will land.
|
|
129
|
+
|
|
130
|
+
### App background and wallpaper
|
|
131
|
+
|
|
132
|
+
`<television-app>` is the root surface — the thing that fills the window. Out of the box it shows a bundled wallpaper image with a fallback background color. Two app-level tokens control this layer:
|
|
133
|
+
|
|
134
|
+
- **`--app-bg`** — base background color, defaulting to `var(--color-bg)`. Shows through wherever `--app-wallpaper` is transparent or set to `none`.
|
|
135
|
+
- **`--app-wallpaper`** — the `background-image` value, defaulting to the bundled wallpaper `url(...)`. Set this to `none` to remove the wallpaper (so `--app-bg` shows), or to a `url(...)` (typically pointing at a theme asset) to use a custom wallpaper.
|
|
136
|
+
|
|
137
|
+
Theme levers:
|
|
138
|
+
|
|
139
|
+
- Want a flat colored background? `:root { --app-wallpaper: none; }` and override `--color-bg` (or `--app-bg` directly for finer control).
|
|
140
|
+
- Want a custom wallpaper? `:root { --app-wallpaper: url(my-bg.jpg); }` where `my-bg.jpg` is in the theme's `resources/` folder (the server will rewrite the relative URL).
|
|
141
|
+
- The default-look bundled wallpaper is `packages/web/src/assets/wallpaper-s.jpg` — themes don't import or reference it; they replace the variable.
|
|
142
|
+
|
|
143
|
+
### Buttons
|
|
144
|
+
|
|
145
|
+
Television has three button stories: variant-styled buttons, ghost buttons (chromeless overlay hover), and bespoke chrome-button shapes (close buttons, breadcrumbs, etc.).
|
|
146
|
+
|
|
147
|
+
What each consumes:
|
|
148
|
+
|
|
149
|
+
- **Default `<button>`** — `--color-text` (text), `--color-interactive` (resting bg), `--color-interactive-hover` (hover bg), `--control-height-md` (28px outer height), `--shadow-control` (subtle drop shadow on resting state).
|
|
150
|
+
- **`<button variant="ghost">`** — fully chromeless, no fill. Hover/active backgrounds use `--color-overlay-hover` / `--color-overlay-active` (semantic overlay tokens that auto-flip with the surface's `tone`). The ghost-button auto-tone watcher (`packages/ui/utils/button-tone.ts`) samples the surface under each ghost button and sets `tone="dark"` or `tone="light"` on the button itself so its hover tint reads against the local backdrop.
|
|
151
|
+
- **`<button variant="primary">`** — emphasis button. Fills with `--color-primary` for the bg, `--white` for text.
|
|
152
|
+
- **Icon-only buttons** — `<button icon-only>` becomes a square at `--control-height-md` per side.
|
|
153
|
+
|
|
154
|
+
Theme levers:
|
|
155
|
+
|
|
156
|
+
- Adjust `--color-interactive` / `--color-interactive-hover` for default-button affordance.
|
|
157
|
+
- Adjust `--color-overlay-hover` / `--color-overlay-active` to change ghost-button hover intensity (these also affect dropdown items and other chromeless overlays).
|
|
158
|
+
- Adjust `--color-primary` for emphasis-button fills.
|
|
159
|
+
- Don't set `cursor: pointer` on buttons — there's a global rule in `elements.css` that sets `cursor: default` to match the macOS-native feel.
|
|
160
|
+
|
|
161
|
+
### Artifact title bars
|
|
162
|
+
|
|
163
|
+
The chrome strip at the top of each `<artifact-view>` card. Uses **glass** material (translucent + backdrop-blur). Tone is sampled from the artifact content beneath it, so the title bar adapts: a dark-content artifact gets `tone="dark"` and a light-foreground title; a light-content artifact gets the inverse.
|
|
164
|
+
|
|
165
|
+
What it consumes:
|
|
166
|
+
|
|
167
|
+
- The glass tint (which composites against the artifact body) — driven by `materials.css` rules referencing the alpha scale and current surface tone.
|
|
168
|
+
- `--color-text` / `--color-text-muted` for the title text and any sub-text.
|
|
169
|
+
- `--color-border` for the hairline rim around the glass surface.
|
|
170
|
+
|
|
171
|
+
Theme levers:
|
|
172
|
+
|
|
173
|
+
- Adjust `--color-border` to change the title bar's edge weight.
|
|
174
|
+
- Adjust the title's font weight or letter spacing via selector-level rules on `artifact-view > header` if the design needs a non-token change (comment the rule with purpose).
|
|
175
|
+
|
|
176
|
+
### Command panel — input + chat stream
|
|
177
|
+
|
|
178
|
+
`<command-panel>` is the persistent chrome at the bottom (or corner) of the app. It hosts the chat input (typically a textarea) and the message stream above it. By default uses **paper** material in **dark** tone, **`level="overlay"`** (no shadow — it's bonded to the viewport).
|
|
179
|
+
|
|
180
|
+
What it consumes:
|
|
181
|
+
|
|
182
|
+
- The paper-dark surface — a near-black opaque fill defined by `materials.css` reading from the `[tone="dark"]` overrides of `--color-surface` and related tokens.
|
|
183
|
+
- `--color-text` (descendants inherit, but with `tone="dark"` flipping descendants to a light foreground).
|
|
184
|
+
- `--color-text-muted` for secondary text in the stream (timestamps, system messages).
|
|
185
|
+
- `--color-border` / `--color-border-muted` for separators between messages.
|
|
186
|
+
- The input's textarea consumes `--color-interactive` (background) and `--color-border` (rim).
|
|
187
|
+
|
|
188
|
+
Theme levers:
|
|
189
|
+
|
|
190
|
+
- Override the dark-tone surface color: target `[tone="dark"]` in your theme and set `--color-surface` (or set it on `command-panel` directly with a purpose comment).
|
|
191
|
+
- Adjust message-stream separator weight via `--color-border-muted`.
|
|
192
|
+
- Adjust the chat input's affordance via `--color-interactive`.
|
|
193
|
+
- For dramatic looks (a saturated chat background, a textured chat surface), target `command-panel` directly with a purpose comment.
|
|
194
|
+
|
|
195
|
+
### Popovers and dropdowns
|
|
196
|
+
|
|
197
|
+
Anchored panels for menus and inline forms. Paper material, light tone typically, `level="1"` (small drop-shadow). Dismiss on outside click.
|
|
198
|
+
|
|
199
|
+
What they consume:
|
|
200
|
+
|
|
201
|
+
- `--color-surface` (paper fill).
|
|
202
|
+
- `--color-border` (hairline rim).
|
|
203
|
+
- `--color-text` (label text), `--color-text-muted` (secondary labels).
|
|
204
|
+
- `--color-overlay-hover` / `--color-overlay-active` for hover/active states on individual items (these are *also* used by ghost buttons, so changing them affects both surfaces — usually fine, since the relationship is semantic).
|
|
205
|
+
- `--shadow-control` for the drop shadow (defined as a soft 2-layer shadow).
|
|
206
|
+
|
|
207
|
+
Theme levers:
|
|
208
|
+
|
|
209
|
+
- Surface color via `--color-surface`.
|
|
210
|
+
- Hairline rim via `--color-border`.
|
|
211
|
+
- The overlay-hover token controls both popover-item and ghost-button hover; usually move them together.
|
|
212
|
+
|
|
213
|
+
### Modal sheets
|
|
214
|
+
|
|
215
|
+
Full-screen overlays for blocking flows. Paper material, larger than popovers, no specific level (often `level="2"`).
|
|
216
|
+
|
|
217
|
+
What they consume:
|
|
218
|
+
|
|
219
|
+
- `--color-surface` (fill).
|
|
220
|
+
- `--color-overlay-backdrop` for the scrim behind the modal (the dark veil over the rest of the app while the modal is open).
|
|
221
|
+
- All the popover tokens for internal elements.
|
|
222
|
+
|
|
223
|
+
Theme levers:
|
|
224
|
+
|
|
225
|
+
- The scrim via `--color-overlay-backdrop`.
|
|
226
|
+
- The modal surface via `--color-surface`.
|
|
227
|
+
|
|
228
|
+
### Layout canvas
|
|
229
|
+
|
|
230
|
+
The scrollable area inside `<screen-view>` where artifact cards live. Has its own scroll position and pan/zoom semantics.
|
|
231
|
+
|
|
232
|
+
What it consumes:
|
|
233
|
+
|
|
234
|
+
- `--color-bg` for the canvas background (the "page" surface).
|
|
235
|
+
- `--color-bg-muted` if the canvas distinguishes content areas (e.g. gutter regions vs. card region).
|
|
236
|
+
- `--color-border-muted` for any grid lines, if a future debug mode shows them.
|
|
237
|
+
|
|
238
|
+
Theme levers:
|
|
239
|
+
|
|
240
|
+
- `--color-bg` is the highest-leverage single token in any theme — it determines the page's overall feel.
|
|
241
|
+
- `--color-bg-muted` for related secondary surfaces.
|
|
242
|
+
|
|
243
|
+
### Bare HTML in artifacts
|
|
244
|
+
|
|
245
|
+
Artifact content is HTML rendered inside an iframe. The iframe links `/canonical/v1/styles.css`, which the server composes from the canonical bundle plus your active theme. So everything below works in artifacts the same way it does in the app chrome.
|
|
246
|
+
|
|
247
|
+
Default styling for bare tags is in `packages/ui/styles/elements.css`:
|
|
248
|
+
|
|
249
|
+
- `<body>` uses `--color-bg` background, `--color-text` text, `--font-sans` family.
|
|
250
|
+
- `<h1>`–`<h6>` use `--font-brand` (often the same as `--font-sans` unless overridden), with the type scale tokens (`--text-base`, `--text-lg`, `--text-xl`) and `--color-text` for color.
|
|
251
|
+
- `<a>` uses `--color-link` (defaults to `inherit` — links read in the body color unless a theme sets otherwise).
|
|
252
|
+
- `<code>` and `<pre>` use `--font-mono`, `--color-bg-muted` for the background, `--color-text` for content.
|
|
253
|
+
- Form controls (`<input>`, `<textarea>`, `<select>`) consume `--control-height-md`, `--color-interactive`, `--color-border`, `--color-focus-ring`.
|
|
254
|
+
|
|
255
|
+
Theme levers:
|
|
256
|
+
|
|
257
|
+
- The same `:root` tokens that drive the app chrome drive bare HTML — there's no separate "artifact theme."
|
|
258
|
+
- For a theme with a distinctive link color (e.g. a brand accent), set `--color-link: <value>`.
|
|
259
|
+
- For a theme with a custom code/pre font, override `--font-mono`.
|
|
260
|
+
|
|
261
|
+
## What's in scope for a theme
|
|
262
|
+
|
|
263
|
+
- CSS custom properties on `:root` — the primary tool.
|
|
264
|
+
- `@font-face` declarations for custom typography (font files in the skill's `resources/` folder; reference relatively from `theme.css`, e.g. `url(MyFont.woff2)` — the render step copies them into the theme folder).
|
|
265
|
+
- Background images, decorative images (same path — `resources/` in the skill, copied alongside `theme.css`).
|
|
266
|
+
- `@media (prefers-color-scheme: dark)` blocks if the theme should react to OS-level light/dark.
|
|
267
|
+
- Selector-level rules **with purpose comments** for design intent the tokens can't fully express.
|
|
268
|
+
|
|
269
|
+
## What's out of scope
|
|
270
|
+
|
|
271
|
+
- JavaScript hooks — themes are static styling assets.
|
|
272
|
+
- Theme manifests with metadata beyond the SKILL.md.
|
|
273
|
+
- Multiple variants within one theme (a theme is one look; if you want a dark variant of a light theme, that's a separate theme).
|
|
274
|
+
|
|
275
|
+
## Workflow
|
|
276
|
+
|
|
277
|
+
Theme authoring has two phases. **Iterate first** — work directly on `theme.css` with the live-reload loop, see changes immediately, refine until the user is happy. **Then export to a skill** — capture the intent so the theme survives future Television versions.
|
|
278
|
+
|
|
279
|
+
### Phase A: Iterate live on theme.css
|
|
280
|
+
|
|
281
|
+
1. **Gather intent from the user.** Aesthetic / vibe / references, palette, typography choices, any specific surfaces they care about. Don't design before understanding — clear intent saves rendering loops.
|
|
282
|
+
2. **Read the current Television token surface.** See "The token surface" section above; identify which semantic tokens map to the user's intent. Don't override tokens that don't exist in the current surface.
|
|
283
|
+
3. **Pick a name** matching `^[a-z0-9][a-z0-9-]*$` (e.g. `paperlike`, `cyberpunk-arcade`). The reserved value `default` cannot be used — it's the CLI sentinel for clearing the active theme.
|
|
284
|
+
4. **Write `<storagePath>/themes/<name>/theme.css`** with your initial overrides. Place any assets (fonts, images) alongside it.
|
|
285
|
+
5. **Activate it:** `tv set-theme <name>`. The app re-skins immediately.
|
|
286
|
+
6. **Iterate.** Edits to `theme.css` propagate within ~50ms — no PATCH, no reload. Listen to the user's feedback ("bump the primary, lower the body contrast"), edit the file, watch the result. This is where the bulk of theme work happens.
|
|
287
|
+
7. **Comment selector-level rules with their purpose.** When the look needs more than token overrides, add selector-level rules — and explain *why* each one exists in a comment above it. Television's internals can shift; the comment is what lets a future agent re-target the rule.
|
|
288
|
+
|
|
289
|
+
```css
|
|
290
|
+
/*
|
|
291
|
+
* Active artifact title bar gets a faint warm tint as a quiet "you are here"
|
|
292
|
+
* cue — design wanted on-screen orientation without a heavier indicator.
|
|
293
|
+
*/
|
|
294
|
+
[data-active] > .artifact-title {
|
|
295
|
+
background: color-mix(in srgb, var(--color-text) 4%, transparent);
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Phase B: Export to a skill once the look is settled
|
|
300
|
+
|
|
301
|
+
When the user is happy with the theme, capture it as a skill. The skill is the durable artifact — Television's token surface evolves, components get refactored, and a flat `theme.css` from today may render incorrectly under a future version. The skill carries enough context (intent, design choices, per-rule purpose) that an agent can re-render the theme cleanly against a new surface.
|
|
302
|
+
|
|
303
|
+
Create a new skill — wherever skills live in the user's environment. Folder layout:
|
|
304
|
+
|
|
305
|
+
```
|
|
306
|
+
<theme-skill-folder>/
|
|
307
|
+
SKILL.md # intent + design choices + style overrides + render instructions
|
|
308
|
+
resources/ # assets the rendered theme.css references (fonts, images, etc.)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
The SKILL.md should have:
|
|
312
|
+
|
|
313
|
+
- **Frontmatter** with `name` following the convention `tv-theme-<name>` (e.g. `tv-theme-paperlike`) and `description` (one-line aesthetic summary). The `tv-theme-` prefix scopes the skill to Television theming so it's discoverable alongside the bundled `television-theme` meta-skill.
|
|
314
|
+
- **Intent.** 1–3 paragraphs describing the look and the user-facing pitch. Specific enough that another agent (or you, six months later) could re-author this theme from scratch from this section alone.
|
|
315
|
+
- **References.** Optional — inspirations, links, screenshots, brand/product references.
|
|
316
|
+
- **Design choices.** Bulleted list of decisions with rationale. E.g. *"Background is near-black to evoke low-light comfort"*, *"Primary accent is muted teal — saturated enough to read on dark, restrained enough not to scream."*
|
|
317
|
+
- **Style overrides.** Copy the contents of the iterated `theme.css`, comments and all. The purpose comments you wrote during iteration are what make the theme re-renderable.
|
|
318
|
+
- **Assets.** List of files in `resources/`, what each is, what `theme.css` rule references it. Copy the assets from the live theme folder into `resources/`.
|
|
319
|
+
- **Render instructions.** A short section telling future invocations how to render this skill: "fetch the live Television token surface (`/canonical/v1/styles.css` or `<checkout>/packages/ui/styles/{tokens,theme}.css`); map this skill's Intent + Design choices + Style overrides onto the current surface; emit `<storagePath>/themes/<name>/theme.css` and copy `resources/*` to `<storagePath>/themes/<name>/`."
|
|
320
|
+
|
|
321
|
+
Once exported, the iterated `<storagePath>/themes/<name>/` folder and the skill should be in sync. Future edits should happen in both — update `theme.css` for the live feedback loop, update the skill's **Style overrides** section in lockstep so the durable record stays current. If they drift, the skill is the source of truth.
|
|
322
|
+
|
|
323
|
+
## Re-rendering across Television versions
|
|
324
|
+
|
|
325
|
+
When Television's token surface or component structure changes (new tokens added, existing tokens renamed or repurposed, components renamed, selector-level rules in a theme become stale), the theme's `theme.css` may render incorrectly under the new version — variables that no longer exist do nothing, new variables that the theme should set are missed, selector-level rules may target elements that no longer exist.
|
|
326
|
+
|
|
327
|
+
Recovery procedure (the theme skill makes this possible):
|
|
328
|
+
|
|
329
|
+
1. **Read the current Television surface:**
|
|
330
|
+
- Running server: `curl http://localhost:32848/canonical/v1/styles.css | head -300` (or substitute the actual server URL from `tv state`).
|
|
331
|
+
- Or, from a checkout: `cat <television-checkout>/packages/ui/styles/{tokens,theme}.css`.
|
|
332
|
+
2. **Read the theme's skill** — especially the **Intent**, **Design choices**, and the *comments* in the **Style overrides** section. The comments are what let you re-author selector-level rules: even if `.artifact-title` no longer exists, the comment "*active card gets a faint warm tint as a 'you are here' cue*" tells you what to target with whatever selector achieves that intent on the new version.
|
|
333
|
+
3. **Map the original intent onto the new surface.** Token overrides that reference tokens still present transfer directly. Renamed tokens get re-mapped. New semantic tokens added to Television may need to be set to fit the theme's vibe. Selector-level rules get re-expressed against the new structure.
|
|
334
|
+
4. **Update the skill's Style overrides section** with the revised rules (keep the purpose comments updated).
|
|
335
|
+
5. **Re-render**: write the updated CSS to `<storagePath>/themes/<name>/theme.css` and re-copy any new/changed assets from `resources/`.
|
|
336
|
+
6. **Activate and verify visually** — `tv set-theme <name>`, walk through the app.
|
|
337
|
+
|
|
338
|
+
Without the skill capturing intent and per-rule purpose comments, this would be reverse-engineering from CSS — lossy. The skill is the durable artifact; `theme.css` is the build output that may need refreshing across versions.
|
|
339
|
+
|
|
340
|
+
## Smoke test before declaring done
|
|
341
|
+
|
|
342
|
+
After authoring:
|
|
343
|
+
|
|
344
|
+
1. `tv set-theme <name>` — does the app re-skin without errors?
|
|
345
|
+
2. Open the app, navigate around — does the chrome look right? Any elements that look wrong (unreadable text, wrong contrast, broken borders)?
|
|
346
|
+
3. Look at an existing artifact — does it pick up the theme?
|
|
347
|
+
4. `tv set-theme default` — does it return to the bundled look cleanly?
|
|
348
|
+
|
|
349
|
+
If any of these fail, the theme is incomplete. Fix and re-test.
|