@compilr-dev/sdk 0.18.10 → 0.19.0
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/canvas/assets.d.ts +99 -0
- package/dist/canvas/assets.js +111 -0
- package/dist/canvas/color.d.ts +85 -0
- package/dist/canvas/color.js +216 -0
- package/dist/canvas/index.d.ts +8 -0
- package/dist/canvas/index.js +16 -0
- package/dist/canvas/quality-checks.d.ts +75 -0
- package/dist/canvas/quality-checks.js +217 -0
- package/dist/canvas/ramp.d.ts +45 -0
- package/dist/canvas/ramp.js +98 -0
- package/dist/capabilities/packs.js +16 -2
- package/dist/platform/context.d.ts +16 -2
- package/dist/platform/context.js +13 -1
- package/dist/platform/repositories.d.ts +4 -0
- package/dist/platform/sqlite/canvas-repository.d.ts +9 -0
- package/dist/platform/sqlite/canvas-repository.js +52 -0
- package/dist/platform/sqlite/db.js +29 -0
- package/dist/platform/sqlite/schema.d.ts +1 -1
- package/dist/platform/sqlite/schema.js +1 -1
- package/dist/platform/tools/canvas-tools.d.ts +12 -2
- package/dist/platform/tools/canvas-tools.js +316 -6
- package/dist/platform/tools/image-tools.d.ts +9 -2
- package/dist/platform/tools/image-tools.js +4 -2
- package/dist/platform/tools/index.js +10 -2
- package/dist/platform/tools/project-tools.js +3 -2
- package/dist/skills/canvas-exemplars.d.ts +8 -0
- package/dist/skills/canvas-exemplars.js +36 -0
- package/dist/skills/canvas-icons.d.ts +6 -0
- package/dist/skills/canvas-icons.js +84 -0
- package/dist/skills/canvas-skills.js +207 -20
- package/dist/skills/platform-skills.d.ts +2 -0
- package/dist/skills/platform-skills.js +8 -0
- package/dist/team/tool-config.js +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worked exemplars — the samples an agent reads before authoring.
|
|
3
|
+
*
|
|
4
|
+
* ⚠️ GENERATED by scripts/build-canvas-exemplars.mjs from the design handoff. Do not
|
|
5
|
+
* edit by hand; re-run the script.
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ WHY EXEMPLARS AND NOT MORE ADJECTIVES. The previous guidance described quality in
|
|
8
|
+
* words — "clean, minimal, generous whitespace" — so every session re-derived taste from
|
|
9
|
+
* scratch. Shown a real screenshot the model produces good work immediately, so what was
|
|
10
|
+
* missing was never capability; it was a reference.
|
|
11
|
+
*
|
|
12
|
+
* ⚠️ TWO SKILLS, NOT ONE. Together they are ~7.7K tokens and an agent authoring an
|
|
13
|
+
* infographic has no use for the app-screen markup, so canvas_guide serves them
|
|
14
|
+
* separately and each costs only what it is worth.
|
|
15
|
+
*/
|
|
16
|
+
import { defineSkill } from '@compilr-dev/agents';
|
|
17
|
+
/** The light theme-flat exemplar, ready to adapt. */
|
|
18
|
+
export const THEME_FLAT_EXEMPLAR = '<div style="--canvas-bg: #E9EAEE; --canvas-fg: #1B1C1F; --canvas-muted: #63656D; --canvas-accent: #C2410C; --canvas-card: #FFFFFF; --canvas-border: #D5D7DE; --canvas-surface-1: #FFFFFF; --canvas-surface-2: #F2F3F6; --canvas-hairline: #D5D7DE; width: 1000px; background: var(--canvas-bg); font-family: system-ui, -apple-system, \'Segoe UI\', Roboto, sans-serif; color: var(--canvas-fg); padding: 40px;">\n\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 24px; margin-bottom: 24px;">\n <div style="font-size: 11px; letter-spacing: 0.14em; font-weight: 600; color: var(--canvas-muted);">Q3 DELIVERY REVIEW · PLATFORM</div>\n <div style="font-size: 11px; letter-spacing: 0.08em; color: var(--canvas-muted);">as of 6 Sep 2026</div>\n </div>\n\n <div style="display: grid; grid-template-columns: 1.35fr 1fr; gap: 16px; margin-bottom: 16px;">\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 30px 32px;">\n <div style="font-size: 11px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-accent); margin-bottom: 16px;">THE QUARTER IN ONE NUMBER</div>\n <div style="font-size: 84px; line-height: 0.94; font-weight: 700; letter-spacing: -0.035em; font-variant-numeric: tabular-nums; margin-bottom: 12px;">41<span style="font-size: 40px; font-weight: 600; color: var(--canvas-muted);"> of 47</span></div>\n <div style="font-size: 20px; line-height: 1.35; font-weight: 600; letter-spacing: -0.01em; margin-bottom: 14px; max-width: 22em;">commitments shipped, and the six that slipped share one cause.</div>\n <p style="font-size: 14px; line-height: 1.65; color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg)); margin: 0;">Every delayed item was blocked on the migration, not on capacity. Team throughput rose 12% over Q2 while the queue behind a single dependency grew, which is why headcount is the wrong lever here.</p>\n </div>\n\n <div style="display: grid; grid-template-rows: repeat(3, 1fr); gap: 16px;">\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 18px 20px; display: flex; align-items: baseline; justify-content: space-between; gap: 16px;">\n <div>\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-bottom: 6px;">CYCLE TIME</div>\n <div style="font-size: 34px; line-height: 1; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums;">6.2<span style="font-size: 15px; font-weight: 500; color: var(--canvas-muted);"> days</span></div>\n </div>\n <div style="font-size: 13px; font-weight: 600; color: var(--canvas-accent); flex: none;">▼ 1.8</div>\n </div>\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 18px 20px; display: flex; align-items: baseline; justify-content: space-between; gap: 16px;">\n <div>\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-bottom: 6px;">ESCAPED DEFECTS</div>\n <div style="font-size: 34px; line-height: 1; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums;">3</div>\n </div>\n <div style="font-size: 13px; font-weight: 600; color: var(--canvas-muted); flex: none;">▼ 5</div>\n </div>\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 18px 20px; display: flex; align-items: baseline; justify-content: space-between; gap: 16px;">\n <div>\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-bottom: 6px;">BLOCKED, NOW</div>\n <div style="font-size: 34px; line-height: 1; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums;">6</div>\n </div>\n <div style="font-size: 13px; font-weight: 600; color: var(--canvas-muted); flex: none;">▲ 4</div>\n </div>\n </div>\n </div>\n\n <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">\n\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 22px 24px 20px;">\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-bottom: 18px;">SHIPPED PER SPRINT</div>\n <svg width="100%" height="150" viewBox="0 0 420 150" style="display: block; overflow: visible;">\n <line x1="0" y1="126" x2="420" y2="126" style="stroke: var(--canvas-hairline, var(--canvas-border));" stroke-width="1"></line>\n <rect x="10" y="72" width="46" height="54" style="fill: color-mix(in oklab, var(--canvas-fg) 22%, var(--canvas-bg));"></rect>\n <text x="33" y="62" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-fg); font-family: system-ui, sans-serif;">6</text>\n <text x="33" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S1</text>\n <rect x="76" y="45" width="46" height="81" style="fill: color-mix(in oklab, var(--canvas-fg) 22%, var(--canvas-bg));"></rect>\n <text x="99" y="35" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-fg); font-family: system-ui, sans-serif;">9</text>\n <text x="99" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S2</text>\n <rect x="142" y="54" width="46" height="72" style="fill: color-mix(in oklab, var(--canvas-fg) 22%, var(--canvas-bg));"></rect>\n <text x="165" y="44" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-fg); font-family: system-ui, sans-serif;">8</text>\n <text x="165" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S3</text>\n <rect x="208" y="27" width="46" height="99" style="fill: color-mix(in oklab, var(--canvas-fg) 22%, var(--canvas-bg));"></rect>\n <text x="231" y="17" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-fg); font-family: system-ui, sans-serif;">11</text>\n <text x="231" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S4</text>\n <rect x="274" y="99" width="46" height="27" style="fill: var(--canvas-accent);"></rect>\n <text x="297" y="89" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-accent); font-family: system-ui, sans-serif;">3</text>\n <text x="297" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S5</text>\n <rect x="340" y="90" width="46" height="36" style="fill: color-mix(in oklab, var(--canvas-fg) 22%, var(--canvas-bg));"></rect>\n <text x="363" y="80" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-fg); font-family: system-ui, sans-serif;">4</text>\n <text x="363" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S6</text>\n </svg>\n <div style="font-size: 13px; line-height: 1.55; color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg)); margin-top: 20px; border-top: 1px solid var(--canvas-hairline, var(--canvas-border)); padding-top: 12px;">Sprint 5 is when the migration landed in the critical path.</div>\n </div>\n\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 22px 24px 20px;">\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-bottom: 14px;">THE SIX THAT SLIPPED</div>\n <div style="background: var(--canvas-surface-2, var(--canvas-bg)); border: 1px solid var(--canvas-hairline, var(--canvas-border));">\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 8px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 10px; letter-spacing: 0.1em; font-weight: 600; color: var(--canvas-muted);"><span>COMMITMENT</span><span>BLOCKED BY</span><span style="text-align: right;">DAYS</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">Billing export</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">21</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">Audit trail</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">18</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">SSO for teams</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">14</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">Usage alerts</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">11</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">Retention job</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">9</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">Region failover</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">6</span></div>\n </div>\n <div style="font-size: 13px; line-height: 1.55; color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg)); margin-top: 16px;">One dependency, 79 days of accumulated delay.</div>\n </div>\n </div>\n\n <div style="border-top: 1px solid var(--canvas-hairline, var(--canvas-border)); margin-top: 26px; padding-top: 14px; display: flex; align-items: baseline; justify-content: space-between; gap: 24px; font-size: 11px; letter-spacing: 0.06em; color: var(--canvas-muted);">\n <span>PLATFORM · QUARTERLY REVIEW</span>\n <span>Source: delivery board, sprints 1–6</span>\n </div>\n </div>';
|
|
19
|
+
/** The same markup in dark: only these nine values change. */
|
|
20
|
+
export const THEME_FLAT_DARK_TOKENS = '--canvas-bg: #17181C; --canvas-fg: #ECEDF1; --canvas-muted: #9A9CA6; --canvas-accent: #FB7B4B; --canvas-card: #22242A; --canvas-border: #31333B; --canvas-surface-1: #22242A; --canvas-surface-2: #1B1D22; --canvas-hairline: #31333B';
|
|
21
|
+
/** The app-screen exemplar — a single UI screen, four surfaces. */
|
|
22
|
+
export const APP_SCREEN_EXEMPLAR = '<div style="--canvas-bg: #E9EAEE; --canvas-fg: #1B1C1F; --canvas-muted: #63656D; --canvas-accent: #C2410C; --canvas-card: #FFFFFF; --canvas-border: #D5D7DE; --canvas-surface-1: #FFFFFF; --canvas-surface-2: #F2F3F6; --canvas-hairline: #DCDEE4; width: 1000px; background: var(--canvas-surface-1, var(--canvas-card)); font-family: system-ui, -apple-system, \'Segoe UI\', Roboto, sans-serif; color: var(--canvas-fg); display: grid; grid-template-columns: 232px 1fr;">\n\n <div style="border-right: 1px solid var(--canvas-hairline, var(--canvas-border)); display: flex; flex-direction: column; min-height: 640px;">\n <div style="padding: 18px 18px 16px; display: flex; align-items: center; gap: 10px;">\n <span style="width: 28px; height: 28px; background: var(--canvas-fg); color: var(--canvas-surface-1, var(--canvas-card)); font-size: 11px; font-weight: 700; letter-spacing: 0.02em; display: flex; align-items: center; justify-content: center; flex: none;">CO</span>\n <span style="font-size: 15px; font-weight: 700; letter-spacing: -0.01em;">Cohort</span>\n </div>\n\n <div style="padding: 6px 10px 0; display: flex; flex-direction: column; gap: 1px;">\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; background: color-mix(in oklab, var(--canvas-accent) 10%, var(--canvas-surface-1, var(--canvas-card))); box-shadow: inset 2px 0 0 var(--canvas-accent); font-size: 13.5px; font-weight: 600;">\n <span style="font-size: 13px; flex: none; color: var(--canvas-accent);">■</span>Overview\n </div>\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">\n <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="flex: none; color: var(--canvas-muted);"><circle cx="6" cy="6" r="2.5"></circle><path d="M2 13.5c.8-2.2 2.2-3.3 4-3.3s3.2 1.1 4 3.3"></path><path d="M11 4.2a2.5 2.5 0 0 1 0 4.6"></path></svg>Applicants\n <span style="margin-left: auto; font-size: 12px; color: var(--canvas-muted); font-variant-numeric: tabular-nums;">248</span>\n </div>\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">\n <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="flex: none; color: var(--canvas-muted);"><rect x="2.5" y="3.5" width="11" height="10" rx="1"></rect><path d="M2.5 6.5h11M5.5 2v2.5M10.5 2v2.5"></path></svg>Interviews\n <span style="margin-left: auto; font-size: 12px; color: var(--canvas-muted); font-variant-numeric: tabular-nums;">67</span>\n </div>\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">\n <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="flex: none; color: var(--canvas-muted);"><path d="M9.5 2H4.5A1.5 1.5 0 0 0 3 3.5v9A1.5 1.5 0 0 0 4.5 14h7a1.5 1.5 0 0 0 1.5-1.5V5.5z"></path><path d="M9.5 2v3.5H13"></path></svg>Documents\n </div>\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">\n <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="flex: none; color: var(--canvas-muted);"><path d="M2 14h12"></path><path d="M4.5 14V9M8 14V4.5M11.5 14V7"></path></svg>Reports\n </div>\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">\n <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="flex: none; color: var(--canvas-muted);"><path d="M2 5.5A1.5 1.5 0 0 1 3.5 4h2.2l1.3 1.6h5.5A1.5 1.5 0 0 1 14 7.1v5.4A1.5 1.5 0 0 1 12.5 14h-9A1.5 1.5 0 0 1 2 12.5z"></path></svg>Programmes\n <span style="margin-left: auto; font-size: 12px; color: var(--canvas-muted); font-variant-numeric: tabular-nums;">12</span>\n </div>\n </div>\n\n <div style="margin-top: auto; border-top: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 12px 22px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">Settings</div>\n <div style="border-top: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 14px 18px; display: flex; align-items: center; gap: 10px;">\n <span style="width: 30px; height: 30px; background: var(--canvas-surface-2, var(--canvas-bg)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 11px; font-weight: 600; color: var(--canvas-muted); display: flex; align-items: center; justify-content: center; flex: none;">RM</span>\n <span>\n <span style="display: block; font-size: 13px; font-weight: 600;">Rita Marchetti</span>\n <span style="display: block; font-size: 11px; color: var(--canvas-muted);">Admissions lead</span>\n </span>\n </div>\n </div>\n\n <div style="display: flex; flex-direction: column;">\n <div style="padding: 20px 28px 18px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); display: flex; align-items: flex-end; justify-content: space-between; gap: 24px;">\n <div>\n <div style="font-size: 11px; letter-spacing: 0.06em; color: var(--canvas-muted); margin-bottom: 6px;">Autumn 2027 / Admissions</div>\n <div style="font-size: 26px; font-weight: 700; letter-spacing: -0.022em;">Overview</div>\n </div>\n <div style="display: flex; align-items: center; gap: 8px; flex: none;">\n <span style="font-size: 13px; padding: 8px 14px; border: 1px solid var(--canvas-hairline, var(--canvas-border)); color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">Export</span>\n <span style="font-size: 13px; font-weight: 600; padding: 9px 15px; background: var(--canvas-fg); color: var(--canvas-surface-1, var(--canvas-card));">New applicant</span>\n </div>\n </div>\n <div style="background: var(--canvas-surface-2, var(--canvas-bg)); padding: 20px 28px 26px; flex: 1; display: flex; flex-direction: column; gap: 16px;">\n\n <div style="display: grid; grid-template-columns: 1.45fr 1fr; gap: 16px;">\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 22px 24px;">\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 14px;">\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-accent);">THIS WEEK</div>\n <div style="font-size: 11px; color: var(--canvas-muted);">updated 4 min ago</div>\n </div>\n <div style="font-size: 27px; line-height: 1.2; font-weight: 700; letter-spacing: -0.022em; margin-bottom: 10px; max-width: 20em;">Interviews are keeping pace. Document review is not.</div>\n <p style="font-size: 13.5px; line-height: 1.65; color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg)); margin: 0 0 16px;">248 applicants across 12 programmes, and 67 have reached interview. The queue sits at document review, where 41 files have waited more than five days — two programmes account for 30 of them.</p>\n <span style="display: inline-block; font-size: 12.5px; font-weight: 600; color: var(--canvas-accent); border-bottom: 1px solid var(--canvas-accent); padding-bottom: 1px;">Review the 41 waiting files</span>\n </div>\n\n <div style="background: var(--canvas-fg); color: var(--canvas-surface-1, var(--canvas-card)); padding: 20px 22px; display: flex; flex-direction: column; gap: 14px;">\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 12px;">\n <span style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600;">PIPELINE</span>\n <span style="font-size: 10px; letter-spacing: 0.06em; opacity: 0.62;">stage by stage</span>\n </div>\n <div style="display: flex; flex-direction: column; gap: 11px;">\n <div>\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 12px;"><span style="opacity: 0.75;">Applied</span><span style="font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;">248</span></div>\n <div style="height: 4px; background: rgba(255,255,255,0.16); margin-top: 5px;"><div style="height: 4px; width: 100%; background: rgba(255,255,255,0.62);"></div></div>\n </div>\n <div>\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 12px;"><span style="opacity: 0.75;">Documents in</span><span style="font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;">193</span></div>\n <div style="height: 4px; background: rgba(255,255,255,0.16); margin-top: 5px;"><div style="height: 4px; width: 78%; background: rgba(255,255,255,0.62);"></div></div>\n </div>\n <div>\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 12px;"><span style="opacity: 0.75;">Reviewed</span><span style="font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;">152</span></div>\n <div style="height: 4px; background: rgba(255,255,255,0.16); margin-top: 5px;"><div style="height: 4px; width: 61%; background: var(--canvas-accent);"></div></div>\n </div>\n <div>\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 12px;"><span style="opacity: 0.75;">Interviewed</span><span style="font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;">67</span></div>\n <div style="height: 4px; background: rgba(255,255,255,0.16); margin-top: 5px;"><div style="height: 4px; width: 27%; background: rgba(255,255,255,0.62);"></div></div>\n </div>\n </div>\n <div style="margin-top: auto; border-top: 1px solid rgba(255,255,255,0.18); padding-top: 11px; font-size: 12px; opacity: 0.82;">41 files stalled at review</div>\n </div>\n </div>\n\n <div style="display: flex; align-items: center; gap: 8px;">\n <span style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-right: 4px;">FACULTY</span>\n <span style="font-size: 12.5px; font-weight: 600; padding: 6px 12px; background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-fg);">All <span style="color: var(--canvas-muted); font-weight: 400;">12</span></span>\n <span style="font-size: 12.5px; padding: 6px 12px; background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">Design <span style="color: var(--canvas-muted);">4</span></span>\n <span style="font-size: 12.5px; padding: 6px 12px; background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">Business <span style="color: var(--canvas-muted);">5</span></span>\n <span style="font-size: 12.5px; padding: 6px 12px; background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">Engineering <span style="color: var(--canvas-muted);">3</span></span>\n </div>\n\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border));">\n <div style="padding: 13px 18px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); display: flex; align-items: baseline; justify-content: space-between; gap: 16px;">\n <span style="font-size: 14px; font-weight: 600;">Programmes needing attention</span>\n <span style="font-size: 12px; color: var(--canvas-muted);">4 of 12</span>\n </div>\n <div style="display: grid; grid-template-columns: 1.6fr 120px 84px 84px 92px; gap: 14px; padding: 9px 18px; background: var(--canvas-surface-2, var(--canvas-bg)); border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 10px; letter-spacing: 0.1em; font-weight: 600; color: var(--canvas-muted);">\n <span>PROGRAMME</span><span>REVIEW</span><span style="text-align: right;">APPLIED</span><span style="text-align: right;">OFFERS</span><span style="text-align: right;">WAITING</span>\n </div>\n <div style="display: grid; grid-template-columns: 1.6fr 120px 84px 84px 92px; gap: 14px; padding: 12px 18px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: center;">\n <span style="font-weight: 600;">MSc Product Design</span>\n <span style="height: 5px; background: var(--canvas-surface-2, var(--canvas-bg));"><span style="display: block; height: 5px; width: 38%; background: var(--canvas-accent);"></span></span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">31</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">4</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; color: var(--canvas-accent);">17</span>\n </div>\n <div style="display: grid; grid-template-columns: 1.6fr 120px 84px 84px 92px; gap: 14px; padding: 12px 18px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: center;">\n <span style="font-weight: 600;">MBA Sustainable Business</span>\n <span style="height: 5px; background: var(--canvas-surface-2, var(--canvas-bg));"><span style="display: block; height: 5px; width: 46%; background: var(--canvas-accent);"></span></span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">28</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">6</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; color: var(--canvas-accent);">13</span>\n </div>\n <div style="display: grid; grid-template-columns: 1.6fr 120px 84px 84px 92px; gap: 14px; padding: 12px 18px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: center;">\n <span style="font-weight: 600;">MA Curation</span>\n <span style="height: 5px; background: var(--canvas-surface-2, var(--canvas-bg));"><span style="display: block; height: 5px; width: 71%; background: color-mix(in oklab, var(--canvas-fg) 32%, var(--canvas-bg));"></span></span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">19</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">5</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">7</span>\n </div>\n <div style="display: grid; grid-template-columns: 1.6fr 120px 84px 84px 92px; gap: 14px; padding: 12px 18px; font-size: 13px; align-items: center;">\n <span style="font-weight: 600;">MEng Robotics</span>\n <span style="height: 5px; background: var(--canvas-surface-2, var(--canvas-bg));"><span style="display: block; height: 5px; width: 83%; background: color-mix(in oklab, var(--canvas-fg) 32%, var(--canvas-bg));"></span></span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">24</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">9</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">4</span>\n </div>\n </div>\n </div>\n </div>\n </div>';
|
|
23
|
+
export const canvasExemplarInfographicSkill = defineSkill({
|
|
24
|
+
name: 'canvas-exemplar-infographic',
|
|
25
|
+
description: 'A worked theme-flat infographic to read before authoring one — sandbox-legal markup ' +
|
|
26
|
+
'showing the hierarchy, grid and restraint the style calls for.',
|
|
27
|
+
tags: ['visual', 'canvas', 'design', 'exemplar'],
|
|
28
|
+
prompt: 'A worked **theme-flat infographic**. Read it, then build yours to the same shape.\n\n⚠️ This is a reference to ADAPT, not a template to fill in. Copying the words produces\na canvas about someone else\'s quarter. What to carry over is the SHAPE: one dominant\nelement, a claim rather than a label as the headline, the accent used once, figures that\nreconcile, density that varies.\n\n⚠️ It is already sandbox-legal — system fonts, inline styles, theme tokens, an explicit\nbackground, no network. Keep the outer div that declares the tokens: it is what lets the\ncanvas render on any theme, and the var(--canvas-surface-1, var(--canvas-card)) fallbacks\nkeep it working on a host that has not shipped the elevation ramp.\n\n```html\n<div style="--canvas-bg: #E9EAEE; --canvas-fg: #1B1C1F; --canvas-muted: #63656D; --canvas-accent: #C2410C; --canvas-card: #FFFFFF; --canvas-border: #D5D7DE; --canvas-surface-1: #FFFFFF; --canvas-surface-2: #F2F3F6; --canvas-hairline: #D5D7DE; width: 1000px; background: var(--canvas-bg); font-family: system-ui, -apple-system, \'Segoe UI\', Roboto, sans-serif; color: var(--canvas-fg); padding: 40px;">\n\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 24px; margin-bottom: 24px;">\n <div style="font-size: 11px; letter-spacing: 0.14em; font-weight: 600; color: var(--canvas-muted);">Q3 DELIVERY REVIEW · PLATFORM</div>\n <div style="font-size: 11px; letter-spacing: 0.08em; color: var(--canvas-muted);">as of 6 Sep 2026</div>\n </div>\n\n <div style="display: grid; grid-template-columns: 1.35fr 1fr; gap: 16px; margin-bottom: 16px;">\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 30px 32px;">\n <div style="font-size: 11px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-accent); margin-bottom: 16px;">THE QUARTER IN ONE NUMBER</div>\n <div style="font-size: 84px; line-height: 0.94; font-weight: 700; letter-spacing: -0.035em; font-variant-numeric: tabular-nums; margin-bottom: 12px;">41<span style="font-size: 40px; font-weight: 600; color: var(--canvas-muted);"> of 47</span></div>\n <div style="font-size: 20px; line-height: 1.35; font-weight: 600; letter-spacing: -0.01em; margin-bottom: 14px; max-width: 22em;">commitments shipped, and the six that slipped share one cause.</div>\n <p style="font-size: 14px; line-height: 1.65; color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg)); margin: 0;">Every delayed item was blocked on the migration, not on capacity. Team throughput rose 12% over Q2 while the queue behind a single dependency grew, which is why headcount is the wrong lever here.</p>\n </div>\n\n <div style="display: grid; grid-template-rows: repeat(3, 1fr); gap: 16px;">\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 18px 20px; display: flex; align-items: baseline; justify-content: space-between; gap: 16px;">\n <div>\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-bottom: 6px;">CYCLE TIME</div>\n <div style="font-size: 34px; line-height: 1; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums;">6.2<span style="font-size: 15px; font-weight: 500; color: var(--canvas-muted);"> days</span></div>\n </div>\n <div style="font-size: 13px; font-weight: 600; color: var(--canvas-accent); flex: none;">▼ 1.8</div>\n </div>\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 18px 20px; display: flex; align-items: baseline; justify-content: space-between; gap: 16px;">\n <div>\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-bottom: 6px;">ESCAPED DEFECTS</div>\n <div style="font-size: 34px; line-height: 1; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums;">3</div>\n </div>\n <div style="font-size: 13px; font-weight: 600; color: var(--canvas-muted); flex: none;">▼ 5</div>\n </div>\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 18px 20px; display: flex; align-items: baseline; justify-content: space-between; gap: 16px;">\n <div>\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-bottom: 6px;">BLOCKED, NOW</div>\n <div style="font-size: 34px; line-height: 1; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums;">6</div>\n </div>\n <div style="font-size: 13px; font-weight: 600; color: var(--canvas-muted); flex: none;">▲ 4</div>\n </div>\n </div>\n </div>\n\n <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">\n\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 22px 24px 20px;">\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-bottom: 18px;">SHIPPED PER SPRINT</div>\n <svg width="100%" height="150" viewBox="0 0 420 150" style="display: block; overflow: visible;">\n <line x1="0" y1="126" x2="420" y2="126" style="stroke: var(--canvas-hairline, var(--canvas-border));" stroke-width="1"></line>\n <rect x="10" y="72" width="46" height="54" style="fill: color-mix(in oklab, var(--canvas-fg) 22%, var(--canvas-bg));"></rect>\n <text x="33" y="62" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-fg); font-family: system-ui, sans-serif;">6</text>\n <text x="33" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S1</text>\n <rect x="76" y="45" width="46" height="81" style="fill: color-mix(in oklab, var(--canvas-fg) 22%, var(--canvas-bg));"></rect>\n <text x="99" y="35" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-fg); font-family: system-ui, sans-serif;">9</text>\n <text x="99" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S2</text>\n <rect x="142" y="54" width="46" height="72" style="fill: color-mix(in oklab, var(--canvas-fg) 22%, var(--canvas-bg));"></rect>\n <text x="165" y="44" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-fg); font-family: system-ui, sans-serif;">8</text>\n <text x="165" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S3</text>\n <rect x="208" y="27" width="46" height="99" style="fill: color-mix(in oklab, var(--canvas-fg) 22%, var(--canvas-bg));"></rect>\n <text x="231" y="17" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-fg); font-family: system-ui, sans-serif;">11</text>\n <text x="231" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S4</text>\n <rect x="274" y="99" width="46" height="27" style="fill: var(--canvas-accent);"></rect>\n <text x="297" y="89" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-accent); font-family: system-ui, sans-serif;">3</text>\n <text x="297" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S5</text>\n <rect x="340" y="90" width="46" height="36" style="fill: color-mix(in oklab, var(--canvas-fg) 22%, var(--canvas-bg));"></rect>\n <text x="363" y="80" text-anchor="middle" font-size="13" font-weight="700" style="fill: var(--canvas-fg); font-family: system-ui, sans-serif;">4</text>\n <text x="363" y="142" text-anchor="middle" font-size="11" style="fill: var(--canvas-muted); font-family: system-ui, sans-serif;">S6</text>\n </svg>\n <div style="font-size: 13px; line-height: 1.55; color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg)); margin-top: 20px; border-top: 1px solid var(--canvas-hairline, var(--canvas-border)); padding-top: 12px;">Sprint 5 is when the migration landed in the critical path.</div>\n </div>\n\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 22px 24px 20px;">\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-bottom: 14px;">THE SIX THAT SLIPPED</div>\n <div style="background: var(--canvas-surface-2, var(--canvas-bg)); border: 1px solid var(--canvas-hairline, var(--canvas-border));">\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 8px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 10px; letter-spacing: 0.1em; font-weight: 600; color: var(--canvas-muted);"><span>COMMITMENT</span><span>BLOCKED BY</span><span style="text-align: right;">DAYS</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">Billing export</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">21</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">Audit trail</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">18</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">SSO for teams</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">14</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">Usage alerts</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">11</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">Retention job</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">9</span></div>\n <div style="display: grid; grid-template-columns: 1fr 88px 74px; gap: 12px; padding: 10px 14px; font-size: 13px; align-items: baseline;"><span style="font-weight: 600;">Region failover</span><span style="color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg));">migration</span><span style="text-align: right; font-variant-numeric: tabular-nums;">6</span></div>\n </div>\n <div style="font-size: 13px; line-height: 1.55; color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg)); margin-top: 16px;">One dependency, 79 days of accumulated delay.</div>\n </div>\n </div>\n\n <div style="border-top: 1px solid var(--canvas-hairline, var(--canvas-border)); margin-top: 26px; padding-top: 14px; display: flex; align-items: baseline; justify-content: space-between; gap: 24px; font-size: 11px; letter-spacing: 0.06em; color: var(--canvas-muted);">\n <span>PLATFORM · QUARTERLY REVIEW</span>\n <span>Source: delivery board, sprints 1–6</span>\n </div>\n </div>\n```\n\n## The same design, dark\n\nNothing about the markup changes — only these nine values on the wrapper. A palette swap\nis not a different design, and if you find yourself restructuring for dark, something in\nthe structure was carrying the colour\'s weight.\n\n```\n--canvas-bg: #17181C; --canvas-fg: #ECEDF1; --canvas-muted: #9A9CA6; --canvas-accent: #FB7B4B; --canvas-card: #22242A; --canvas-border: #31333B; --canvas-surface-1: #22242A; --canvas-surface-2: #1B1D22; --canvas-hairline: #31333B\n```',
|
|
29
|
+
});
|
|
30
|
+
export const canvasExemplarAppScreenSkill = defineSkill({
|
|
31
|
+
name: 'canvas-exemplar-app-screen',
|
|
32
|
+
description: 'A worked app-screen mock to read before drawing a UI — four surfaces, one active ' +
|
|
33
|
+
'state, a finding rather than a page name.',
|
|
34
|
+
tags: ['visual', 'canvas', 'design', 'exemplar'],
|
|
35
|
+
prompt: 'A worked **app-screen mock** — one screen of an application, not a wireframe.\n\n⚠️ This is a reference to ADAPT, not a template to fill in. Copying the words produces\na canvas about someone else\'s quarter. What to carry over is the SHAPE: one dominant\nelement, a claim rather than a label as the headline, the accent used once, figures that\nreconcile, density that varies.\n\n⚠️ It is already sandbox-legal — system fonts, inline styles, theme tokens, an explicit\nbackground, no network. Keep the outer div that declares the tokens: it is what lets the\ncanvas render on any theme, and the var(--canvas-surface-1, var(--canvas-card)) fallbacks\nkeep it working on a host that has not shipped the elevation ramp.\n\n⚠️ Note what it does NOT draw: no traffic lights, no browser tab bar, no URL field.\nWindow chrome costs vertical space and dates the mock; the app\'s own header is the frame.\n\n```html\n<div style="--canvas-bg: #E9EAEE; --canvas-fg: #1B1C1F; --canvas-muted: #63656D; --canvas-accent: #C2410C; --canvas-card: #FFFFFF; --canvas-border: #D5D7DE; --canvas-surface-1: #FFFFFF; --canvas-surface-2: #F2F3F6; --canvas-hairline: #DCDEE4; width: 1000px; background: var(--canvas-surface-1, var(--canvas-card)); font-family: system-ui, -apple-system, \'Segoe UI\', Roboto, sans-serif; color: var(--canvas-fg); display: grid; grid-template-columns: 232px 1fr;">\n\n <div style="border-right: 1px solid var(--canvas-hairline, var(--canvas-border)); display: flex; flex-direction: column; min-height: 640px;">\n <div style="padding: 18px 18px 16px; display: flex; align-items: center; gap: 10px;">\n <span style="width: 28px; height: 28px; background: var(--canvas-fg); color: var(--canvas-surface-1, var(--canvas-card)); font-size: 11px; font-weight: 700; letter-spacing: 0.02em; display: flex; align-items: center; justify-content: center; flex: none;">CO</span>\n <span style="font-size: 15px; font-weight: 700; letter-spacing: -0.01em;">Cohort</span>\n </div>\n\n <div style="padding: 6px 10px 0; display: flex; flex-direction: column; gap: 1px;">\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; background: color-mix(in oklab, var(--canvas-accent) 10%, var(--canvas-surface-1, var(--canvas-card))); box-shadow: inset 2px 0 0 var(--canvas-accent); font-size: 13.5px; font-weight: 600;">\n <span style="font-size: 13px; flex: none; color: var(--canvas-accent);">■</span>Overview\n </div>\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">\n <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="flex: none; color: var(--canvas-muted);"><circle cx="6" cy="6" r="2.5"></circle><path d="M2 13.5c.8-2.2 2.2-3.3 4-3.3s3.2 1.1 4 3.3"></path><path d="M11 4.2a2.5 2.5 0 0 1 0 4.6"></path></svg>Applicants\n <span style="margin-left: auto; font-size: 12px; color: var(--canvas-muted); font-variant-numeric: tabular-nums;">248</span>\n </div>\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">\n <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="flex: none; color: var(--canvas-muted);"><rect x="2.5" y="3.5" width="11" height="10" rx="1"></rect><path d="M2.5 6.5h11M5.5 2v2.5M10.5 2v2.5"></path></svg>Interviews\n <span style="margin-left: auto; font-size: 12px; color: var(--canvas-muted); font-variant-numeric: tabular-nums;">67</span>\n </div>\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">\n <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="flex: none; color: var(--canvas-muted);"><path d="M9.5 2H4.5A1.5 1.5 0 0 0 3 3.5v9A1.5 1.5 0 0 0 4.5 14h7a1.5 1.5 0 0 0 1.5-1.5V5.5z"></path><path d="M9.5 2v3.5H13"></path></svg>Documents\n </div>\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">\n <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="flex: none; color: var(--canvas-muted);"><path d="M2 14h12"></path><path d="M4.5 14V9M8 14V4.5M11.5 14V7"></path></svg>Reports\n </div>\n <div style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">\n <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="flex: none; color: var(--canvas-muted);"><path d="M2 5.5A1.5 1.5 0 0 1 3.5 4h2.2l1.3 1.6h5.5A1.5 1.5 0 0 1 14 7.1v5.4A1.5 1.5 0 0 1 12.5 14h-9A1.5 1.5 0 0 1 2 12.5z"></path></svg>Programmes\n <span style="margin-left: auto; font-size: 12px; color: var(--canvas-muted); font-variant-numeric: tabular-nums;">12</span>\n </div>\n </div>\n\n <div style="margin-top: auto; border-top: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 12px 22px; font-size: 13.5px; color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">Settings</div>\n <div style="border-top: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 14px 18px; display: flex; align-items: center; gap: 10px;">\n <span style="width: 30px; height: 30px; background: var(--canvas-surface-2, var(--canvas-bg)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 11px; font-weight: 600; color: var(--canvas-muted); display: flex; align-items: center; justify-content: center; flex: none;">RM</span>\n <span>\n <span style="display: block; font-size: 13px; font-weight: 600;">Rita Marchetti</span>\n <span style="display: block; font-size: 11px; color: var(--canvas-muted);">Admissions lead</span>\n </span>\n </div>\n </div>\n\n <div style="display: flex; flex-direction: column;">\n <div style="padding: 20px 28px 18px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); display: flex; align-items: flex-end; justify-content: space-between; gap: 24px;">\n <div>\n <div style="font-size: 11px; letter-spacing: 0.06em; color: var(--canvas-muted); margin-bottom: 6px;">Autumn 2027 / Admissions</div>\n <div style="font-size: 26px; font-weight: 700; letter-spacing: -0.022em;">Overview</div>\n </div>\n <div style="display: flex; align-items: center; gap: 8px; flex: none;">\n <span style="font-size: 13px; padding: 8px 14px; border: 1px solid var(--canvas-hairline, var(--canvas-border)); color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">Export</span>\n <span style="font-size: 13px; font-weight: 600; padding: 9px 15px; background: var(--canvas-fg); color: var(--canvas-surface-1, var(--canvas-card));">New applicant</span>\n </div>\n </div>\n <div style="background: var(--canvas-surface-2, var(--canvas-bg)); padding: 20px 28px 26px; flex: 1; display: flex; flex-direction: column; gap: 16px;">\n\n <div style="display: grid; grid-template-columns: 1.45fr 1fr; gap: 16px;">\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); padding: 22px 24px;">\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 14px;">\n <div style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-accent);">THIS WEEK</div>\n <div style="font-size: 11px; color: var(--canvas-muted);">updated 4 min ago</div>\n </div>\n <div style="font-size: 27px; line-height: 1.2; font-weight: 700; letter-spacing: -0.022em; margin-bottom: 10px; max-width: 20em;">Interviews are keeping pace. Document review is not.</div>\n <p style="font-size: 13.5px; line-height: 1.65; color: color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg)); margin: 0 0 16px;">248 applicants across 12 programmes, and 67 have reached interview. The queue sits at document review, where 41 files have waited more than five days — two programmes account for 30 of them.</p>\n <span style="display: inline-block; font-size: 12.5px; font-weight: 600; color: var(--canvas-accent); border-bottom: 1px solid var(--canvas-accent); padding-bottom: 1px;">Review the 41 waiting files</span>\n </div>\n\n <div style="background: var(--canvas-fg); color: var(--canvas-surface-1, var(--canvas-card)); padding: 20px 22px; display: flex; flex-direction: column; gap: 14px;">\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 12px;">\n <span style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600;">PIPELINE</span>\n <span style="font-size: 10px; letter-spacing: 0.06em; opacity: 0.62;">stage by stage</span>\n </div>\n <div style="display: flex; flex-direction: column; gap: 11px;">\n <div>\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 12px;"><span style="opacity: 0.75;">Applied</span><span style="font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;">248</span></div>\n <div style="height: 4px; background: rgba(255,255,255,0.16); margin-top: 5px;"><div style="height: 4px; width: 100%; background: rgba(255,255,255,0.62);"></div></div>\n </div>\n <div>\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 12px;"><span style="opacity: 0.75;">Documents in</span><span style="font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;">193</span></div>\n <div style="height: 4px; background: rgba(255,255,255,0.16); margin-top: 5px;"><div style="height: 4px; width: 78%; background: rgba(255,255,255,0.62);"></div></div>\n </div>\n <div>\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 12px;"><span style="opacity: 0.75;">Reviewed</span><span style="font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;">152</span></div>\n <div style="height: 4px; background: rgba(255,255,255,0.16); margin-top: 5px;"><div style="height: 4px; width: 61%; background: var(--canvas-accent);"></div></div>\n </div>\n <div>\n <div style="display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 12px;"><span style="opacity: 0.75;">Interviewed</span><span style="font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;">67</span></div>\n <div style="height: 4px; background: rgba(255,255,255,0.16); margin-top: 5px;"><div style="height: 4px; width: 27%; background: rgba(255,255,255,0.62);"></div></div>\n </div>\n </div>\n <div style="margin-top: auto; border-top: 1px solid rgba(255,255,255,0.18); padding-top: 11px; font-size: 12px; opacity: 0.82;">41 files stalled at review</div>\n </div>\n </div>\n\n <div style="display: flex; align-items: center; gap: 8px;">\n <span style="font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--canvas-muted); margin-right: 4px;">FACULTY</span>\n <span style="font-size: 12.5px; font-weight: 600; padding: 6px 12px; background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-fg);">All <span style="color: var(--canvas-muted); font-weight: 400;">12</span></span>\n <span style="font-size: 12.5px; padding: 6px 12px; background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">Design <span style="color: var(--canvas-muted);">4</span></span>\n <span style="font-size: 12.5px; padding: 6px 12px; background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">Business <span style="color: var(--canvas-muted);">5</span></span>\n <span style="font-size: 12.5px; padding: 6px 12px; background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border)); color: color-mix(in oklab, var(--canvas-fg) 82%, var(--canvas-bg));">Engineering <span style="color: var(--canvas-muted);">3</span></span>\n </div>\n\n <div style="background: var(--canvas-surface-1, var(--canvas-card)); border: 1px solid var(--canvas-hairline, var(--canvas-border));">\n <div style="padding: 13px 18px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); display: flex; align-items: baseline; justify-content: space-between; gap: 16px;">\n <span style="font-size: 14px; font-weight: 600;">Programmes needing attention</span>\n <span style="font-size: 12px; color: var(--canvas-muted);">4 of 12</span>\n </div>\n <div style="display: grid; grid-template-columns: 1.6fr 120px 84px 84px 92px; gap: 14px; padding: 9px 18px; background: var(--canvas-surface-2, var(--canvas-bg)); border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 10px; letter-spacing: 0.1em; font-weight: 600; color: var(--canvas-muted);">\n <span>PROGRAMME</span><span>REVIEW</span><span style="text-align: right;">APPLIED</span><span style="text-align: right;">OFFERS</span><span style="text-align: right;">WAITING</span>\n </div>\n <div style="display: grid; grid-template-columns: 1.6fr 120px 84px 84px 92px; gap: 14px; padding: 12px 18px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: center;">\n <span style="font-weight: 600;">MSc Product Design</span>\n <span style="height: 5px; background: var(--canvas-surface-2, var(--canvas-bg));"><span style="display: block; height: 5px; width: 38%; background: var(--canvas-accent);"></span></span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">31</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">4</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; color: var(--canvas-accent);">17</span>\n </div>\n <div style="display: grid; grid-template-columns: 1.6fr 120px 84px 84px 92px; gap: 14px; padding: 12px 18px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: center;">\n <span style="font-weight: 600;">MBA Sustainable Business</span>\n <span style="height: 5px; background: var(--canvas-surface-2, var(--canvas-bg));"><span style="display: block; height: 5px; width: 46%; background: var(--canvas-accent);"></span></span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">28</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">6</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; color: var(--canvas-accent);">13</span>\n </div>\n <div style="display: grid; grid-template-columns: 1.6fr 120px 84px 84px 92px; gap: 14px; padding: 12px 18px; border-bottom: 1px solid var(--canvas-hairline, var(--canvas-border)); font-size: 13px; align-items: center;">\n <span style="font-weight: 600;">MA Curation</span>\n <span style="height: 5px; background: var(--canvas-surface-2, var(--canvas-bg));"><span style="display: block; height: 5px; width: 71%; background: color-mix(in oklab, var(--canvas-fg) 32%, var(--canvas-bg));"></span></span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">19</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">5</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">7</span>\n </div>\n <div style="display: grid; grid-template-columns: 1.6fr 120px 84px 84px 92px; gap: 14px; padding: 12px 18px; font-size: 13px; align-items: center;">\n <span style="font-weight: 600;">MEng Robotics</span>\n <span style="height: 5px; background: var(--canvas-surface-2, var(--canvas-bg));"><span style="display: block; height: 5px; width: 83%; background: color-mix(in oklab, var(--canvas-fg) 32%, var(--canvas-bg));"></span></span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">24</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">9</span>\n <span style="text-align: right; font-variant-numeric: tabular-nums;">4</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n```',
|
|
36
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Identical for every icon; the agent emits this and drops one body inside. */
|
|
2
|
+
export declare const ICON_WRAPPER: string;
|
|
3
|
+
export declare const ICON_BODIES: Record<string, string>;
|
|
4
|
+
/** The one deliberate exception to stroke-only. */
|
|
5
|
+
export declare const ACTIVE_MARKER = "<rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" fill=\"currentColor\" stroke=\"none\"/>";
|
|
6
|
+
export declare const canvasIconsSkill: import("@compilr-dev/agents").Skill;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The twenty-shape icon set a canvas may use.
|
|
3
|
+
*
|
|
4
|
+
* ⚠️ WHY A FIXED SET. `infographic`'s "icons & shapes" section said "inline SVG,
|
|
5
|
+
* consistent stroke width" and gave the agent nothing to be consistent WITH, so every
|
|
6
|
+
* canvas invented its own paths — and where invention felt too hard, emoji arrived
|
|
7
|
+
* instead. The counter-example in the design handoff has a bar chart, a clock, a snake
|
|
8
|
+
* and an hourglass as its stat-tile icons.
|
|
9
|
+
*
|
|
10
|
+
* ⚠️ SMALL ON PURPOSE. One wrapper plus twenty bodies is a few hundred tokens; twenty
|
|
11
|
+
* complete SVG elements would be several thousand, which is the difference between a set
|
|
12
|
+
* an agent reads and one it skips.
|
|
13
|
+
*/
|
|
14
|
+
import { defineSkill } from '@compilr-dev/agents';
|
|
15
|
+
/** Identical for every icon; the agent emits this and drops one body inside. */
|
|
16
|
+
export const ICON_WRAPPER = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" ' +
|
|
17
|
+
'stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">BODY</svg>';
|
|
18
|
+
export const ICON_BODIES = {
|
|
19
|
+
grid: '<rect x="2" y="2" width="12" height="12"/><path d="M8 2v12M2 8h12"/>',
|
|
20
|
+
list: '<path d="M5.5 4H14M5.5 8H14M5.5 12H14M2.5 4h.01M2.5 8h.01M2.5 12h.01"/>',
|
|
21
|
+
users: '<circle cx="6" cy="6" r="2.5"/><path d="M2 13.5c.8-2.2 2.2-3.3 4-3.3s3.2 1.1 4 3.3"/><path d="M11 4.2a2.5 2.5 0 0 1 0 4.6"/>',
|
|
22
|
+
document: '<path d="M9.5 2H4.5A1.5 1.5 0 0 0 3 3.5v9A1.5 1.5 0 0 0 4.5 14h7a1.5 1.5 0 0 0 1.5-1.5V5.5z"/><path d="M9.5 2v3.5H13"/>',
|
|
23
|
+
folder: '<path d="M2 5.5A1.5 1.5 0 0 1 3.5 4h2.2l1.3 1.6h5.5A1.5 1.5 0 0 1 14 7.1v5.4A1.5 1.5 0 0 1 12.5 14h-9A1.5 1.5 0 0 1 2 12.5z"/>',
|
|
24
|
+
chart: '<path d="M2 14h12"/><path d="M4.5 14V9M8 14V4.5M11.5 14V7"/>',
|
|
25
|
+
calendar: '<rect x="2.5" y="3.5" width="11" height="10" rx="1"/><path d="M2.5 6.5h11M5.5 2v2.5M10.5 2v2.5"/>',
|
|
26
|
+
clock: '<circle cx="8" cy="8" r="6"/><path d="M8 4.5V8l2.5 1.5"/>',
|
|
27
|
+
search: '<circle cx="7" cy="7" r="4.5"/><path d="M10.5 10.5 14 14"/>',
|
|
28
|
+
settings: '<path d="M2 5h6.5M13 5h1M2 11h1M7.5 11H14"/><circle cx="10.5" cy="5" r="1.6"/><circle cx="5" cy="11" r="1.6"/>',
|
|
29
|
+
tag: '<path d="M8.6 2H13a1 1 0 0 1 1 1v4.4l-6.3 6.3a1 1 0 0 1-1.4 0L2.3 9.7a1 1 0 0 1 0-1.4z"/><path d="M11 5h.01"/>',
|
|
30
|
+
'add-card': '<rect x="2" y="2.5" width="12" height="11" rx="1"/><path d="M8 6v5M5.5 8.5h5"/>',
|
|
31
|
+
plus: '<path d="M8 3v10M3 8h10"/>',
|
|
32
|
+
check: '<path d="M3 8.5 6.5 12 13 4.5"/>',
|
|
33
|
+
close: '<path d="M4 4l8 8M12 4l-8 8"/>',
|
|
34
|
+
alert: '<path d="M8 2.5 14.5 13.5h-13z"/><path d="M8 6.5v3M8 11.6h.01"/>',
|
|
35
|
+
chevron: '<path d="M6 3.5 10.5 8 6 12.5"/>',
|
|
36
|
+
external: '<path d="M6.5 9.5 14 2M14 2H9.5M14 2v4.5"/><path d="M12 10v2.5A1.5 1.5 0 0 1 10.5 14h-7A1.5 1.5 0 0 1 2 12.5v-7A1.5 1.5 0 0 1 3.5 4H6"/>',
|
|
37
|
+
'arrow-up': '<path d="M8 13V3M4 7l4-4 4 4"/>',
|
|
38
|
+
'arrow-down': '<path d="M8 3v10M4 9l4 4 4-4"/>',
|
|
39
|
+
};
|
|
40
|
+
/** The one deliberate exception to stroke-only. */
|
|
41
|
+
export const ACTIVE_MARKER = '<rect x="4" y="4" width="8" height="8" fill="currentColor" stroke="none"/>';
|
|
42
|
+
const table = Object.entries(ICON_BODIES)
|
|
43
|
+
.map(([name, body]) => `| \`${name}\` | \`${body}\` |`)
|
|
44
|
+
.join('\n');
|
|
45
|
+
export const canvasIconsSkill = defineSkill({
|
|
46
|
+
name: 'canvas-icons',
|
|
47
|
+
description: 'The twenty-shape icon set for canvases — one SVG wrapper, twenty bodies, plus the ' +
|
|
48
|
+
'rules that keep a set of icons from becoming decoration.',
|
|
49
|
+
tags: ['visual', 'canvas', 'design', 'icons'],
|
|
50
|
+
prompt: `Twenty shapes, one stroke weight. Use these rather than inventing a path — and
|
|
51
|
+
rather than an emoji, which is what a canvas reaches for when drawing feels hard.
|
|
52
|
+
|
|
53
|
+
## The wrapper — identical for every icon
|
|
54
|
+
|
|
55
|
+
\`\`\`html
|
|
56
|
+
${ICON_WRAPPER}
|
|
57
|
+
\`\`\`
|
|
58
|
+
|
|
59
|
+
## The bodies
|
|
60
|
+
|
|
61
|
+
| name | body |
|
|
62
|
+
|---|---|
|
|
63
|
+
${table}
|
|
64
|
+
|
|
65
|
+
## Rules
|
|
66
|
+
|
|
67
|
+
1. **\`currentColor\`, never a token.** Colour the parent; the icon inherits.
|
|
68
|
+
\`stroke="var(--canvas-accent)"\` on an icon is how a cluster drifts out of the palette.
|
|
69
|
+
2. **16 grid, not 24.** Stroke 1.5 on a 16 grid holds detail down to 14px, where nav rows
|
|
70
|
+
and table cells live. A 24 grid scaled to 14 puts hairlines below one device pixel.
|
|
71
|
+
3. **14px is the floor.** Below it, drop the icon — do not shrink it.
|
|
72
|
+
4. **Scale with the \`width\`/\`height\` attributes only.** Never edit the geometry.
|
|
73
|
+
5. **Stroke only, \`fill="none"\`.** One exception, the active-nav marker, deliberately the
|
|
74
|
+
only solid mark on a screen: \`${ACTIVE_MARKER}\`
|
|
75
|
+
6. **Twenty is a budget, not a start.** If a canvas needs a twenty-first, use a word. A
|
|
76
|
+
text label always beats a guessed glyph.
|
|
77
|
+
7. **One icon per row at most** — leading, or none. Icons on both sides of a row, or one
|
|
78
|
+
per stat tile, is decoration; that is the slot emoji creep into.
|
|
79
|
+
|
|
80
|
+
## Deltas
|
|
81
|
+
|
|
82
|
+
\`arrow-up\` and \`arrow-down\` carry direction beside a figure. Both inherit
|
|
83
|
+
\`currentColor\`, so the arrow can never disagree with its number.`,
|
|
84
|
+
});
|
|
@@ -35,19 +35,56 @@ export const canvasSkill = defineSkill({
|
|
|
35
35
|
|
|
36
36
|
## STEPS
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- **Key content / data** — the actual points, numbers, sections, or slides to include. Don't invent data.
|
|
42
|
-
- **Style / brand** — theme-matched (default), a specific palette/brand, or a named **aesthetic**? For infographics & carousels you can offer a look from the \`canvas-styles\` skill (skeuomorphic, glass, brutalist, editorial, retro) as part of THIS same question — don't default every canvas to the flat theme look.
|
|
43
|
-
For open design directions (which layout, which visual approach), present concrete options with **\`propose_alternatives\`** instead of guessing.
|
|
44
|
-
**Skip questions the user already answered**, and if they gave full detail or explicitly said "just make it / surprise me / your call", go straight to authoring. Keep it to ONE focused round — a short question batch, never a long interview — then build.
|
|
38
|
+
⚠️ **Two passes, not one.** Most weak canvases are weak because layout and decoration got
|
|
39
|
+
decided in the same breath, and the decoration ends up compensating for a structure that
|
|
40
|
+
never worked. Structure first, with the real content; skin it second, from a recipe.
|
|
45
41
|
|
|
46
|
-
|
|
42
|
+
1. **Ask purpose, audience and content — never taste.** Use **\`ask_user\`** (batch into ONE
|
|
43
|
+
call):
|
|
44
|
+
- **Purpose & audience** — what is it for, who reads it?
|
|
45
|
+
- **Key content / data** — the actual points, numbers, sections or slides. Don't invent
|
|
46
|
+
data; if you need a figure you were not given, ask for it.
|
|
47
|
+
|
|
48
|
+
⚠️ **Do NOT ask which style or aesthetic they want.** "Brutalist or editorial?" asks
|
|
49
|
+
someone to imagine two things they have never seen, in a vocabulary they did not choose,
|
|
50
|
+
before the canvas exists — and then commits you to whatever comes back. Purpose,
|
|
51
|
+
audience and content are answerable from what the user already knows. Style is
|
|
52
|
+
answerable from what they can SEE, which is step 8.
|
|
53
|
+
|
|
54
|
+
**Skip the round entirely** when they said "just make it / surprise me / your call" or
|
|
55
|
+
already gave full detail. This round asks LESS than it used to, not more.
|
|
56
|
+
|
|
57
|
+
⚠️ **IF THE QUESTION ROUND FAILS, SAY SO AND ASK AGAIN — do not author anyway.** An
|
|
58
|
+
\`ask_user\` call can die on the output limit, and the failure looks like nothing: no
|
|
59
|
+
answers arrive and authoring simply continues on invented content. That is how a canvas
|
|
60
|
+
ends up full of placeholder names nobody asked for. If the round did not come back, send
|
|
61
|
+
ONE short retry; if that fails too, tell the user what you need in one line and stop.
|
|
62
|
+
Inventing the brief wastes the whole pass.
|
|
63
|
+
|
|
64
|
+
2. **Route the type and style from the content**, using the cheatsheet in
|
|
65
|
+
\`canvas_guide("styles")\`. One screen of an app → \`infographic\` + the app-screen style.
|
|
66
|
+
Several options compared → \`board\`. Slides → \`carousel\`. Data or a one-pager →
|
|
67
|
+
\`infographic\` + theme-flat.
|
|
68
|
+
|
|
69
|
+
⚠️ **REAL IMAGES GO IN AS ASSETS.** If the user supplied photos, logos or screenshots, put
|
|
70
|
+
each one in with \`canvas_asset_add\` (canvas_id, path, ref) and reference it as
|
|
71
|
+
\`<img src="asset:REF" alt="what it shows">\`. Do **not** paste base64 into the markup — it
|
|
72
|
+
would work, and it would bury the document under hundreds of KB that \`canvas_edit\` then has
|
|
73
|
+
to patch around. Do **not** draw a grey placeholder box when a real image was provided:
|
|
74
|
+
that is the single thing that makes a mock unreviewable. \`canvas_asset_list\` shows what is
|
|
75
|
+
stored and what the markup actually uses.
|
|
76
|
+
|
|
77
|
+
3. **Pass one — structure, with the FINAL content.** No colour decisions, no type scale yet:
|
|
78
|
+
get the real words and real numbers into the real layout. A structure that works with
|
|
79
|
+
placeholder text is not a structure.
|
|
80
|
+
|
|
81
|
+
Build it in small steps — never one giant tool call. A canvas is HTML/SVG you emit as
|
|
82
|
+
tool arguments; a single very large \`canvas_write\` can overrun the output limit, get cut
|
|
83
|
+
off mid-arguments, and fail. Emit each call immediately with NO prose preamble
|
|
84
|
+
(narration competes with the HTML for the same output budget):
|
|
47
85
|
- **2a. First \`canvas_write\`** (type, title, html) = a COMPACT skeleton: the \`<style>\` block, the overall layout, and just the first section or heading. This is the ONLY way to create a canvas — describing it in chat does nothing.
|
|
48
86
|
- **2b. Then \`canvas_edit\` (operation=append)** to add each remaining section, one call per section. The preview grows as you go, and every call stays small and reliable. (You can also leave \`<!-- placeholder -->\` markers in 2a and str_replace them.)
|
|
49
87
|
- Put the whole thing in one \`canvas_write\` ONLY if it is genuinely small (a single stat card / short poster).
|
|
50
|
-
|
|
51
88
|
HTML constraints for every write:
|
|
52
89
|
- Do NOT include \`<html>\`, \`<head>\`, \`<meta>\`, \`<!doctype>\`, or your own CSP — the host injects the sandbox and CSP. Just the body content + a \`<style>\` and optional \`<script>\`.
|
|
53
90
|
- The sandbox is \`allow-scripts\` with NO same-origin and CSP \`default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob:\`. So: inline \`<style>\`/\`<script>\` only, no external fonts/CSS/JS/network, no remote images (use inline SVG or data: URIs).
|
|
@@ -56,7 +93,13 @@ export const canvasSkill = defineSkill({
|
|
|
56
93
|
- Make it look intentional: a clear grid, strong type scale, generous spacing. Use \`var(--canvas-accent)\` sparingly for emphasis. Prefer inline SVG for shapes/charts/icons (fill/stroke with the theme vars).
|
|
57
94
|
- For a **carousel**, wrap each slide in \`<section data-sheet>…</section>\` — a natural unit to add one per \`canvas_edit\` append.
|
|
58
95
|
|
|
59
|
-
|
|
96
|
+
4. **Pass two — skin it.** Read \`canvas_guide\` for your style's recipe and its exemplar
|
|
97
|
+
(\`exemplar-infographic\` or \`exemplar-app-screen\`), then apply the values. This pass is
|
|
98
|
+
mechanical, because the recipe supplies every number — surfaces, type ladder, spacing
|
|
99
|
+
scale, accent budget. Edit in place with \`canvas_edit\`; pass one already put the content
|
|
100
|
+
where it belongs.
|
|
101
|
+
|
|
102
|
+
5. **Add a Tweaks controls manifest when it helps** (the \`controls\` argument). Each control is \`{ type, param, label, default, …type config }\` where type ∈ slider | number | toggle | select | color | text.
|
|
60
103
|
- **⚠️ EVERY control you declare MUST be bound in the HTML — a declared-but-unbound control is a dead knob that visibly does nothing when the user drags it. Declaring the control is only half the job; you MUST also reference its param.** Bind each param one of these ways:
|
|
61
104
|
- CSS custom property (most common): use \`var(--param)\` directly in your styles — e.g. a \`headline\` slider means \`font-size: var(--headline)\` (NOT a literal \`48px\`), an \`accent\` color means \`color: var(--accent)\`. The host sets \`--param\` on the root and updates it live. Include a unit in the CSS if the raw value is a number: \`font-size: calc(var(--headline) * 1px)\`.
|
|
62
105
|
- Text binding: \`<span data-bind="param"></span>\` — its text is replaced with the value.
|
|
@@ -65,13 +108,55 @@ export const canvasSkill = defineSkill({
|
|
|
65
108
|
- Give every canvas at least 2–4 sensible controls (accent color, a headline size slider, a toggle to show/hide a section). Seed \`default\` values that MATCH what you authored (a slider default of 48 means the HTML's initial \`var(--headline)\` should read 48).
|
|
66
109
|
- **Before finishing, re-check: is each control's \`param\` actually referenced in the HTML?** If not, either bind it or drop the control — never ship a dead knob.
|
|
67
110
|
|
|
68
|
-
|
|
111
|
+
6. **To EDIT an existing canvas, do NOT re-send the whole document.** First call \`canvas_get\` with \`outline=true\` (or a \`startLine\`/\`maxLines\` slice) to find the exact snippet, then \`canvas_edit\` with \`operation=str_replace\` (old_str must be unique — include surrounding context — or set replace_all=true), or append/prepend. Reserve \`canvas_write\` with \`canvas_id\` for a full intentional rewrite.
|
|
112
|
+
|
|
113
|
+
7. **Validate.** Call \`canvas_validate\` (canvas_id) — a fast static check for content that
|
|
114
|
+
won't render (Mermaid/Markdown/CDN), a board missing its \`data-board\` bounds or with
|
|
115
|
+
nodes off-canvas, sparse output, hardcoded colours that ignore the theme, a card that
|
|
116
|
+
shares its ground's value, text under 4.5:1, too many hues, and dead Tweaks. Fix every
|
|
117
|
+
**error** and address applicable **warnings**.
|
|
118
|
+
|
|
119
|
+
8. **The gate — screenshot, verdict, fix, screenshot AGAIN.** Call \`canvas_screenshot\`
|
|
120
|
+
(canvas_id), then give all six verdicts explicitly, in this form:
|
|
121
|
+
|
|
122
|
+
\`01 pass · 02 fail → fixed · 03 pass · 04 pass · 05 fail → fixed · 06 pass\`
|
|
123
|
+
|
|
124
|
+
| # | check | the question to ask |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| 01 | One dominant element | Squint: what do you see FIRST? If the answer is "the whole thing at once", nothing dominates. The largest element should be ≥2x the next and hold the FINDING, not merely the first metric. |
|
|
127
|
+
| 02 | Cards differ from their ground | Cover the borders with your thumb — can you still see the cards? If the layout only exists because of its lines, the ramp is missing. |
|
|
128
|
+
| 03 | Nothing under 4.5:1 | Check every label against the surface it ACTUALLY sits on, not against the page. |
|
|
129
|
+
| 04 | Every value is specific | Do the numbers add up? Could a reader challenge one? A total that does not reconcile with its rows is what makes a canvas feel machine-made. |
|
|
130
|
+
| 05 | Density varies | Blur it until the text goes — is there a composition left? A uniform grid of equal boxes is a form. |
|
|
131
|
+
| 06 | One accent, one family | Count the hues, then count the reasons. More hues than reasons means colour is decoration. |
|
|
69
132
|
|
|
70
|
-
|
|
133
|
+
⚠️ **Naming each check is what forces looking at it.** Asked for a summary judgement, a
|
|
134
|
+
model writes "looks good" every time.
|
|
71
135
|
|
|
72
|
-
|
|
136
|
+
⚠️ **FAILING IS NORMAL** — most first drafts fail two of these. A failed check is
|
|
137
|
+
something to EDIT, not something to argue with. Do not write a justification.
|
|
73
138
|
|
|
74
|
-
|
|
139
|
+
⚠️ **A \`canvas_validate\` WARNING IS A FAILED CHECK, not an opinion to weigh.** If it
|
|
140
|
+
reported too many hues, 06 is a fail; if it reported a card on its ground, 02 is a fail.
|
|
141
|
+
Fix it and re-screenshot. Answering a warning with why the canvas is an exception — "the
|
|
142
|
+
tile colours are deliberately varied", "this is a committed aesthetic" — is the
|
|
143
|
+
justification this step exists to stop, and it is how a draft self-passes six out of six
|
|
144
|
+
while visibly breaking one of them.
|
|
145
|
+
|
|
146
|
+
⚠️ **The second screenshot is the one that matters**, because it catches a fix that broke
|
|
147
|
+
something else. Cap at two rounds; if something still fails, hand off and say so in one
|
|
148
|
+
clause.
|
|
149
|
+
|
|
150
|
+
Checks 02, 03 and 06 are also computed by \`canvas_validate\`, so on a text-only model run
|
|
151
|
+
the gate on 01, 04 and 05 — they need judgement, not eyes.
|
|
152
|
+
|
|
153
|
+
⚠️ **Do not report the gate to the user.** The verdicts are working notes.
|
|
154
|
+
|
|
155
|
+
9. **One line, then offer two alternates as PICTURES.** Say what you made and point at the
|
|
156
|
+
Tweaks. Then use **\`propose_alternatives\`** with **two** further skins of the same
|
|
157
|
+
canvas — never a list of style names. The content is already fixed, so each variant
|
|
158
|
+
costs one \`canvas_write\` and the user picks by looking. This is the aesthetic menu,
|
|
159
|
+
moved to the only point where the choice is cheap for them and informative for you.
|
|
75
160
|
|
|
76
161
|
## Rules
|
|
77
162
|
- CALL THE TOOL — don't describe the HTML you "would" write and stop. A canvas only exists once the tool succeeds.
|
|
@@ -177,6 +262,18 @@ export const boardSkill = defineSkill({
|
|
|
177
262
|
## SHOW, don't TELL (the #1 rule)
|
|
178
263
|
A board is a VISUAL surface — its value is that it *depicts* things, not that it holds text. If your board is mostly paragraphs and bullet lists, you've built a text document on a grid and failed the medium. That is what the "propose alternatives" text tool is for — a board must EARN its place by being visual.
|
|
179
264
|
- **Depict, don't describe.** Exploring website / UI options? DRAW each option as a **wireframe mock** — a browser/window frame with a nav bar, a hero block, and content sections as labeled BOXES — laid side by side so they can be compared at a glance. Do NOT write "Option A: terminal-first hero, CLI-style product list…" as prose; SKETCH it.
|
|
265
|
+
- ⚠️ **LOW FIDELITY MEANS NO COLOUR, NO IMAGERY AND NO TYPE HIERARCHY. IT DOES NOT MEAN
|
|
266
|
+
NO CONTENT.** Grey bars where headings, prices and product names belong are a
|
|
267
|
+
placeholder for THINKING, and they make every layout look equally plausible because
|
|
268
|
+
none of them has to survive real copy. Boxes stay grey **for images only**. Every line
|
|
269
|
+
of text is written out: real nav items, real product names, real prices, a real
|
|
270
|
+
headline. A wireframe with placeholder text has not been designed yet — and the user
|
|
271
|
+
cannot react to it, which is the whole point of showing them one.
|
|
272
|
+
- ⚠️ **This is for COMPARING several options, at low fidelity.** For ONE screen at full
|
|
273
|
+
fidelity — "mock up the admissions dashboard" — use \`infographic\` with the
|
|
274
|
+
**app-screen** style instead (\`canvas_guide("styles")\`), and draw NO window chrome
|
|
275
|
+
there. The frame below earns its place only because several options sitting side by
|
|
276
|
+
side need something to separate them.
|
|
180
277
|
- **Architecture / flow?** Draw boxes-and-arrows (nodes + inline-SVG connectors), not a written description of the components.
|
|
181
278
|
- **Mind-map?** A central node with branches and sub-nodes, not an outline.
|
|
182
279
|
- Text belongs INSIDE the visual as short labels (titles, captions, a few key words) — never as the primary content of a node.
|
|
@@ -187,7 +284,7 @@ Build each screen mock as nested boxes so it reads as a *picture of a page*:
|
|
|
187
284
|
<div style="position:absolute;left:80px;top:120px;width:520px;background:var(--canvas-card);
|
|
188
285
|
border:1px solid var(--canvas-border);border-radius:8px;overflow:hidden">
|
|
189
286
|
<div style="height:28px;background:var(--canvas-bg);display:flex;align-items:center;gap:6px;padding:0 10px">
|
|
190
|
-
<span style="width:8px;height:8px;border-radius:50%;background:var(--canvas-muted)"></span> …
|
|
287
|
+
<span style="width:8px;height:8px;border-radius:50%;background:var(--canvas-muted)"></span> …dots that say "this is a window"…
|
|
191
288
|
</div>
|
|
192
289
|
<div style="height:44px;border-bottom:1px solid var(--canvas-border);display:flex;align-items:center;
|
|
193
290
|
justify-content:space-between;padding:0 16px"><b style="color:var(--canvas-fg)">logo</b><span style="color:var(--canvas-muted)">nav · nav · nav</span></div>
|
|
@@ -231,8 +328,8 @@ Give each mock a small title above it ("OPTION A — Terminal-first"). Two or th
|
|
|
231
328
|
// =============================================================================
|
|
232
329
|
export const canvasStylesSkill = defineSkill({
|
|
233
330
|
name: 'canvas-styles',
|
|
234
|
-
description: 'The visual STYLE CATALOGUE for canvases —
|
|
235
|
-
'glassmorphism, brutalist, editorial/print, retro/synthwave) each with a concrete, sandbox-safe, ' +
|
|
331
|
+
description: 'The visual STYLE CATALOGUE for canvases — seven named aesthetics (theme-flat, skeuomorphic, ' +
|
|
332
|
+
'glassmorphism, brutalist, editorial/print, retro/synthwave, app-screen) each with a concrete, sandbox-safe, ' +
|
|
236
333
|
'export-safe CSS recipe. Consult when picking or offering a look beyond the default theme-matched flat style.',
|
|
237
334
|
tags: ['visual', 'canvas', 'style', 'aesthetic', 'design'],
|
|
238
335
|
prompt: `The STYLE CATALOGUE for canvases — pick a coherent visual aesthetic instead of defaulting to the flat theme look. Design guidance; author with the canvas tools (see the \`canvas\` skill for mechanics). Applies to **infographic** and **carousel** (a board is a diagram surface — keep it theme-flat unless asked).
|
|
@@ -246,14 +343,59 @@ export const canvasStylesSkill = defineSkill({
|
|
|
246
343
|
- **EXPORT-SAFE background.** Always set an EXPLICIT background (never \`transparent\`) on the outer wrapper (and each \`<section data-sheet>\`). A look that leans on the page background breaks on the WHITE PDF export.
|
|
247
344
|
- **\`backdrop-filter\` is fragile.** It renders on screen and in \`canvas_screenshot\`, but PDF export MAY drop it — so for glass, give every panel a semi-opaque SOLID fallback fill too, so it still reads without the blur.
|
|
248
345
|
- **You MAY override the theme vars** for a committed aesthetic (declare your own palette in \`<style>\`), but keep text/background contrast strong. For "theme-matched", use \`var(--canvas-*)\` as-is. Either way, set the bg explicitly.
|
|
346
|
+
- ⚠️ **This licenses a PALETTE, not a free hand with hue.** Committing to an aesthetic
|
|
347
|
+
changes which colours you use; it does not raise the budget. One accent, three uses,
|
|
348
|
+
greys for everything else still applies — a canvas that answers the hue-count warning
|
|
349
|
+
with "the tile colours are deliberately varied" has used the permission to excuse the
|
|
350
|
+
exact thing the rule forbids. Colour encodes categories a reader must tell apart, or
|
|
351
|
+
it is decoration.
|
|
352
|
+
- ⚠️ **Check muted against the page GROUND, not the card.** A muted grey that passes on a
|
|
353
|
+
white card can fail on the ground two steps below it. Test every token against the
|
|
354
|
+
darkest surface it will actually sit on.
|
|
249
355
|
- Keep Tweaks working: still expose 2–4 bound controls (accent, a size slider, a toggle) even inside a strong style.
|
|
250
356
|
|
|
251
357
|
## The six styles
|
|
252
358
|
|
|
253
359
|
### 1. theme-flat — DEFAULT
|
|
254
360
|
Clean, modern, theme-driven. Reach for it for data, dashboards, and anything "serious/neutral".
|
|
255
|
-
|
|
256
|
-
|
|
361
|
+
|
|
362
|
+
⚠️ This recipe is LITERAL VALUES, not adjectives. "Generous whitespace" and "used
|
|
363
|
+
sparingly" are what the old entry said, and they produced a canvas that followed every
|
|
364
|
+
instruction and still looked machine-made. Read \`canvas_guide("exemplar-infographic")\`
|
|
365
|
+
for a worked example — it is worth more than everything below.
|
|
366
|
+
|
|
367
|
+
**Surfaces — three, never two.** Radius **0**, and **no shadows at all**: the ramp is the
|
|
368
|
+
depth.
|
|
369
|
+
- page ground \`var(--canvas-bg)\` · raised card \`var(--canvas-surface-1, var(--canvas-card))\` · inset (tables, code) \`var(--canvas-surface-2, var(--canvas-card))\`
|
|
370
|
+
- hairlines \`1px solid var(--canvas-hairline, var(--canvas-border))\`
|
|
371
|
+
- A card that shares its ground's value is a rectangle of text. If you ever find yourself
|
|
372
|
+
relying on the border to show where a card is, the ramp is missing.
|
|
373
|
+
|
|
374
|
+
**Type — one family, \`system-ui, -apple-system, "Segoe UI", Roboto, sans-serif\`.**
|
|
375
|
+
- hero figure **72–88px / 700 / -0.035em** · standfirst **20px / 600** · stat **34px / 700**
|
|
376
|
+
· body **14px / 1.65** · label **10–11px / 600 / 0.12em / uppercase**
|
|
377
|
+
- \`font-variant-numeric: tabular-nums\` on **every** figure, or columns of numbers jitter.
|
|
378
|
+
|
|
379
|
+
**Spacing — an 8px scale.** Gaps 16 · card padding 18–32 · outer padding 40.
|
|
380
|
+
|
|
381
|
+
**The canvas fills its frame.** The root takes \`width: 100%\` with an inner \`max-width\` for
|
|
382
|
+
the measure — never a fixed outer width. The viewer is not a fixed size, and a canvas that
|
|
383
|
+
leaves a dead strip down one side looks broken regardless of what is inside it.
|
|
384
|
+
|
|
385
|
+
**Grid — asymmetric tracks**, e.g. \`grid-template-columns: 1.35fr 1fr\`. Equal columns make
|
|
386
|
+
a canvas read as a form.
|
|
387
|
+
|
|
388
|
+
**Accent — three times maximum**, and they are: one kicker, one delta, one bar. Everything
|
|
389
|
+
else is greys.
|
|
390
|
+
|
|
391
|
+
**Dominance is geometric.** The hero figure is ~2.5x the next largest type, in a card ~1.35x
|
|
392
|
+
its neighbour. Bolder is not bigger.
|
|
393
|
+
|
|
394
|
+
**Two derived colours** the token set does not carry, and which get invented badly:
|
|
395
|
+
- body copy \`color-mix(in oklab, var(--canvas-fg) 78%, var(--canvas-bg))\`
|
|
396
|
+
- chart neutral \`color-mix(in oklab, var(--canvas-fg) 22%, var(--canvas-bg))\`
|
|
397
|
+
|
|
398
|
+
Both work in either polarity, so they need no host support.
|
|
257
399
|
|
|
258
400
|
### 2. skeuomorphic — tactile, physical
|
|
259
401
|
Soft, real-material surfaces — great for device/app-UI mockups and "premium product" one-pagers.
|
|
@@ -287,9 +429,54 @@ Hype/launch/gaming/music. Dark base, neon glow, chrome.
|
|
|
287
429
|
- Neon palette: hot pink \`#ff2bd6\`, cyan \`#22d3ee\`, violet \`#a855f7\`. Glow on headings/borders: \`text-shadow:0 0 8px currentColor,0 0 22px currentColor\` and \`box-shadow:0 0 12px #22d3ee,inset 0 0 12px rgba(34,211,238,.3)\`.
|
|
288
430
|
- Optional perspective grid at the bottom via repeating linear-gradients or an inline SVG. Chrome/gradient text with \`background:linear-gradient(#fff,#8ab4ff);-webkit-background-clip:text;color:transparent\`. (Glow via \`text-shadow\` exports fine.)
|
|
289
431
|
|
|
432
|
+
### 7. app-screen — a single UI screen
|
|
433
|
+
A mockup of one screen of an application. Read \`canvas_guide("exemplar-app-screen")\` before
|
|
434
|
+
drawing one.
|
|
435
|
+
|
|
436
|
+
⚠️ **Route a mockup here, not to \`board\`.** A single screen is one composition, so the
|
|
437
|
+
container is \`infographic\`; \`board\` teaches low-fidelity wireframe boxes for comparing
|
|
438
|
+
options side by side, which is not what anyone means by "mock up the dashboard".
|
|
439
|
+
|
|
440
|
+
**Four surfaces, in this order** — this is what makes a screen read as an application
|
|
441
|
+
rather than a document:
|
|
442
|
+
- chrome (rail, header) at \`surface-1\` · **the work canvas INSET at \`surface-2\`** ·
|
|
443
|
+
cards back up to \`surface-1\` on top of it · table headers at \`surface-2\`
|
|
444
|
+
|
|
445
|
+
**Exactly one active state**, and no hover states drawn at all. A static mock showing three
|
|
446
|
+
highlighted rows reads as a bug. The active row gets a 10% accent tint plus a 2px inset
|
|
447
|
+
accent edge; one filter chip gets the \`--canvas-fg\` border and the rest carry hairlines.
|
|
448
|
+
|
|
449
|
+
**One primary action, and it is INK, not accent** (\`background: var(--canvas-fg)\`). The
|
|
450
|
+
accent is reserved for the thing that needs attention. Two filled buttons side by side is
|
|
451
|
+
the commonest mock tell; the secondary is a hairline outline.
|
|
452
|
+
|
|
453
|
+
**State a finding, not a page name.** A real dashboard says "Overview" and stops; a MOCK
|
|
454
|
+
has to argue why the screen is worth building, so the largest text is a claim and the
|
|
455
|
+
accent marks its evidence. "Interviews are keeping pace. Document review is not." — not
|
|
456
|
+
"Admissions Dashboard".
|
|
457
|
+
|
|
458
|
+
**Numbers must reconcile.** 248 applied → 193 documents in → 152 reviewed → 67 interviewed,
|
|
459
|
+
and the listed programmes account for the 41 waiting. Figures that contradict each other
|
|
460
|
+
are what make a mock feel machine-made, more than any styling choice. If you were not given
|
|
461
|
+
real data, ask for it rather than inventing it.
|
|
462
|
+
|
|
463
|
+
**Do not draw the OS.** No traffic lights, no browser tab bar, no URL field, no dock. Window
|
|
464
|
+
chrome costs vertical space and dates the mock; the app's own header is the frame. Add it
|
|
465
|
+
only when the point being made is about the window itself.
|
|
466
|
+
|
|
467
|
+
Icons: use the set in \`canvas_guide("icons")\` — never an emoji, never a guessed path.
|
|
468
|
+
|
|
469
|
+
⚠️ **No icon is better than a wrong icon.** When the set has no shape for a concept, set
|
|
470
|
+
the label alone. A drinking glass on a Ceramics tile or an up-arrow on a Candles tile costs
|
|
471
|
+
more credibility than empty space would, and improvising an SVG path to fill the slot costs
|
|
472
|
+
more still. The set is for UI affordances — nav, actions, status. It is not illustration.
|
|
473
|
+
|
|
290
474
|
## Pick-by-content cheatsheet
|
|
475
|
+
- **One screen of an app / a UI mockup** → \`infographic\` + **app-screen**. Several options
|
|
476
|
+
compared side by side → \`board\` + wireframe. (Asking for "a mockup" used to route to one
|
|
477
|
+
of three types, none of which was right.)
|
|
291
478
|
- **Data / stats / dashboard / neutral** → theme-flat (or glass for a hero moment)
|
|
292
|
-
- **
|
|
479
|
+
- **A device or product SHOWCASE, not its screen** → skeuomorphic or glass
|
|
293
480
|
- **Manifesto / dev-tool / bold statement** → brutalist
|
|
294
481
|
- **Long-form / essay / report / "serious"** → editorial
|
|
295
482
|
- **Launch / hype / gaming / music / 80s** → retro
|