Skip to main content

max / makenotwork

Put real screenshots in the landing carousel Three captures of testnot.work from one run of the capture script, replacing the placeholder SVGs. The storefront shows a shop and its cover art, the item page an $8 price and a buy button, the library nine purchases with their license keys and open buttons: the three things the captions claim. Alt text now describes what is in each frame rather than what the page it came from contains. Frame 1's crop holds the shop and the artwork and stops above the prices, so it no longer claims them. WebP, not PNG. At 2x and 2560px wide the item frame was 3.8 MB as a PNG and is 599 KB here; all three together are under 2 MB. Chrome encodes it during the capture, so this costs no build step and no second tool.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-08 00:27 UTC
Signed with PGP, not checked
Commit: 90083e33579daf8f763c326f358287979e3d4f48
Parent: a8b3b74
8 files changed, +32 insertions, -70 deletions
@@ -68,6 +68,14 @@
68 68 const CROP_WIDTH = Number(process.env.CAPTURE_WIDTH ?? 1280);
69 69 const SETTLE_MS = 1200; // after load + fonts, for lazy images and islands
70 70
71 + // Output format. These are 2x captures 2560px wide, and as PNG the item frame
72 + // weighed 3.8 MB, which is not a thing to put on a landing page that is trying
73 + // to look fast. WebP at 90 carries the same crop at a fraction of that and is
74 + // supported everywhere the site is. Chrome encodes it, so there is no build
75 + // step and no second tool. CAPTURE_FORMAT=png restores the old behaviour.
76 + const FORMAT = process.env.CAPTURE_FORMAT ?? 'webp';
77 + const QUALITY = Number(process.env.CAPTURE_QUALITY ?? 90);
78 +
71 79 // The element each frame is cropped to, unless the frame names its own.
72 80 // `.container` is the outer content wrapper on all three pages, so the three
73 81 // crops share their left/right margins.
@@ -101,7 +109,7 @@
101 109 {
102 110 name: 'storefront',
103 111 path: STOREFRONT,
104 - alt: "A creator's storefront showing their listed items with prices and cover art",
112 + alt: "A creator's storefront on Makenotwork, titled and described, above a row of their work in cover art",
105 113 needsAuth: false,
106 114 },
107 115 {
@@ -133,13 +141,13 @@
133 141 return result.value;
134 142 },
135 143 from: STOREFRONT,
136 - alt: 'An item page with its price, buy button, and download details',
144 + alt: 'An item page showing its cover art, an $8 price, and a buy button, beside what the purchase includes',
137 145 needsAuth: false,
138 146 },
139 147 {
140 148 name: 'library',
141 149 path: '/library',
142 - alt: 'A buyer library listing the files they have purchased, ready to download',
150 + alt: 'A buyer library listing what they have bought, each row with its creator, type, purchase date and a button to open it',
143 151 needsAuth: true,
144 152 },
145 153 ];
@@ -462,12 +470,14 @@
462 470
463 471 const clip = { ...clipFor(result.value), scale: SCALE };
464 472 const shot = await call('Page.captureScreenshot', {
465 - format: 'png',
473 + format: FORMAT,
474 + // PNG ignores quality; WebP and JPEG do not.
475 + ...(FORMAT === 'png' ? {} : { quality: QUALITY }),
466 476 clip,
467 477 captureBeyondViewport: true,
468 478 fromSurface: true,
469 479 });
470 - const file = path.join(OUT_DIR, `${frame.name}.png`);
480 + const file = path.join(OUT_DIR, `${frame.name}.${FORMAT}`);
471 481 const bytes = Buffer.from(shot.data, 'base64');
472 482 await writeFile(file, bytes);
473 483 console.error(
@@ -496,7 +506,7 @@
496 506 }
497 507
498 508 console.error(`\nAll ${FRAMES.length} frames captured from ${BASE}.`);
499 - console.error('Next: review them (GoingsOn 7f3da540), then point landing.rs at the .png files');
509 + console.error(`Next: review them (GoingsOn 7f3da540), then point landing.rs at the .${FORMAT} files`);
500 510 console.error('and delete static/images/shots/placeholder-*.svg.');
501 511 }
502 512
@@ -108,24 +108,30 @@
108 108 None
109 109 };
110 110
111 - // Placeholder carousel frames. Swap the images for real captures and
112 - // tighten the alt text when the screenshots exist (launch plan ยง S).
113 - // The alt text below is written as real descriptions, not "image of
114 - // a screenshot", to model the bar CarouselFrame::new nudges toward.
111 + // Real captures of testnot.work, all three from one run of
112 + // scripts/capture-landing-carousel.mjs. Re-shoot with that script
113 + // rather than by hand: the three agree on viewport, scale, crop and
114 + // aspect by construction, and shooting one of them alone is what
115 + // makes a carousel look wrong.
116 + //
117 + // The alt text describes what is actually in each frame, not what
118 + // the page it came from contains. Frame 1's crop holds the shop and
119 + // its cover art; the prices sit below the fold, so it does not claim
120 + // them.
115 121 let landing_carousel = vec![
116 122 CarouselFrame::new(
117 - "/static/images/shots/placeholder-storefront.svg",
118 - "A creator's storefront on Makenotwork showing their listed items with prices and cover art",
123 + "/static/images/shots/storefront.webp",
124 + "A creator's storefront on Makenotwork, titled and described, above a row of their work in cover art",
119 125 )
120 126 .with_caption("Your storefront: sell anything digital"),
121 127 CarouselFrame::new(
122 - "/static/images/shots/placeholder-item.svg",
123 - "An item page with its price, buy button, and download details",
128 + "/static/images/shots/item.webp",
129 + "An item page showing its cover art, an $8 price, and a buy button, beside what the purchase includes",
124 130 )
125 131 .with_caption("Every sale is yours. 0% platform fee"),
126 132 CarouselFrame::new(
127 - "/static/images/shots/placeholder-library.svg",
128 - "A buyer's library listing the files they have purchased, ready to download",
133 + "/static/images/shots/library.webp",
134 + "A buyer's library listing what they have bought, each row with its creator, type, purchase date and a button to open it",
129 135 )
130 136 .with_caption("Buyers keep what they bought. One-click export"),
131 137 ];
Binary file
Binary file
@@ -1,18 +1,0 @@
1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 800" role="img" aria-label="Placeholder">
2 - <rect width="1280" height="800" fill="#f4f0eb"/>
3 - <rect x="0" y="0" width="1280" height="56" fill="#ede8e1"/>
4 - <circle cx="32" cy="28" r="7" fill="#d0cbb8"/>
5 - <circle cx="56" cy="28" r="7" fill="#d0cbb8"/>
6 - <circle cx="80" cy="28" r="7" fill="#d0cbb8"/>
7 - <rect x="120" y="16" width="900" height="24" rx="6" fill="#e2dad2"/>
8 - <rect x="40" y="120" width="1200" height="600" rx="10" fill="#ede8e1" stroke="#d0cbb8" stroke-width="2"/>
9 - <rect x="80" y="170" width="220" height="500" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
10 - <rect x="340" y="170" width="860" height="64" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
11 - <rect x="340" y="258" width="860" height="120" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
12 - <rect x="340" y="402" width="860" height="120" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
13 - <rect x="340" y="546" width="860" height="120" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
14 - <rect x="540" y="350" width="200" height="44" rx="22" fill="#6c5ce7"/>
15 - <text x="640" y="380" font-family="IBM Plex Mono, monospace" font-size="20" fill="#ffffff" text-anchor="middle">PLACEHOLDER</text>
16 - <text x="640" y="436" font-family="Young Serif, Georgia, serif" font-size="40" fill="#3d3530" text-anchor="middle">Item page</text>
17 - <text x="640" y="478" font-family="Lato, sans-serif" font-size="22" fill="#8a8480" text-anchor="middle">Real screenshot goes here</text>
18 - </svg>
@@ -1,18 +1,0 @@
1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 800" role="img" aria-label="Placeholder">
2 - <rect width="1280" height="800" fill="#f4f0eb"/>
3 - <rect x="0" y="0" width="1280" height="56" fill="#ede8e1"/>
4 - <circle cx="32" cy="28" r="7" fill="#d0cbb8"/>
5 - <circle cx="56" cy="28" r="7" fill="#d0cbb8"/>
6 - <circle cx="80" cy="28" r="7" fill="#d0cbb8"/>
7 - <rect x="120" y="16" width="900" height="24" rx="6" fill="#e2dad2"/>
8 - <rect x="40" y="120" width="1200" height="600" rx="10" fill="#ede8e1" stroke="#d0cbb8" stroke-width="2"/>
9 - <rect x="80" y="170" width="220" height="500" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
10 - <rect x="340" y="170" width="860" height="64" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
11 - <rect x="340" y="258" width="860" height="120" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
12 - <rect x="340" y="402" width="860" height="120" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
13 - <rect x="340" y="546" width="860" height="120" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
14 - <rect x="540" y="350" width="200" height="44" rx="22" fill="#6c5ce7"/>
15 - <text x="640" y="380" font-family="IBM Plex Mono, monospace" font-size="20" fill="#ffffff" text-anchor="middle">PLACEHOLDER</text>
16 - <text x="640" y="436" font-family="Young Serif, Georgia, serif" font-size="40" fill="#3d3530" text-anchor="middle">Buyer library</text>
17 - <text x="640" y="478" font-family="Lato, sans-serif" font-size="22" fill="#8a8480" text-anchor="middle">Real screenshot goes here</text>
18 - </svg>
@@ -1,18 +1,0 @@
1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 800" role="img" aria-label="Placeholder">
2 - <rect width="1280" height="800" fill="#f4f0eb"/>
3 - <rect x="0" y="0" width="1280" height="56" fill="#ede8e1"/>
4 - <circle cx="32" cy="28" r="7" fill="#d0cbb8"/>
5 - <circle cx="56" cy="28" r="7" fill="#d0cbb8"/>
6 - <circle cx="80" cy="28" r="7" fill="#d0cbb8"/>
7 - <rect x="120" y="16" width="900" height="24" rx="6" fill="#e2dad2"/>
8 - <rect x="40" y="120" width="1200" height="600" rx="10" fill="#ede8e1" stroke="#d0cbb8" stroke-width="2"/>
9 - <rect x="80" y="170" width="220" height="500" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
10 - <rect x="340" y="170" width="860" height="64" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
11 - <rect x="340" y="258" width="860" height="120" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
12 - <rect x="340" y="402" width="860" height="120" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
13 - <rect x="340" y="546" width="860" height="120" rx="8" fill="#f4f0eb" stroke="#d0cbb8" stroke-width="2"/>
14 - <rect x="540" y="350" width="200" height="44" rx="22" fill="#6c5ce7"/>
15 - <text x="640" y="380" font-family="IBM Plex Mono, monospace" font-size="20" fill="#ffffff" text-anchor="middle">PLACEHOLDER</text>
16 - <text x="640" y="436" font-family="Young Serif, Georgia, serif" font-size="40" fill="#3d3530" text-anchor="middle">Storefront</text>
17 - <text x="640" y="478" font-family="Lato, sans-serif" font-size="22" fill="#8a8480" text-anchor="middle">Real screenshot goes here</text>
18 - </svg>
Binary file