@ammduncan/easel 0.2.29 → 0.3.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 +18 -0
- package/dist/client/viewer.js +137 -113
- package/dist/mcp.js +1 -1
- package/package.json +1 -1
- package/skills/using-easel/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to easel. This project adheres to [Semantic Versioning](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## 0.3.1 — 2026-05-26
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **Prose measure tightened from ~90 to ~66 characters per line.** The reading-column cap was `max-width: 880px`, which at the 18px body font produces ~90-character lines — past WCAG 1.4.8's 80-char ceiling and well past Bringhurst's 45–75 comfortable range. Changed to `max-width: 56ch`. The `ch` unit is the width of the "0" glyph and proportional Inter averages narrower, so 56ch renders ~66 actual characters — the reading-measure sweet spot. (`ch` scales with font-size, so headings stay proportional; short headings never hit the cap, so it's load-bearing only on body paragraphs, which is correct.)
|
|
9
|
+
- **`.full-bleed` now has vertical breathing room.** It only set horizontal margins, so a paragraph after an embedded mockup hugged the frame with no gap. Added `margin: 32px 0`; it collapses correctly against adjacent prose margins (32px, not 64) and the existing first/last-child margin resets still zero it at the card's top/bottom edge.
|
|
10
|
+
|
|
11
|
+
## 0.3.0 — 2026-05-26
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **App-fidelity mode (`kind:"mockup"`/`"app"`) no longer strips the structural primitives — `.window`/`.code`/`.terminal` now render in mockups.** The wrapper has two branches: a normal presentation branch and an app-fidelity branch for UI recreations (which skips presets/tokens/chips/prose-caps/body-bg so the agent controls every pixel). But app-fidelity skipped the *entire* built-in stylesheet — including the self-contained `.window` window chrome and `.code`/`.terminal` code blocks — while the skill and the `push` tool description told agents to use `.window` *for mockups*. So a `kind:"mockup"` push with `<div class="window">` rendered as unstyled serif text with no chrome (the same "I shipped a fix but it doesn't apply here" surprise as the 0.2.29 `.window` washout). Extracted the primitives — which use fixed, theme-independent colours and can't leak the host theme — into a shared `STRUCTURAL_PRIMITIVES_CSS` constant injected into BOTH wrapper branches (single source, no duplication; the normal branch's inline copies and their `@media print` overrides were removed). A mockup can now reach for `.window`/`.code`/`.terminal` and they render, in either kind.
|
|
15
|
+
- **App-fidelity mode now sets a system-sans default font instead of falling back to serif.** It deliberately omits the Inter webfont (so the agent controls typography with no CDN dependency), but it also left no `font-family` at all, so any mockup that didn't set its own font rendered in Times serif. Added a `system-ui, -apple-system, "Segoe UI", sans-serif` floor; the pushed HTML's own `font-family` still wins the cascade.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **Visual-regression test suite (`tests/visual/`).** A fixture battery covering every built-in primitive plus realistic composites, each carrying an injected contrast-audit that walks text nodes, composites translucent backgrounds over the host backdrop, computes WCAG contrast, and reports washout failures. A driver pushes them to a running server; the suite is rendered across the full preset × theme × density matrix (+ print) to catch surface-vs-ink regressions. The two fixes above were both found by this suite. See `tests/visual/README.md`.
|
|
19
|
+
|
|
20
|
+
### Docs
|
|
21
|
+
- **`push` tool `kind` description and the using-easel skill now state what app-fidelity keeps vs strips** — structural primitives + sans default kept; presentation defaults (preset tokens, chips, prose caps, body bg/color, Inter) stripped — so the "use `.window` for mockups" guidance and the engine no longer contradict each other.
|
|
22
|
+
|
|
5
23
|
## 0.2.29 — 2026-05-25
|
|
6
24
|
|
|
7
25
|
### Fixed
|
package/dist/client/viewer.js
CHANGED
|
@@ -110,6 +110,127 @@
|
|
|
110
110
|
:root[data-theme="light"] .chip.info { background:#ecfeff; color:#0e7490; border-color:#a5f3fc; box-shadow:0 0 12px -6px rgba(14,116,144,.45); }
|
|
111
111
|
:root[data-theme="dark"] .chip.info { background:#0a1c22; color:#67e8f9; border-color:#155060; box-shadow:0 0 12px -4px rgba(103,232,249,.4); }
|
|
112
112
|
.chip.accent { background:var(--ds-accent-soft); color:var(--ds-accent); border-color:transparent; box-shadow:0 0 12px -4px color-mix(in srgb, var(--ds-accent) 40%, transparent); }
|
|
113
|
+
`;
|
|
114
|
+
|
|
115
|
+
/* Self-contained structural primitives — window chrome + locked code/terminal.
|
|
116
|
+
These pin their own background and ink with fixed (theme-independent) colours,
|
|
117
|
+
so unlike the preset-token presentation styles they CAN'T leak the host theme.
|
|
118
|
+
Injected in BOTH the normal wrapper AND app-fidelity (mockup/app) mode: a UI
|
|
119
|
+
recreation is exactly where an agent reaches for a window frame or a code
|
|
120
|
+
block, so stripping these in fidelity mode left the skill's own guidance
|
|
121
|
+
("wrap a mockup in .window") producing unstyled output. */
|
|
122
|
+
const STRUCTURAL_PRIMITIVES_CSS = `
|
|
123
|
+
/* Skeuomorphic macOS-style window chrome for UI mockups. Usage:
|
|
124
|
+
<div class="window" data-title="App name"> …mockup content… </div>
|
|
125
|
+
Draws a 40px title bar with the three traffic-light dots (red/yellow/green)
|
|
126
|
+
and an optional centred title from data-title. Content sits below the bar.
|
|
127
|
+
Add the desktop class for a full desktop-screen canvas — min-height 900px,
|
|
128
|
+
i.e. the 1440x900 (16:10) standard design canvas — so a screen mockup looks
|
|
129
|
+
like a real window with viewport breathing room rather than a short strip.
|
|
130
|
+
Omit desktop for dialogs / small components so they stay content-sized.
|
|
131
|
+
|
|
132
|
+
A mockup renders an app's own UI, so it owns a STABLE surface that does NOT
|
|
133
|
+
flip with the host theme — otherwise a light dashboard mockup renders on a dark
|
|
134
|
+
window in a dark-mode viewer and every subtle gray label washes out (same
|
|
135
|
+
surface-vs-ink mismatch the .code primitive locks against). Default is a light
|
|
136
|
+
canvas with pinned dark ink and color:inherit re-scoped to every child so the
|
|
137
|
+
host's light-dark() ink can never leak in. Add the dark class
|
|
138
|
+
(class="window dark") for a genuinely dark-UI mockup. */
|
|
139
|
+
.window {
|
|
140
|
+
position: relative;
|
|
141
|
+
padding-top: 40px;
|
|
142
|
+
border-radius: 12px;
|
|
143
|
+
border: 1px solid #e2e2e2;
|
|
144
|
+
box-shadow: 0 14px 48px rgba(0, 0, 0, 0.16);
|
|
145
|
+
overflow: hidden;
|
|
146
|
+
background: #ffffff;
|
|
147
|
+
color: #1a1a1a;
|
|
148
|
+
}
|
|
149
|
+
.window * { color: inherit; }
|
|
150
|
+
.window::before {
|
|
151
|
+
content: "";
|
|
152
|
+
position: absolute;
|
|
153
|
+
top: 0;
|
|
154
|
+
left: 0;
|
|
155
|
+
right: 0;
|
|
156
|
+
height: 40px;
|
|
157
|
+
background-color: #f1f1f1;
|
|
158
|
+
border-bottom: 1px solid #e2e2e2;
|
|
159
|
+
background-image:
|
|
160
|
+
radial-gradient(circle at 19px 20px, #ff5f57 6px, transparent 6.5px),
|
|
161
|
+
radial-gradient(circle at 39px 20px, #febc2e 6px, transparent 6.5px),
|
|
162
|
+
radial-gradient(circle at 59px 20px, #28c840 6px, transparent 6.5px);
|
|
163
|
+
background-repeat: no-repeat;
|
|
164
|
+
}
|
|
165
|
+
.window::after {
|
|
166
|
+
content: attr(data-title);
|
|
167
|
+
position: absolute;
|
|
168
|
+
top: 0;
|
|
169
|
+
left: 0;
|
|
170
|
+
right: 0;
|
|
171
|
+
height: 40px;
|
|
172
|
+
display: flex;
|
|
173
|
+
align-items: center;
|
|
174
|
+
justify-content: center;
|
|
175
|
+
font-size: 13px;
|
|
176
|
+
font-weight: 500;
|
|
177
|
+
color: #6b6b6b;
|
|
178
|
+
pointer-events: none;
|
|
179
|
+
}
|
|
180
|
+
.window.dark {
|
|
181
|
+
border-color: #2a2a2a;
|
|
182
|
+
background: #161616;
|
|
183
|
+
color: #e6edf3;
|
|
184
|
+
box-shadow: 0 14px 48px rgba(0, 0, 0, 0.4);
|
|
185
|
+
}
|
|
186
|
+
.window.dark::before {
|
|
187
|
+
background-color: #1f1f1f;
|
|
188
|
+
border-bottom-color: #2a2a2a;
|
|
189
|
+
}
|
|
190
|
+
.window.dark::after { color: #9b9b9b; }
|
|
191
|
+
.window.desktop {
|
|
192
|
+
min-height: 900px;
|
|
193
|
+
}
|
|
194
|
+
/* Locked-dark code / terminal primitive. Reach for this instead of hand-rolling
|
|
195
|
+
a dark code container — the recurring failure is a custom dark <div> that sets
|
|
196
|
+
its own background but lets base text inherit .wrap's light-dark() ink, which
|
|
197
|
+
resolves to near-black in light host mode and vanishes against the dark panel.
|
|
198
|
+
This class locks BOTH background and ink, and re-scopes color:inherit to every
|
|
199
|
+
child so the host theme can never leak in. Ships the verified github-dark token
|
|
200
|
+
palette so syntax highlighting reads against #0f172a without per-token tuning.
|
|
201
|
+
Usage: <div class="code"><span class="kw">gcloud</span> services enable …</div>
|
|
202
|
+
.terminal is an alias; add .terminal for a prompt feel (same colors). */
|
|
203
|
+
.code, .terminal {
|
|
204
|
+
background: #0f172a;
|
|
205
|
+
color: #e6edf3;
|
|
206
|
+
border-radius: 12px;
|
|
207
|
+
padding: 18px 22px;
|
|
208
|
+
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
209
|
+
font-size: 13.5px;
|
|
210
|
+
line-height: 1.7;
|
|
211
|
+
overflow: auto;
|
|
212
|
+
margin: 16px 0 24px;
|
|
213
|
+
}
|
|
214
|
+
.code *, .terminal * { color: inherit; }
|
|
215
|
+
.code .kw, .terminal .kw { color: #ff7b72; } /* keywords, control flow */
|
|
216
|
+
.code .string, .terminal .string { color: #a5d6ff; } /* strings, attr values */
|
|
217
|
+
.code .fn, .terminal .fn { color: #d2a8ff; } /* function names */
|
|
218
|
+
.code .prop, .terminal .prop { color: #79c0ff; } /* identifiers, properties */
|
|
219
|
+
.code .num, .terminal .num { color: #ffa657; } /* numbers, constants */
|
|
220
|
+
.code .comment, .terminal .comment { color: #8b949e; } /* comments */
|
|
221
|
+
.code .muted, .terminal .muted { color: #94a3b8; } /* dim / secondary */
|
|
222
|
+
.code .accent, .terminal .accent { color: #6ee7b7; } /* highlight / success */
|
|
223
|
+
@media print {
|
|
224
|
+
/* Force the locked-dark primitives light for print — browsers drop background
|
|
225
|
+
colours by default, which would otherwise strand their light ink on white
|
|
226
|
+
paper. Applies in both normal and app-fidelity mode. The !important here
|
|
227
|
+
also (intentionally) overrides the normal branch's non-print-gated pre/code
|
|
228
|
+
theming, so code reads as dark-on-light on paper regardless of host theme. */
|
|
229
|
+
pre, code, .code, .terminal { background: #f4f3ed !important; color: #111 !important; border: 1px solid #ddd; }
|
|
230
|
+
.code *, .terminal * { color: #111 !important; }
|
|
231
|
+
.window.dark { background: #ffffff !important; color: #111 !important; }
|
|
232
|
+
.window.dark * { color: #111 !important; }
|
|
233
|
+
}
|
|
113
234
|
`;
|
|
114
235
|
|
|
115
236
|
const unreadIds = new Set();
|
|
@@ -653,7 +774,11 @@
|
|
|
653
774
|
<script src="https://cdn.jsdelivr.net/npm/html-to-image@1.11.13/dist/html-to-image.js"></script>
|
|
654
775
|
<style>
|
|
655
776
|
*, *::before, *::after { box-sizing: border-box; }
|
|
656
|
-
|
|
777
|
+
/* Sane sans-serif floor so an unstyled mockup doesn't fall back to Times serif.
|
|
778
|
+
No CDN font here (that's the agent's call in fidelity mode) — the pushed HTML
|
|
779
|
+
can override font-family inline / in its own <style>, which wins the cascade. */
|
|
780
|
+
html, body { margin: 0; padding: 0; font-family: system-ui, -apple-system, "Segoe UI", sans-serif; }
|
|
781
|
+
${STRUCTURAL_PRIMITIVES_CSS}
|
|
657
782
|
</style>
|
|
658
783
|
</head>
|
|
659
784
|
<body>
|
|
@@ -671,9 +796,10 @@ ${body}
|
|
|
671
796
|
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
|
|
672
797
|
<script src="https://cdn.jsdelivr.net/npm/html-to-image@1.11.13/dist/html-to-image.js"></script>
|
|
673
798
|
<style>
|
|
799
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
674
800
|
${PRESET_TOKENS_CSS}
|
|
675
801
|
${SEMANTIC_CHIPS_CSS}
|
|
676
|
-
|
|
802
|
+
${STRUCTURAL_PRIMITIVES_CSS}
|
|
677
803
|
html, body {
|
|
678
804
|
margin: 0;
|
|
679
805
|
background: var(--ds-bg-elev);
|
|
@@ -703,7 +829,10 @@ body > h1, body > h2, body > h3, body > h4,
|
|
|
703
829
|
body > .wrap > p, body > .wrap > .deck, body > .wrap > .lede,
|
|
704
830
|
body > .wrap > ul, body > .wrap > ol, body > .wrap > blockquote,
|
|
705
831
|
body > .wrap > h1, body > .wrap > h2, body > .wrap > h3, body > .wrap > h4 {
|
|
706
|
-
|
|
832
|
+
/* ~56ch of "0"-width lands ~66 actual characters in proportional Inter
|
|
833
|
+
(avg glyph is narrower than "0"), i.e. Bringhurst's reading-measure sweet
|
|
834
|
+
spot — not 56 literal characters. */
|
|
835
|
+
max-width: 56ch;
|
|
707
836
|
}
|
|
708
837
|
body > *:first-child { margin-top: 0 !important; }
|
|
709
838
|
body > *:last-child { margin-bottom: 0 !important; }
|
|
@@ -714,83 +843,13 @@ body > *:last-child { margin-bottom: 0 !important; }
|
|
|
714
843
|
stays as a gutter, so neither the mockup nor the surrounding text ever touches
|
|
715
844
|
the card border. (The name is historical — it's "full content width", not
|
|
716
845
|
"bleed to the card edge".) Capped at 100% of the content column, which the
|
|
717
|
-
body's max-width already limits to desktop-realistic proportions.
|
|
846
|
+
body's max-width already limits to desktop-realistic proportions.
|
|
847
|
+
Vertical margin gives an embedded mockup breathing room from the prose above
|
|
848
|
+
and below it (without it, the next paragraph hugs the frame). */
|
|
718
849
|
.full-bleed {
|
|
719
850
|
width: 100%;
|
|
720
851
|
max-width: 100% !important;
|
|
721
|
-
margin
|
|
722
|
-
margin-right: 0;
|
|
723
|
-
}
|
|
724
|
-
/* Skeuomorphic macOS-style window chrome for UI mockups. Usage:
|
|
725
|
-
<div class="window" data-title="App name"> …mockup content… </div>
|
|
726
|
-
Draws a 40px title bar with the three traffic-light dots (red/yellow/green)
|
|
727
|
-
and an optional centred title from data-title. Content sits below the bar.
|
|
728
|
-
Add the desktop class for a full desktop-screen canvas — min-height 900px,
|
|
729
|
-
i.e. the 1440x900 (16:10) standard design canvas — so a screen mockup looks
|
|
730
|
-
like a real window with viewport breathing room rather than a short strip.
|
|
731
|
-
Omit desktop for dialogs / small components so they stay content-sized.
|
|
732
|
-
|
|
733
|
-
A mockup renders an app's own UI, so it owns a STABLE surface that does NOT
|
|
734
|
-
flip with the host theme — otherwise a light dashboard mockup renders on a dark
|
|
735
|
-
window in a dark-mode viewer and every subtle gray label washes out (same
|
|
736
|
-
surface-vs-ink mismatch the .code primitive locks against). Default is a light
|
|
737
|
-
canvas with pinned dark ink and color:inherit re-scoped to every child so the
|
|
738
|
-
host's light-dark() ink can never leak in. Add the dark class
|
|
739
|
-
(class="window dark") for a genuinely dark-UI mockup. */
|
|
740
|
-
.window {
|
|
741
|
-
position: relative;
|
|
742
|
-
padding-top: 40px;
|
|
743
|
-
border-radius: 12px;
|
|
744
|
-
border: 1px solid #e2e2e2;
|
|
745
|
-
box-shadow: 0 14px 48px rgba(0, 0, 0, 0.16);
|
|
746
|
-
overflow: hidden;
|
|
747
|
-
background: #ffffff;
|
|
748
|
-
color: #1a1a1a;
|
|
749
|
-
}
|
|
750
|
-
.window * { color: inherit; }
|
|
751
|
-
.window::before {
|
|
752
|
-
content: "";
|
|
753
|
-
position: absolute;
|
|
754
|
-
top: 0;
|
|
755
|
-
left: 0;
|
|
756
|
-
right: 0;
|
|
757
|
-
height: 40px;
|
|
758
|
-
background-color: #f1f1f1;
|
|
759
|
-
border-bottom: 1px solid #e2e2e2;
|
|
760
|
-
background-image:
|
|
761
|
-
radial-gradient(circle at 19px 20px, #ff5f57 6px, transparent 6.5px),
|
|
762
|
-
radial-gradient(circle at 39px 20px, #febc2e 6px, transparent 6.5px),
|
|
763
|
-
radial-gradient(circle at 59px 20px, #28c840 6px, transparent 6.5px);
|
|
764
|
-
background-repeat: no-repeat;
|
|
765
|
-
}
|
|
766
|
-
.window::after {
|
|
767
|
-
content: attr(data-title);
|
|
768
|
-
position: absolute;
|
|
769
|
-
top: 0;
|
|
770
|
-
left: 0;
|
|
771
|
-
right: 0;
|
|
772
|
-
height: 40px;
|
|
773
|
-
display: flex;
|
|
774
|
-
align-items: center;
|
|
775
|
-
justify-content: center;
|
|
776
|
-
font-size: 13px;
|
|
777
|
-
font-weight: 500;
|
|
778
|
-
color: #6b6b6b;
|
|
779
|
-
pointer-events: none;
|
|
780
|
-
}
|
|
781
|
-
.window.dark {
|
|
782
|
-
border-color: #2a2a2a;
|
|
783
|
-
background: #161616;
|
|
784
|
-
color: #e6edf3;
|
|
785
|
-
box-shadow: 0 14px 48px rgba(0, 0, 0, 0.4);
|
|
786
|
-
}
|
|
787
|
-
.window.dark::before {
|
|
788
|
-
background-color: #1f1f1f;
|
|
789
|
-
border-bottom-color: #2a2a2a;
|
|
790
|
-
}
|
|
791
|
-
.window.dark::after { color: #9b9b9b; }
|
|
792
|
-
.window.desktop {
|
|
793
|
-
min-height: 900px;
|
|
852
|
+
margin: 32px 0;
|
|
794
853
|
}
|
|
795
854
|
.wrap { display: block; }
|
|
796
855
|
.kicker {
|
|
@@ -858,35 +917,6 @@ pre {
|
|
|
858
917
|
margin: 16px 0 24px;
|
|
859
918
|
}
|
|
860
919
|
pre code { background: transparent; padding: 0; color: inherit; font-size: inherit; }
|
|
861
|
-
/* Locked-dark code / terminal primitive. Reach for this instead of hand-rolling
|
|
862
|
-
a dark code container — the recurring failure is a custom dark <div> that sets
|
|
863
|
-
its own background but lets base text inherit .wrap's light-dark() ink, which
|
|
864
|
-
resolves to near-black in light host mode and vanishes against the dark panel.
|
|
865
|
-
This class locks BOTH background and ink, and re-scopes color:inherit to every
|
|
866
|
-
child so the host theme can never leak in. Ships the verified github-dark token
|
|
867
|
-
palette so syntax highlighting reads against #0f172a without per-token tuning.
|
|
868
|
-
Usage: <div class="code"><span class="kw">gcloud</span> services enable …</div>
|
|
869
|
-
.terminal is an alias; add .terminal for a prompt feel (same colors). */
|
|
870
|
-
.code, .terminal {
|
|
871
|
-
background: #0f172a;
|
|
872
|
-
color: #e6edf3;
|
|
873
|
-
border-radius: 12px;
|
|
874
|
-
padding: 18px 22px;
|
|
875
|
-
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
876
|
-
font-size: 13.5px;
|
|
877
|
-
line-height: 1.7;
|
|
878
|
-
overflow: auto;
|
|
879
|
-
margin: 16px 0 24px;
|
|
880
|
-
}
|
|
881
|
-
.code *, .terminal * { color: inherit; }
|
|
882
|
-
.code .kw, .terminal .kw { color: #ff7b72; } /* keywords, control flow */
|
|
883
|
-
.code .string, .terminal .string { color: #a5d6ff; } /* strings, attr values */
|
|
884
|
-
.code .fn, .terminal .fn { color: #d2a8ff; } /* function names */
|
|
885
|
-
.code .prop, .terminal .prop { color: #79c0ff; } /* identifiers, properties */
|
|
886
|
-
.code .num, .terminal .num { color: #ffa657; } /* numbers, constants */
|
|
887
|
-
.code .comment, .terminal .comment { color: #8b949e; } /* comments */
|
|
888
|
-
.code .muted, .terminal .muted { color: #94a3b8; } /* dim / secondary */
|
|
889
|
-
.code .accent, .terminal .accent { color: #6ee7b7; } /* highlight / success */
|
|
890
920
|
blockquote {
|
|
891
921
|
border-left: 3px solid var(--ds-accent);
|
|
892
922
|
margin: 18px 0;
|
|
@@ -933,13 +963,7 @@ img { max-width: 100%; height: auto; border-radius: 10px; }
|
|
|
933
963
|
body { padding: 24px !important; max-width: none !important; }
|
|
934
964
|
body > p, body > .deck, body > .lede, body > ul, body > ol, body > blockquote,
|
|
935
965
|
body > h1, body > h2, body > h3, body > h4 { max-width: none !important; }
|
|
936
|
-
|
|
937
|
-
.code *, .terminal * { color: #111 !important; }
|
|
938
|
-
/* Force the dark window variant light for print — browsers drop background
|
|
939
|
-
colors by default, which would leave its light ink invisible on white paper
|
|
940
|
-
(same reason .code/.terminal are forced light above). */
|
|
941
|
-
.window.dark { background: #ffffff !important; color: #111 !important; }
|
|
942
|
-
.window.dark * { color: #111 !important; }
|
|
966
|
+
/* .code/.terminal/.window.dark print overrides live in STRUCTURAL_PRIMITIVES_CSS. */
|
|
943
967
|
.card, .panel { background: #fff !important; border: 1px solid #ddd !important; box-shadow: none !important; }
|
|
944
968
|
a { color: #111 !important; text-decoration: underline; border-bottom: 0 !important; }
|
|
945
969
|
}
|
package/dist/mcp.js
CHANGED
|
@@ -72,7 +72,7 @@ const inputSchema = {
|
|
|
72
72
|
},
|
|
73
73
|
kind: {
|
|
74
74
|
type: "string",
|
|
75
|
-
description: "Freeform tag: mockup, app, diff, explanation, comparison, diagram, status, progress, etc. SPECIAL: 'mockup' and 'app' switch the iframe into APP-FIDELITY mode — the wrapper skips its
|
|
75
|
+
description: "Freeform tag: mockup, app, diff, explanation, comparison, diagram, status, progress, etc. SPECIAL: 'mockup' and 'app' switch the iframe into APP-FIDELITY mode — the wrapper skips its PRESENTATION defaults (preset design-token CSS, semantic chips, prose width constraints, body bg/color, the Inter webfont) so the host theme can't leak in and you control every pixel. It KEEPS the self-contained structural primitives (.window/.window.dark window chrome, .code/.terminal code blocks — all fixed-colour, theme-independent) and a neutral system-sans default font, so you can still reach for <div class=\"window\"> in a mockup and it renders. Set your own font-family/colours in the pushed HTML to override the sans default. Use this kind when the push is a recreation of real UI (app screen, component instance, embedded preview). For presentation content (explanations, comparisons, status reports), omit kind or use a non-fidelity value.",
|
|
76
76
|
},
|
|
77
77
|
},
|
|
78
78
|
required: ["html"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ammduncan/easel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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",
|
|
@@ -299,7 +299,7 @@ Most mockups appear *inside* an explanation push — prose intro, embedded UI mo
|
|
|
299
299
|
`.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.
|
|
300
300
|
|
|
301
301
|
Two cases, two tools:
|
|
302
|
-
- **Whole push is a mockup / app recreation** → `kind: "mockup"` (or `"app"`) on the push. Strips the
|
|
302
|
+
- **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.
|
|
303
303
|
- **Mockup embedded in an explanation** → leave the push as-is and wrap the mockup section in `<div class="full-bleed">`.
|
|
304
304
|
|
|
305
305
|
### Window chrome for UI mockups
|