Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions mockups/canvases/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,28 @@ folder are invisible to it.
painted over five text classes without an error. `assets/art/` and
`assets/art-gen/` are committed; the eight `ref-*` boards are
gitignored, so a fresh clone has 13.
- `flashcard-onboarding/`: the run to read when the only source is a **screen
recording**. Four onboarding screens of a flashcard app, from a clip posted
on X, in 13 boards across three rows: a token board, three evidence boards
for 28 tokens, an art board for 7 crops, the four replicas, and the video
frame behind each one column-for-column underneath. Mean absolute delta is
6.17-7.05 levels (of 255), two to four times `duolingo-ios`', and the gap is
the medium: at 1.337 capture px per design pt a glyph is three pixels tall
through an H.264 encoder, so a sharp render scores an error the geometry
does not contain - the cropped hero art sits at 1.0-3.5 while the type zone
sits at 7.7-14.2 with every string inside 1.5pt of its reference box. Its
`README.md` carries the three findings that cost the most:
**`letter-spacing` inherits as a computed length**, so an `em` set on `body`
reaches a 36px title as body's own -0.4px and tracks it at a third of the
intent, which reads exactly like a display size that wants its own value;
the whole design is tracked at a single **-.025em**, proved by character
count rather than by width, which is also what told SF Pro from SF Pro
Rounded; and **LANCZOS undershoot** in the downscale step, which read as a
20-level ink-core error until the resample became an area average. It also
prices the one deliberate deviation - the source's phone frame is a mockup
asset, with a 118 x 4.5 home indicator at bottom 2.5 - at exactly 1.00 delta
per screen. `assets/art/` is committed; the four `ref-*` boards are
gitignored, so a fresh clone has 9.
- `spotify-ios/`: the run to read when the brand face is unavailable and the
screens are mostly type. Five screens of the Spotify iOS app - the home
feed at two scroll positions, two full-screen promo modals and the Spotify
Expand Down Expand Up @@ -339,6 +361,33 @@ folder are invisible to it.
is worthless on grey, and that a blur which monotonically improves a band is
hiding a content defect rather than an antialiasing one. The 25 `ref-*`
boards are gitignored, so a fresh clone has 29.
- `skillpath-ios/`: the run to read when the source is a **zooming** screen
recording, so there is no such thing as *the* capture scale. Five screens of
an unnamed gamified self-improvement app, from a clip posted on X, in 23
boards across three rows: six token boards and seven evidence boards for 73
tokens, the five replicas, and the video frame behind each one
column-for-column underneath. Those foundation boards are plural for a
reason worth borrowing: 73 rows is 4000px of table in a 980px artboard, and
`refkit shoot --check-overflow` only says so when you leave `--crop-phone`
off, and never says so at all about a table running off the *side*. Mean
absolute delta is 5.88-9.04 levels (of 255). Its `README.md` records the
three things that decided those numbers. **The device is 402 x 874, not the
393 x 852 the rest of this repo uses** - an iPhone 17 Pro - and it was found
by scale agreement, where solving each frame's screen-inner rect against 402
x 874 makes its width and height scales agree to 0.07% against 0.34% for the
smaller frame. **The clip zooms, so every frame carries its own px-per-pt**
(1.01194 to 1.07985) and every one of the 59 rows in `probes.json` carries
its own `"pt"`, which is what `refkit batch` needs to replay them all in one
pass. And **the renderer's cap metrics are not the face's**: a probe of
eight font stacks came back byte-identical, so the boards are set in the
platform fallback, whose cap is 0.733 em and sits 0.350 x font-size below
the line box rather than SF Pro's 0.245 - inverting the nominal relation
instead of the measured one put every run on the board low by 3.3pt at
31.5px and cost 1.50 delta on the busiest screen. All 20 type sizes are
fitted on ink width against a named probe rather than on cap height, which a
video frame inflates by 1-2pt; `CURRENT STREAK` read as 14px that way and
set 18% wide. `assets/art/` is committed for its 17 crops; the five `ref-*`
boards are gitignored, so a fresh clone has 18.
- `templates/`: the starting point, not a finished board. The four boards
every run produces (design tokens, evidence, one phone screen, one parked
reference) with placeholder values, generated from one list of tokens so
Expand Down
102 changes: 102 additions & 0 deletions mockups/canvases/flashcard-onboarding/00-design-tokens.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flashcard Onboarding - Design Tokens</title>
<style>
:root{
/* Font */
--f-font:system-ui,-apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
--f-tracking:-.025em;

/* Surface */
--f-bg:#FFFFFF;
--f-card:#FDFAF4;
--f-track:#F4F4F4;
--f-pill-off:#C1C1C1;

/* Line */
--f-hairline:#EFEFEF;

/* Ink */
--f-ink:#000000;
--f-ink-mid:#3A3A3A;
--f-ink-2:#7E7E7E;
--f-ink-inv:#FFFFFF;

/* Accent */
--f-accent:#F39D05;

/* Fill */
--f-pill-dark:linear-gradient(180deg,#8A8A8A 0,#3C3C3C 6.8px,#141414 15.7px,#0F0F0F 30px,#090909 41px,#040404 100%);
--f-pill-grey:linear-gradient(180deg,#DADADA 0,#D2D2D2 4.5px,#C4C4C4 9.8px,#C1C1C1 30px,#C1C1C1 100%);
--f-btn-dark:linear-gradient(180deg,#8A8A8A 0,#3C3C3C 5px,#000000 12px,#000000 100%);

/* Radius */
--f-r-pill:999px;
--f-r-phone:52px;

/* Type */
--f-t-eyebrow:600 15px/18px var(--f-font);
--f-t-title:700 36px/42.3px var(--f-font);
--f-t-sub:400 15px/18.7px var(--f-font);
--f-t-btn:600 20px/24px var(--f-font);
--f-t-legal:400 13px/17.2px var(--f-font);
--f-t-time:590 17px/22px var(--f-font);

/* Metrics */
--f-w:393px;
--f-h:852px;
--f-status:54px;
--f-nav-y:768.7px;
--f-nav-h:56.8px;
}

*{box-sizing:border-box;margin:0;padding:0}
body{font-family:var(--f-font);-webkit-font-smoothing:antialiased;
display:flex;justify-content:center;padding:24px}
.phone{position:relative;flex:none;width:var(--f-w);height:var(--f-h);
border-radius:var(--f-r-phone);overflow:hidden;background:var(--f-bg);color:var(--f-ink);transform:translateZ(0);
box-shadow:0 0 0 11px #1D191A,0 0 0 12.5px #3A3735,0 24px 60px rgba(29,25,26,.28)}
.sb{position:absolute;left:0;top:0;width:var(--f-w);height:var(--f-status);z-index:6}
.sb .time{position:absolute;left:0;top:18.2px;width:142.4px;text-align:center;
font:var(--f-t-time)}
.sb svg{position:absolute;display:block;fill:currentColor}
.sb .island{position:absolute;top:11px;left:50%;transform:translateX(-50%);
width:125px;height:36px;border-radius:20px;background:#000}
.home{position:absolute;left:50%;bottom:8px;transform:translateX(-50%);
width:139px;height:5px;border-radius:3px;background:currentColor;z-index:6}
img.a{position:absolute;display:block}
body{padding:0;background:var(--f-bg);color:var(--f-ink)}
.sheet{width:478px;height:980px;padding:20px;overflow:hidden}
h1{font:600 17px/22px var(--f-font);margin-bottom:2px}
header p{font:400 11px/15px var(--f-font);color:var(--f-ink-2);margin-bottom:14px}
h2{font:600 9px/12px var(--f-font);letter-spacing:.8px;text-transform:uppercase;
color:var(--f-ink-2);margin:12px 0 5px}
.grid{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.sw .chip{height:26px;border-radius:6px;border:1px solid var(--f-hairline)}
.sw b{display:block;margin-top:3px;font:600 8.5px/11px ui-monospace,Menlo,monospace}
.sw i{display:block;font:400 8px/11px ui-monospace,Menlo,monospace;
color:var(--f-ink-2);font-style:normal;word-break:break-all}
.rad{display:flex;gap:9px}
.rb{width:44px;height:26px;background:var(--f-card);border:1px solid var(--f-hairline)}
.rad em{display:block;margin-top:2px;font:400 8.5px/11px var(--f-font);
color:var(--f-ink-2);font-style:normal;text-align:center}
.tr{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
padding-bottom:2px;border-bottom:1px solid var(--f-hairline)}
.tr span{white-space:nowrap;overflow:hidden}
.tr em{font:400 8px/11px ui-monospace,Menlo,monospace;color:var(--f-ink-2);
font-style:normal;white-space:nowrap;flex:none}
.met{font:400 9px/13px ui-monospace,Menlo,monospace;color:var(--f-ink-2)}
table.ev{width:100%;border-collapse:collapse}
table.ev td{vertical-align:top;padding:2.5px 6px 2.5px 0;
border-bottom:1px solid var(--f-hairline);font:400 8.5px/11px var(--f-font)}
td.t,td.v{font-family:ui-monospace,Menlo,monospace}
td.t{color:var(--f-accent);white-space:nowrap}
td.v{color:var(--f-ink-mid);max-width:132px;word-break:break-all}
td.e{color:var(--f-ink-2)}</style>
</head>
<body>
<div class="sheet"><header><h1>Flashcard Onboarding</h1><p>Four onboarding screens, measured off a 1080 &times; 1350 video at 1.337 capture px per design pt. Every value below is a measurement; the row that justifies it is on 00b, and the probe that produced it is in <code>probes.json</code>.</p></header><h2>Colour</h2><div class="grid"><div class="sw"><div class="chip" style="background:var(--f-bg)"></div><b>--f-bg</b><i>#FFFFFF</i></div><div class="sw"><div class="chip" style="background:var(--f-card)"></div><b>--f-card</b><i>#FDFAF4</i></div><div class="sw"><div class="chip" style="background:var(--f-track)"></div><b>--f-track</b><i>#F4F4F4</i></div><div class="sw"><div class="chip" style="background:var(--f-pill-off)"></div><b>--f-pill-off</b><i>#C1C1C1</i></div><div class="sw"><div class="chip" style="background:var(--f-hairline)"></div><b>--f-hairline</b><i>#EFEFEF</i></div><div class="sw"><div class="chip" style="background:var(--f-ink)"></div><b>--f-ink</b><i>#000000</i></div><div class="sw"><div class="chip" style="background:var(--f-ink-mid)"></div><b>--f-ink-mid</b><i>#3A3A3A</i></div><div class="sw"><div class="chip" style="background:var(--f-ink-2)"></div><b>--f-ink-2</b><i>#7E7E7E</i></div><div class="sw"><div class="chip" style="background:var(--f-ink-inv)"></div><b>--f-ink-inv</b><i>#FFFFFF</i></div><div class="sw"><div class="chip" style="background:var(--f-accent)"></div><b>--f-accent</b><i>#F39D05</i></div><div class="sw"><div class="chip" style="background:var(--f-pill-dark)"></div><b>--f-pill-dark</b><i>linear-gradient(180deg,#8A8A8A 0,#3C3C3C 6.8px,#141414 15.7px,#0F0F0F 30px,#090909 41px,#040404 100%)</i></div><div class="sw"><div class="chip" style="background:var(--f-pill-grey)"></div><b>--f-pill-grey</b><i>linear-gradient(180deg,#DADADA 0,#D2D2D2 4.5px,#C4C4C4 9.8px,#C1C1C1 30px,#C1C1C1 100%)</i></div><div class="sw"><div class="chip" style="background:var(--f-btn-dark)"></div><b>--f-btn-dark</b><i>linear-gradient(180deg,#8A8A8A 0,#3C3C3C 5px,#000000 12px,#000000 100%)</i></div></div><h2>Radius</h2><div class="rad"><div><div class="rb" style="border-radius:999px"></div><em>999px</em></div></div><h2>Type</h2><div class="tr"><span style="font:var(--f-t-eyebrow)">Grumpy wizards</span><em>--f-t-eyebrow &middot; 600 15px/18px</em></div><div class="tr"><span style="font:var(--f-t-title)">Grumpy wizards</span><em>--f-t-title &middot; 700 36px/42.3px</em></div><div class="tr"><span style="font:var(--f-t-sub)">Grumpy wizards</span><em>--f-t-sub &middot; 400 15px/18.7px</em></div><div class="tr"><span style="font:var(--f-t-btn)">Grumpy wizards</span><em>--f-t-btn &middot; 600 20px/24px</em></div><div class="tr"><span style="font:var(--f-t-legal)">Grumpy wizards</span><em>--f-t-legal &middot; 400 13px/17.2px</em></div><div class="tr"><span style="font:var(--f-t-time)">Grumpy wizards</span><em>--f-t-time &middot; 590 17px/22px</em></div><h2>Metrics</h2><div class="met">--f-w: 393px<br>--f-h: 852px<br>--f-status: 54px<br>--f-nav-y: 768.7px<br>--f-nav-h: 56.8px</div></div>
</body>
</html>
102 changes: 102 additions & 0 deletions mockups/canvases/flashcard-onboarding/00b-evidence.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flashcard Onboarding - Evidence 1/3</title>
<style>
:root{
/* Font */
--f-font:system-ui,-apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
--f-tracking:-.025em;

/* Surface */
--f-bg:#FFFFFF;
--f-card:#FDFAF4;
--f-track:#F4F4F4;
--f-pill-off:#C1C1C1;

/* Line */
--f-hairline:#EFEFEF;

/* Ink */
--f-ink:#000000;
--f-ink-mid:#3A3A3A;
--f-ink-2:#7E7E7E;
--f-ink-inv:#FFFFFF;

/* Accent */
--f-accent:#F39D05;

/* Fill */
--f-pill-dark:linear-gradient(180deg,#8A8A8A 0,#3C3C3C 6.8px,#141414 15.7px,#0F0F0F 30px,#090909 41px,#040404 100%);
--f-pill-grey:linear-gradient(180deg,#DADADA 0,#D2D2D2 4.5px,#C4C4C4 9.8px,#C1C1C1 30px,#C1C1C1 100%);
--f-btn-dark:linear-gradient(180deg,#8A8A8A 0,#3C3C3C 5px,#000000 12px,#000000 100%);

/* Radius */
--f-r-pill:999px;
--f-r-phone:52px;

/* Type */
--f-t-eyebrow:600 15px/18px var(--f-font);
--f-t-title:700 36px/42.3px var(--f-font);
--f-t-sub:400 15px/18.7px var(--f-font);
--f-t-btn:600 20px/24px var(--f-font);
--f-t-legal:400 13px/17.2px var(--f-font);
--f-t-time:590 17px/22px var(--f-font);

/* Metrics */
--f-w:393px;
--f-h:852px;
--f-status:54px;
--f-nav-y:768.7px;
--f-nav-h:56.8px;
}

*{box-sizing:border-box;margin:0;padding:0}
body{font-family:var(--f-font);-webkit-font-smoothing:antialiased;
display:flex;justify-content:center;padding:24px}
.phone{position:relative;flex:none;width:var(--f-w);height:var(--f-h);
border-radius:var(--f-r-phone);overflow:hidden;background:var(--f-bg);color:var(--f-ink);transform:translateZ(0);
box-shadow:0 0 0 11px #1D191A,0 0 0 12.5px #3A3735,0 24px 60px rgba(29,25,26,.28)}
.sb{position:absolute;left:0;top:0;width:var(--f-w);height:var(--f-status);z-index:6}
.sb .time{position:absolute;left:0;top:18.2px;width:142.4px;text-align:center;
font:var(--f-t-time)}
.sb svg{position:absolute;display:block;fill:currentColor}
.sb .island{position:absolute;top:11px;left:50%;transform:translateX(-50%);
width:125px;height:36px;border-radius:20px;background:#000}
.home{position:absolute;left:50%;bottom:8px;transform:translateX(-50%);
width:139px;height:5px;border-radius:3px;background:currentColor;z-index:6}
img.a{position:absolute;display:block}
body{padding:0;background:var(--f-bg);color:var(--f-ink)}
.sheet{width:478px;height:980px;padding:20px;overflow:hidden}
h1{font:600 17px/22px var(--f-font);margin-bottom:2px}
header p{font:400 11px/15px var(--f-font);color:var(--f-ink-2);margin-bottom:14px}
h2{font:600 9px/12px var(--f-font);letter-spacing:.8px;text-transform:uppercase;
color:var(--f-ink-2);margin:12px 0 5px}
.grid{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.sw .chip{height:26px;border-radius:6px;border:1px solid var(--f-hairline)}
.sw b{display:block;margin-top:3px;font:600 8.5px/11px ui-monospace,Menlo,monospace}
.sw i{display:block;font:400 8px/11px ui-monospace,Menlo,monospace;
color:var(--f-ink-2);font-style:normal;word-break:break-all}
.rad{display:flex;gap:9px}
.rb{width:44px;height:26px;background:var(--f-card);border:1px solid var(--f-hairline)}
.rad em{display:block;margin-top:2px;font:400 8.5px/11px var(--f-font);
color:var(--f-ink-2);font-style:normal;text-align:center}
.tr{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
padding-bottom:2px;border-bottom:1px solid var(--f-hairline)}
.tr span{white-space:nowrap;overflow:hidden}
.tr em{font:400 8px/11px ui-monospace,Menlo,monospace;color:var(--f-ink-2);
font-style:normal;white-space:nowrap;flex:none}
.met{font:400 9px/13px ui-monospace,Menlo,monospace;color:var(--f-ink-2)}
table.ev{width:100%;border-collapse:collapse}
table.ev td{vertical-align:top;padding:2.5px 6px 2.5px 0;
border-bottom:1px solid var(--f-hairline);font:400 8.5px/11px var(--f-font)}
td.t,td.v{font-family:ui-monospace,Menlo,monospace}
td.t{color:var(--f-accent);white-space:nowrap}
td.v{color:var(--f-ink-mid);max-width:132px;word-break:break-all}
td.e{color:var(--f-ink-2)}</style>
</head>
<body>
<div class="sheet"><header><h1>Evidence 1/3</h1><p>One row per token. A token with no evidence is a guess.</p></header><table class="ev"><tr><td class="t">--f-font</td><td class="v">system-ui,-apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif</td><td class="e">SF Pro, not Rounded: the terminals on 'Create Account' are cut, not round, at 3x. Four measured strings run 3.3-5.2% narrower than system-ui, a 1.9-point spread that --f-tracking absorbs, against 2.5-7.1% and a 4.6-point spread for SF Pro Rounded</td></tr><tr><td class="t">--f-tracking</td><td class="v">-.025em</td><td class="e">every string is narrower than its untracked setting by an amount that scales with character count, not with width: 5.0px over 13 gaps on the eyebrow and 12.8 over 35 on the subtitle, ratio .391 against .371 predicted by tracking and .533 by a narrower face. The four strings solve to -.0257, -.0244, -.0248 and -.0266em across 15px and 36px, so one figure covers the whole ramp. It has to be set on each rule: letter-spacing inherits as a computed length, so an em on body reaches a 36px title as body's own -.4px and tracks it at a third of the intent</td></tr><tr><td class="t">--f-bg</td><td class="v">#FFFFFF</td><td class="e">flat census on c4 y700-760 is 100% #FDFDFD, but 2801 px elsewhere hit 255: the 2-level floor is H.264 flat-field quantization, not an off-white</td></tr><tr><td class="t">--f-card</td><td class="v">#FDFAF4</td><td class="e">flat run c4 row 185, x 97.4..285.9 -- the warm panel behind the trophy</td></tr><tr><td class="t">--f-track</td><td class="v">#F4F4F4</td><td class="e">flat run c1 col 120, y 770.2..787.4 and 800.9..824.8 -- the nav track</td></tr><tr><td class="t">--f-pill-off</td><td class="v">#C1C1C1</td><td class="e">flat census inside the disabled back pill, 50.6% of 3221 flat px</td></tr><tr><td class="t">--f-hairline</td><td class="v">#EFEFEF</td><td class="e">Login outline: c4 row 651 x 364.0..365.5, c4 col 40 y 623.3..625.5</td></tr><tr><td class="t">--f-ink</td><td class="v">#000000</td><td class="e">ink core (darkest 2%) of the eyebrow, both title lines and the legal bold</td></tr><tr><td class="t">--f-ink-mid</td><td class="v">#3A3A3A</td><td class="e">ink core of the Login label, c4</td></tr><tr><td class="t">--f-ink-2</td><td class="v">#7E7E7E</td><td class="e">subtitle ink core #7D7D7D on c1 and c4, legal-line grey #7F7F7F; one token at the midpoint</td></tr></table></div>
</body>
</html>
Loading