Nº 542 of 543
Taped photo grid
Eight photo pages in a four-column grid on a kraft board, each tilted up to 3° and held by a tape strip or a red pin, with a Caveat caption and a date; hover straightens a page and lifts it 6px.
Preview
Use it
Free to use · credit appreciated1 Once, in your project · Node 22.20+
npx skills add SusanAcharya/Design-Lounge 2 Then ask
Using the Design Lounge skill, build "Taped photo grid" (piece taped-photo-grid) in my stack. Match its brief; restyle it onto my product's theme.
No skill? Paste the brief instead. It carries the numbers, tokens and behaviour.
<!-- Design Lounge Nº 542 · "Taped photo grid" · www.designlounge.live -->
# Taped photo grid
> **Build brief for a coding agent.** Rebuild this piece in the reader's stack. If they haven't said which stack, ask once, then default to semantic HTML + CSS + a little vanilla JS. Match the numbers below; don't "improve" them. The hand face is for captions and the one note; the heading's kicker, the sentence and the dates stay in the sans.
## What it is
A month of pages from Paste, a fictional scrapbook printer, laid out as a four-by-two grid on a kraft board. Each page is a white card with a 10px paper margin and a 40px caption strip: a drawn picture at 4:3, a Caveat caption and a small sans date. Pages are rotated between -3° and 3° from a per-card custom property, and each is held down by either a translucent tape strip at a corner or along the top, or a red push pin. One carries a tilted red "Reprint" stamp. Hovering or focusing a page straightens it to 0° and lifts it 6px over 320ms, so the grid reads as physical without ever moving more than a few pixels. A blue handwritten note with an arrow sits at the bottom left, under the grid, where it covers nothing. The detail worth copying is the per-card `--rot` variable: the grid stays a real CSS grid with real links, and the scrapbook look is one line of CSS per card.
## Reference behaviour
1. First frame: "PASTE · BOOK 3 / May, taped in" (Caveat 48px), a sentence at the right, eight pages: The lake at seven (12 May), Tej's first ticket (19 May), The good plate (26 May, pinned), Walk to the stupa (3 May, stamped Reprint), Rain, from the bus (8 May), Two mangoes (15 May, pinned), The ridge, 05:40 (22 May), Home, finally (31 May). The note: "order a reprint of any of these".
2. Hover or focus a page: it rotates to 0°, rises 6px and comes to the front, over 320ms expo-out. Leave: it returns to its tilt.
3. Click a page: it is a link to the page's own view (here `#`).
4. Nothing animates on load. Reduced motion: no straightening; focus still shows the ring.
## Structure
```
1280 × 800, board #C9A97C with a 5px dot grain
wrap max 1200, padding 34/40
PASTE · BOOK 3 Eight of the thirty-one pages. Hover a photo…
May, taped in 48 Caveat
grid 4 × 1fr, gap 34 / 28, padding-top 10
┌ page -3° ─┐ ┌ page 2° ──┐ ┌ page -1° ─┐ ┌ page 3° ──┐
│ \ tape │ │ ═ tape ═ │ │ ● pin │ │ tape / [REPRINT] │
│ picture │ │ picture │ │ picture │ │ picture │
│ caption · date (strip 40) │
└───────────┘ └───────────┘ └───────────┘ └───────────┘
┌ page 2° ──┐ ┌ page -2° ─┐ ┌ page 1° ──┐ ┌ page -3° ─┐
│ … │ │ ● pin │ │ ═ tape ═ │ │ tape / │
↗ order a reprint of any of these (Caveat 26, blue, bottom left, below the grid)
```
- `main.wrap` → `div.head` (`h1` with a `small` kicker, `p`), `div.grid`, `span.note[aria-hidden]`.
- Each page is `a.photo[style="--rot:…"]` (add `.pin` for a pinned one) → optional `span.tape.a|b|c[aria-hidden]`, optional `span.stamp[aria-hidden]`, `figure` → `span.img[aria-hidden]` with an inline SVG, `figcaption` with a `small` date.
## Tokens
… 117 more lines. Copy or download for the full brief. Loading the source…Brief
157 linesBuild brief for a coding agent. Rebuild this piece in the reader’s stack. If they haven’t said which stack, ask once, then default to semantic HTML + CSS + a little vanilla JS. Match the numbers below; don’t “improve” them. The hand face is for captions and the one note; the heading’s kicker, the sentence and the dates stay in the sans.
What it is
A month of pages from Paste, a fictional scrapbook printer, laid out as a four-by-two grid on a kraft board. Each page is a white card with a 10px paper margin and a 40px caption strip: a drawn picture at 4:3, a Caveat caption and a small sans date. Pages are rotated between -3° and 3° from a per-card custom property, and each is held down by either a translucent tape strip at a corner or along the top, or a red push pin. One carries a tilted red “Reprint” stamp. Hovering or focusing a page straightens it to 0° and lifts it 6px over 320ms, so the grid reads as physical without ever moving more than a few pixels. A blue handwritten note with an arrow sits at the bottom left, under the grid, where it covers nothing. The detail worth copying is the per-card --rot variable: the grid stays a real CSS grid with real links, and the scrapbook look is one line of CSS per card.
Reference behaviour
- First frame: “PASTE · BOOK 3 / May, taped in” (Caveat 48px), a sentence at the right, eight pages: The lake at seven (12 May), Tej’s first ticket (19 May), The good plate (26 May, pinned), Walk to the stupa (3 May, stamped Reprint), Rain, from the bus (8 May), Two mangoes (15 May, pinned), The ridge, 05:40 (22 May), Home, finally (31 May). The note: “order a reprint of any of these”.
- Hover or focus a page: it rotates to 0°, rises 6px and comes to the front, over 320ms expo-out. Leave: it returns to its tilt.
- Click a page: it is a link to the page’s own view (here
#). - Nothing animates on load. Reduced motion: no straightening; focus still shows the ring.
Structure
1280 × 800, board #C9A97C with a 5px dot grain
wrap max 1200, padding 34/40
PASTE · BOOK 3 Eight of the thirty-one pages. Hover a photo…
May, taped in 48 Caveat
grid 4 × 1fr, gap 34 / 28, padding-top 10
┌ page -3° ─┐ ┌ page 2° ──┐ ┌ page -1° ─┐ ┌ page 3° ──┐
│ \ tape │ │ ═ tape ═ │ │ ● pin │ │ tape / [REPRINT] │
│ picture │ │ picture │ │ picture │ │ picture │
│ caption · date (strip 40) │
└───────────┘ └───────────┘ └───────────┘ └───────────┘
┌ page 2° ──┐ ┌ page -2° ─┐ ┌ page 1° ──┐ ┌ page -3° ─┐
│ … │ │ ● pin │ │ ═ tape ═ │ │ tape / │
↗ order a reprint of any of these (Caveat 26, blue, bottom left, below the grid)
main.wrap→div.head(h1with asmallkicker,p),div.grid,span.note[aria-hidden].- Each page is
a.photo[style="--rot:…"](add.pinfor a pinned one) → optionalspan.tape.a|b|c[aria-hidden], optionalspan.stamp[aria-hidden],figure→span.img[aria-hidden]with an inline SVG,figcaptionwith asmalldate.
Tokens
:root {
--board: #c9a97c; --paper: #fbf6ec; --paper-2: #efe2c8;
--ink: #2b2118; --ink-2: #4a3a2a; --ink-3: #5e4d3a; --line: #b08f62;
--red: #d9442b; --blue: #2f6f8f; --yellow: #e0a300;
--tape: rgba(255,250,230,.6);
--hand: "Caveat", cursive; --sans: "Inter", system-ui, sans-serif;
--r: 4px; --shadow: 0 8px 20px -10px rgba(43,33,24,.45);
--pad: 10px; --strip: 40px; --lift: 6px; --tape-w: 92px; --tape-h: 24px; --pin: 16px;
--t-micro: 200ms; --t-tilt: 320ms;
--ease: cubic-bezier(.2,.7,.2,1); --expo: cubic-bezier(.16,1,.3,1);
}
Typography
| Role | Family | Size | Weight | Line-height | Tracking | Case |
|---|---|---|---|---|---|---|
| Title | Caveat | 48px | 700 | 1 | 0 | as written |
| Kicker | Inter | 12px | 600 | 1 | +0.12em | UPPERCASE, --ink-3 |
| Sentence | Inter | 14px | 400 | 1.5 | 0 | sentence, --ink-2, right-aligned |
| Caption | Caveat | 21px | 700 | 1 | 0 | sentence, --ink-2 |
| Date | Inter | 11px | 500 | 1 | +0.04em | --ink-3 |
| Stamp | Inter | 10px | 600 | 1 | +0.14em | UPPERCASE, --red, 2px border, 8° |
| Note | Caveat | 26px | 700 | 1 | 0 | lower case, --blue, −3°, bottom left |
Motion
| Element | Trigger | Property | From → To | Duration | Easing |
|---|---|---|---|---|---|
.photo | hover, focus-visible | transform | rotate(var(--rot)) → rotate(0) translateY(-6px) | 320ms | --expo |
Reduced motion: transitions 1ms and the page keeps its tilt on hover.
States
- Page rest: tilted by
--rot, paper, shadow, tape or pin. Hover / focus: straight, lifted, z-index 2. Focus-visible: 2px blue outline at 4px offset. - Pinned: no tape; a 16px red disc at the top centre with a 2px shadow and an inner shade.
- Stamped: the Reprint stamp at the top right, 85% opacity.
Content rules
- One caption per page, four words or fewer, in the person’s voice; the date is the only sans text on the card.
- Pages are in date order, left to right then down. Do not sort by colour or size.
- At most one stamp per eight pages, and only for a real state (reprint, favourite, sold). A stamp is not decoration.
- Pictures are the person’s photos. The drawn placeholders in this demo stand in for them and are never shipped.
Accessibility
- Every page is a link with a visible caption and date as its text; pictures, tape, pins, the stamp and the note are
aria-hidden. - Focus straightens the page like hover, so keyboard users get the same cue plus the ring.
- Contrast:
--ink-2caption on paper 9.4:1;--ink-3date on paper 7.0:1; the kicker--ink-3on the board 4.6:1; the sentence--ink-2on the board 5.8:1; the note is decoration. - Hit targets: each page is a whole-card link; nothing smaller than the card is interactive.
Where it lives
- On a personal site or a scrapbook product, this is the month view: one grid per month, the title in the hand, the kicker naming the book.
- In a product with a detail page, each card links to the page’s own view; the straightening on hover is the only preview. Do not add a lightbox.
- Under a collage hero (
collage-hero), the grid is the second section; the hero’s three pages are not repeated here. - It never sits inside a card or a panel: the board is the page background, and the cards sit straight on it.
Responsive rules
- ≥ 1280: four columns, gap 34 / 28.
- 1024–1279: four columns, gap 26 / 20, caption 19px.
- 768–1023: three columns; the head stacks.
- < 640: two columns, gap 22 / 14, padding 20px, caption 18px, tape 72×20; rotations halved so pages do not overlap; the note hidden.
Acceptance checklist
Always
- A real CSS grid of link cards; each card’s tilt comes from its own
--rotcustom property between -3° and 3°. - Each card is held by one thing: a tape strip at a corner or the top, or a pin; never both, never none.
- Captions are in the hand face; dates, the kicker and the sentence are the sans.
- Hover or focus straightens the card to 0° and lifts it 6px over 320ms; nothing else moves.
- Pictures are decorative; the link text is the caption and date.
- Rotations and the lift are removed under reduced motion; focus rings stay.
- No photo texture on the board; one dot grain at most.
- The note sits below the grid and covers no card; the stamp may overhang a card’s edge by a few pixels, nothing else does.
This demo
- Eight pages for May with the captions and dates above; pages 3 and 6 pinned; page 4 stamped “Reprint”; the note “order a reprint of any of these”.
Implementation notes
Tilt per card, one variable:
.photo { transform: rotate(var(--rot)); transition: transform var(--t-tilt) var(--expo); }
.photo:hover, .photo:focus-visible { transform: rotate(0deg) translateY(calc(var(--lift) * -1)); z-index: 2; }
<a class="photo" href="/pages/12-may" style="--rot:-3deg">…</a>
Three tape positions and one pin, as classes:
.tape { position: absolute; width: 92px; height: 24px; background: var(--tape); box-shadow: 0 1px 2px rgba(43,33,24,.15); pointer-events: none; }
.tape.a { left: -24px; top: -9px; transform: rotate(-36deg); } /* top-left corner */
.tape.b { right: -24px; top: -9px; transform: rotate(36deg); } /* top-right corner */
.tape.c { left: 50%; top: -11px; transform: translateX(-50%) rotate(-2deg); } /* along the top */
.pin::before { content: ""; position: absolute; left: 50%; top: -8px; width: 16px; height: 16px; border-radius: 50%;
background: var(--red); transform: translateX(-50%); box-shadow: 0 2px 0 rgba(43,33,24,.35), inset -3px -3px 0 rgba(43,33,24,.2); }
Pinned or taped is per card, as a class, so a product can mark a kind (pinned = favourite, taped = ordinary) without a legend; say which in the caption’s date line if the difference matters.
Variants. A three-column version at 1024 drops the gap to 26px and tilts to ±2°. With real photos, .img keeps the 4:3 box and uses object-fit: cover; square photos get a 1:1 box and the caption strip stays 40px. A month with fewer than eight pages leaves the grid short; do not pad it with blank cards.
Common mistakes: rotating the whole grid (only cards tilt); tilts over 3° at four columns (corners collide); a box-shadow on the tape; captions in the sans and dates in the hand (the other way round); forgetting pointer-events: none on the tape, so it steals the hover.
Details
- Palette
- Type
- Caveat · Inter
- Motion
- Subtle motion
- Build
- Quick build
- Tags