@ammduncan/easel 0.2.27 → 0.2.28

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/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable changes to easel. This project adheres to [Semantic Versioning](https://semver.org/).
4
4
 
5
+ ## 0.2.28 — 2026-05-25
6
+
7
+ ### Added
8
+ - **Built-in `.code` / `.terminal` code-block primitive — kills the invisible-code-block bug at the source.** The single most recurring failure was a hand-rolled dark code container: an agent sets `background:#0f172a` on a custom div but leaves base text inheriting `.wrap`'s `light-dark(#111,…)`, which resolves to near-black in light host mode and vanishes against the dark panel (only the explicitly-coloured syntax spans survive). The guidance to lock bg+ink as a pair was correct but purely advisory — it relied on the agent remembering it every push. Now the wrapper ships a baked-in primitive: `<div class="code">` (alias `.terminal`) locks both background and ink, re-scopes `color: inherit` to every child, and provides the verified github-dark token classes (`.kw .string .fn .prop .num .comment .muted .accent`) so syntax highlighting reads against `#0f172a` with no per-token tuning. Same lever as the existing `.window` chrome — a safe primitive agents reach for instead of hand-rolling. Prints on white paper with dark text like `pre`/`code`.
9
+
10
+ ### Docs
11
+ - **Steered the `push` tool description and skill toward the new primitive.** The locked-mode section now leads with "use the built-in `.code`/`.terminal`, don't hand-roll", demoting the hand-rolled CSS to a fallback for other locked containers (brand heroes, custom callouts). Added a "Code & terminal blocks" entry to the skill's Built-in helpers. Plain `<pre>`/`<code>` remain safe (bg+ink token pair) as before.
12
+
5
13
  ## 0.2.27 — 2026-05-23
6
14
 
7
15
  ### Fixed
@@ -837,6 +837,35 @@ pre {
837
837
  margin: 16px 0 24px;
838
838
  }
839
839
  pre code { background: transparent; padding: 0; color: inherit; font-size: inherit; }
840
+ /* Locked-dark code / terminal primitive. Reach for this instead of hand-rolling
841
+ a dark code container — the recurring failure is a custom dark <div> that sets
842
+ its own background but lets base text inherit .wrap's light-dark() ink, which
843
+ resolves to near-black in light host mode and vanishes against the dark panel.
844
+ This class locks BOTH background and ink, and re-scopes color:inherit to every
845
+ child so the host theme can never leak in. Ships the verified github-dark token
846
+ palette so syntax highlighting reads against #0f172a without per-token tuning.
847
+ Usage: <div class="code"><span class="kw">gcloud</span> services enable …</div>
848
+ .terminal is an alias; add .terminal for a prompt feel (same colors). */
849
+ .code, .terminal {
850
+ background: #0f172a;
851
+ color: #e6edf3;
852
+ border-radius: 12px;
853
+ padding: 18px 22px;
854
+ font-family: ui-monospace, "SF Mono", Menlo, monospace;
855
+ font-size: 13.5px;
856
+ line-height: 1.7;
857
+ overflow: auto;
858
+ margin: 16px 0 24px;
859
+ }
860
+ .code *, .terminal * { color: inherit; }
861
+ .code .kw, .terminal .kw { color: #ff7b72; } /* keywords, control flow */
862
+ .code .string, .terminal .string { color: #a5d6ff; } /* strings, attr values */
863
+ .code .fn, .terminal .fn { color: #d2a8ff; } /* function names */
864
+ .code .prop, .terminal .prop { color: #79c0ff; } /* identifiers, properties */
865
+ .code .num, .terminal .num { color: #ffa657; } /* numbers, constants */
866
+ .code .comment, .terminal .comment { color: #8b949e; } /* comments */
867
+ .code .muted, .terminal .muted { color: #94a3b8; } /* dim / secondary */
868
+ .code .accent, .terminal .accent { color: #6ee7b7; } /* highlight / success */
840
869
  blockquote {
841
870
  border-left: 3px solid var(--ds-accent);
842
871
  margin: 18px 0;
@@ -883,7 +912,8 @@ img { max-width: 100%; height: auto; border-radius: 10px; }
883
912
  body { padding: 24px !important; max-width: none !important; }
884
913
  body > p, body > .deck, body > .lede, body > ul, body > ol, body > blockquote,
885
914
  body > h1, body > h2, body > h3, body > h4 { max-width: none !important; }
886
- pre, code { background: #f4f3ed !important; color: #111 !important; border: 1px solid #ddd; }
915
+ pre, code, .code, .terminal { background: #f4f3ed !important; color: #111 !important; border: 1px solid #ddd; }
916
+ .code *, .terminal * { color: #111 !important; }
887
917
  .card, .panel { background: #fff !important; border: 1px solid #ddd !important; box-shadow: none !important; }
888
918
  a { color: #111 !important; text-decoration: underline; border-bottom: 0 !important; }
889
919
  }
package/dist/mcp.js CHANGED
@@ -112,12 +112,17 @@ export async function main() {
112
112
  " .wrap { color: light-dark(#111, #e8e8e8); padding: 56px 48px; font-family: -apple-system, 'Inter', system-ui, sans-serif; max-width: 820px; }\n" +
113
113
  " .wrap *, .wrap h1, .wrap h2, .wrap h3, .wrap p, .wrap li, .wrap span { color: inherit; }\n" +
114
114
  " .card { background: light-dark(#fff, #161616); border: 1px solid light-dark(#e0d9c3, #2a2a2a); border-radius: 12px; padding: 24px; }\n\n" +
115
- "═══ COPY-PASTE STARTER (LOCKED-MODE containerterminal, code block, brand hero) ═══\n" +
116
- "If a container has a FIXED background (not `light-dark()`), you MUST set its own text color AND re-scope `color: inherit` to its children. Otherwise the children inherit `light-dark(...)` from `.wrap` and the text flips to the wrong shade in one mode (e.g. dark text on a locked-dark terminal in light host mode invisible). This is the #1 thing that goes wrong on terminals and code blocks.\n" +
117
- " .terminal { background: #0f172a; color: #e6edf3; border-radius: 12px; padding: 20px 24px; font-family: ui-monospace, 'SF Mono', Menlo, monospace; font-size: 13.5px; line-height: 1.7; }\n" +
118
- " .terminal *, .terminal span, .terminal pre { color: inherit; }\n" +
119
- " .terminal .muted { color: #94a3b8; }\n" +
120
- " .terminal .accent { color: #6ee7b7; }\n" +
115
+ "═══ CODE / TERMINAL BLOCKSUSE THE BUILT-IN PRIMITIVE, DON'T HAND-ROLL ═══\n" +
116
+ "The #1 recurring bug is a hand-rolled dark code container: you set `background:#0f172a` on a custom div but leave base text inheriting `.wrap`'s `light-dark(#111,…)`, which resolves to near-black in light host mode and VANISHES against the dark panel (only the explicitly-coloured syntax spans survive). Don't hand-roll it. The wrapper ships a baked-in, always-safe primitive:\n" +
117
+ " <div class=\"code\"> </div> (alias: class=\"terminal\")\n" +
118
+ "It locks BOTH background (#0f172a) and ink (#e6edf3), re-scopes `color:inherit` to every child, and provides verified github-dark syntax token classes you can drop onto spans — NO per-token tuning needed:\n" +
119
+ " .kw (keywords #ff7b72) · .string (#a5d6ff) · .fn (function #d2a8ff) · .prop (identifiers #79c0ff) · .num (#ffa657) · .comment (#8b949e) · .muted (#94a3b8) · .accent (#6ee7b7)\n" +
120
+ " e.g. <div class=\"code\"><span class=\"kw\">gcloud</span> services enable run.googleapis.com</div>\n" +
121
+ "Plain <pre>/<code> are also already safe (bg+ink token pair). Only reach for a fully custom container when .code/.terminal genuinely don't fit — and then obey the locked-mode rule below.\n\n" +
122
+ "═══ COPY-PASTE STARTER (any OTHER LOCKED-MODE container — brand hero, custom panel) ═══\n" +
123
+ "If a container has a FIXED background (not `light-dark()`), you MUST set its own text color AND re-scope `color: inherit` to its children. Otherwise the children inherit `light-dark(...)` from `.wrap` and the text flips to the wrong shade in one mode (e.g. dark text on a locked-dark panel in light host mode → invisible).\n" +
124
+ " .hero { background: #0f172a; color: #e6edf3; border-radius: 12px; padding: 20px 24px; }\n" +
125
+ " .hero * { color: inherit; }\n" +
121
126
  "• Same pairing applies in the OPPOSITE direction — locked-LIGHT containers (e.g. a white card on the host canvas). A `.card { background: #fff }` with no `color:` inherits `.wrap`'s light-dark() text, which in dark host mode resolves to a light cream/gray → invisible titles on a white card. Commit text too AND re-scope inherit on children. This bites just as often as the dark case.\n" +
122
127
  " .card { background: #ffffff; color: #111111; border: 1px solid #e5e5e5; border-radius: 12px; padding: 24px 32px; }\n" +
123
128
  " .card * { color: inherit; }\n" +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ammduncan/easel",
3
- "version": "0.2.27",
3
+ "version": "0.2.28",
4
4
  "description": "A live browser tab for every Claude Code (and MCP) session. The push MCP tool appends HTML cards to a scrolling feed you keep open in split-screen.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -205,8 +205,10 @@ So the rule is **faithful height, not minimal height** — but always expressed
205
205
 
206
206
  The test: cropped the same way, would your mock look like a screenshot of the real thing? Empty bands the real screen doesn't have = over-padded. A desktop screen squashed to a short strip = under-sized.
207
207
 
208
+ **For code / terminal blocks, don't hand-roll — use the built-in `.code` / `.terminal` primitive** (see Built-in helpers below). It already locks bg + ink, re-scopes `color: inherit` to children, and ships the verified github-dark token palette. The hand-rolled patterns below are the fallback for *other* locked containers (brand heroes, custom dark callouts) where no primitive fits.
209
+
208
210
  ```css
209
- /* Locked-dark container (terminal, dark code block, dark callout). */
211
+ /* Locked-dark container (custom dark callout, brand hero). */
210
212
  .terminal {
211
213
  background: #0f172a; /* locked dark, ignores host mode */
212
214
  color: #e6edf3; /* MUST set text too */
@@ -328,6 +330,20 @@ The width rule above has a vertical twin, and it's the more common footgun: **ne
328
330
  - **Decorative frames** (browser chrome, phone bezel, device frame) must grow with their content — give the frame `min-height` and let it expand, or don't constrain height at all.
329
331
  - **The mental test:** render the tallest card in your head. If any text or button could exceed the container, the container is wrong. When unsure, leave height unset. A mockup exists to show the design *fully* — uniform-looking rectangles are never worth clipped content; let frames be different heights.
330
332
 
333
+ ### Code & terminal blocks
334
+
335
+ Reach for the built-in **`.code`** (alias **`.terminal`**) class instead of hand-rolling a dark code container — that hand-roll is the single most recurring failure (custom `background:#0f172a` div + base text inheriting `.wrap`'s `light-dark(#111,…)` → invisible in light host mode). The primitive locks bg + ink, re-scopes `color: inherit` to children, and ships the verified github-dark token palette so syntax highlighting reads against `#0f172a` with no per-token tuning:
336
+
337
+ ```html
338
+ <div class="code">
339
+ <span class="kw">gcloud</span> services enable run.googleapis.com
340
+ <span class="comment"># dvla artifact registry</span>
341
+ <span class="prop">--location=</span><span class="string">europe-west1</span>
342
+ </div>
343
+ ```
344
+
345
+ Token classes: `.kw` (keywords) · `.string` · `.fn` (functions) · `.prop` (identifiers/properties) · `.num` · `.comment` · `.muted` · `.accent`. Plain `<pre>`/`<code>` are already safe too (bg + ink token pair). Only hand-roll a custom dark container when neither fits — and then obey the locked-mode pairing rule above.
346
+
331
347
  ### Semantic chips
332
348
 
333
349
  ```html