@ammduncan/easel 0.5.0 → 0.5.1

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,16 @@
2
2
 
3
3
  All notable changes to easel. This project adheres to [Semantic Versioning](https://semver.org/).
4
4
 
5
+ ## 0.5.1 — 2026-05-31
6
+
7
+ ### Changed
8
+ - **Sharpened the `using-easel` skill's `kind:"mockup"` decision rule and added a no-`100vh`-rail height rule** — both targeting recurring app-fidelity authoring bugs. The decision section now leads with the real question — *"is the WHOLE push one full-bleed app screen, or is it prose + embedded specimen(s)?"* — and spells out that a review card / spec sheet / lookbook page (eyebrow + heading + prose + labelled specimen images) is a **presentation**, so `kind` should be left **off**: the prose then lands in the ~56ch reading measure with comfortable side padding, while specimens go in `.full-bleed` and fill the wider content column. Tagging such a card `kind:"mockup"` strips the prose-width cap *and* the body padding, so paragraphs run to the card edge — a bug observed repeatedly in marketing-kit/lookbook cards whose wrapper hand-set only `padding:8px 4px`. A failure-mode callout now documents it, plus the reminder that prose only gets the cap as a direct `body` child or inside `div.wrap`. The new height rule: within a full-screen mockup, never pin an inner rail/sidebar to `100vh`/`min-height:100vh` while the main column is shorter — the rail paints past the content and the self-measured frame inherits the dead band; flex-stretch the shell (`display:flex; align-items:stretch`, no height on the rail) so the rail can only ever be as tall as the tallest column. Docs-only; no runtime change.
9
+
10
+ ## 0.5.0 — 2026-05-29
11
+
12
+ ### Fixed
13
+ - **Exports of pushes built from nested `<iframe srcdoc>` panels (e.g. lookbook specimen grids) are no longer blank.** `html-to-image` can't reach into nested iframes, and the outer push iframe is opaque-origin, so a push composed of nested-iframe panels exported with every panel empty. A capture bridge is now injected into each nested `srcdoc` at wrap time; on export the parent asks each nested frame to render itself (`toSvg`) and composites the results onto the canvas at each frame's measured rect. Lazy nested frames are eagerly loaded before capture, and the export watchdog was extended (30s → 2min) so large multi-panel PNG/PDF renders don't time out.
14
+
5
15
  ## 0.4.2 — 2026-05-28
6
16
 
7
17
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ammduncan/easel",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
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",
@@ -210,6 +210,8 @@ A mockup's height should match what it actually represents — don't fake it tal
210
210
 
211
211
  **Mocking a full desktop screen / page** (the whole viewport — a login screen, a dashboard, a settings page): give it **realistic desktop viewport proportions**, because the surrounding space *is* part of how that screen looks. A login form genuinely sits in a ~720–800 px-tall viewport with the panel centred — cropping that down to just the form's content height misrepresents it as much as over-padding a component does. Use **`min-height`** for the floor (e.g. `min-height: 760px` or a 16:10 box) — **never a fixed `height`**, which clips anything taller — and lay the content out inside it the way the real screen does (centred form, top nav, sidebar full-height, etc.). This mirrors the wrapper's own `.window.desktop`, which is `min-height: 900px`, not `height`.
212
212
 
213
+ **Within a full-screen mockup, size the SHELL to content — never pin an inner rail/sidebar to the viewport.** A common miss: the screen is a sidebar + main column, and the sidebar (or a hero rail) gets `height: 100vh` / `min-height: 100vh` while the main column is shorter. The rail then paints far past the content, and the iframe's self-measure inherits that dead band — a tall dark strip below the real UI. **Fix:** make the shell a flex row and let the rail **stretch to content** — `display: flex; align-items: stretch` (the default) with **no height on the rail** — so the rail can only ever be as tall as the tallest column. Put any `min-height` floor on the *outer* screen if you want viewport proportions; never on an inner rail. (This was a real bug: a Ledger dashboard mock's dark rail was pinned to `100vh` against short content; the rebuilt version with flex-stretch measured rail-height === main-height exactly, band gone.)
214
+
213
215
  So the rule is **faithful height, not minimal height** — but always expressed as `min-height`, never a fixed `height`:
214
216
  - Component → content height (no padding to a fake screen size).
215
217
  - Full screen → real viewport proportions via `min-height` (don't crop to content, but don't cap it with a fixed `height` either).
@@ -312,9 +314,12 @@ Most mockups appear *inside* an explanation push — prose intro, embedded UI mo
312
314
 
313
315
  `.full-bleed` is injected into every presentation push. Prose is left-aligned and capped at ~880px; `.full-bleed` fills the **content column's full width from the same left edge** — wider than the prose, sharing one left margin down the card. It does *not* bleed to the card's physical edge: the body padding stays as a gutter, so neither the mockup nor the text ever touches the card border.
314
316
 
315
- Two cases, two tools:
316
- - **Whole push is a mockup / app recreation** → `kind: "mockup"` (or `"app"`) on the push. Strips the *presentation* frame (preset tokens, semantic chips, prose-width caps, body bg/color, the Inter webfont) so the content owns the canvas — but **keeps the structural primitives** (`.window`/`.window.dark`, `.code`/`.terminal`) and a neutral system-sans default font, so `.window` and friends still render in a mockup. To match the real app's typeface, **inject its webfont right in the pushed HTML** — a `<link rel="stylesheet" href="…">` or an `@font-face` block loads fine in the sandbox — then set `font-family` on the content; that wins over the sans default.
317
- - **Mockup embedded in an explanation** → leave the push as-is and wrap the mockup section in `<div class="full-bleed">`.
317
+ Two cases, two tools. **The deciding question is NOT "does this push contain a mockup?" — it's "is the WHOLE push one full-bleed app screen, or is it prose + embedded specimen(s)?"** A review card / spec sheet / lookbook page with an eyebrow + heading + paragraphs and one-or-more labelled mockup images is the **second** kind, even though it "contains mockups" — it's a presentation, not an app recreation. Default to leaving `kind` off; reach for `kind:"mockup"` only when the push is *nothing but* the UI.
318
+
319
+ - **Whole push is a single mockup / app recreation** (a dashboard, a screen — nothing but the UI, edge to edge) `kind: "mockup"` (or `"app"`) on the push. Strips the *presentation* frame (preset tokens, semantic chips, prose-width caps, body bg/color, the Inter webfont) so the content owns the canvas — but **keeps the structural primitives** (`.window`/`.window.dark`, `.code`/`.terminal`) and a neutral system-sans default font, so `.window` and friends still render in a mockup. To match the real app's typeface, **inject its webfont right in the pushed HTML** — a `<link rel="stylesheet" href="…">` or an `@font-face` block loads fine in the sandbox — then set `font-family` on the content; that wins over the sans default. Because app-fidelity strips the body padding too, a full-bleed app screen must **supply its own page padding** (e.g. a `.page { padding: 48px 40px }` wrapper) or it runs to the card edge.
320
+ - **Prose + embedded mockup(s)** (the common case — intro text, then specimen(s), maybe more text) → leave `kind` **off** so the presentation frame stays on, and wrap each specimen in `<div class="full-bleed">`. You get the best of both: prose lands in the ~56ch reading measure with comfortable side padding, while the specimens fill the full content column (up to 1400px) — **wider** than the prose, never narrower. Tagging this `kind:"mockup"` is the bug: app-fidelity strips the prose-width cap **and** the side padding, so your paragraphs run to the card edge unless you hand-pad — which you will forget.
321
+
322
+ > **Failure mode (seen in the wild, more than once):** a marketing-kit / lookbook review card — eyebrow, H1, two prose lines, then labelled atom specimens — tagged `kind:"mockup"`. App-fidelity stripped the padding; the author's wrapper had only `padding: 8px 4px`; the prose kissed the card edges. **Fix: drop the `kind`, wrap specimens in `.full-bleed`.** And remember: prose only gets the ~56ch cap when it's a **direct `body` child or inside `div.wrap`** — nest it in a bare `<div>` and the cap silently misses.
318
323
 
319
324
  ### Window chrome for UI mockups
320
325