Build note · site 17 of 25

How Paper Moon was cut from paper.

A look inside the making of the Paper Moon site — a children's book studio rendered as a layered construction-paper collage. What the pieces are, why they're shaped that way, and the code that holds the fox afloat.

The brief & the concept

A studio you can pick up off the table.

The brief asked for a children's book studio built as a "layered paper-cutout world": torn-edge dividers, drop-shadowed layers that float, a drawable star canvas, book cards that tilt like picked-up paper, and a palette that travels from butter to coral to teal to a final night-blue. Friendly, but not childish-sloppy.

The whole concept hangs on one idea: everything on the page should feel like a physical piece of cut paper lit by a low lamp. That single rule decided the shadows (soft, offset, warm), the edges (torn, never straight), the texture (a grain that sits over the entire page), and the motion (a gentle bob, like a mobile hanging over a crib). The two fox illustrations set the exact hues — I sampled cream #f4ecd6, coral #f0a878, teal #3a9aa0, and moon-yellow #f2d55c straight from them so the CSS-drawn layers and the artwork read as the same material.

The copy is written like a real studio wrote it: "handmade picture books for small humans — and the grown-ups brave enough to do all the voices." Six invented book titles, real ages and prices, a bundle offer with a handwritten-note upsell. Never lorem, never placeholder.

Design decisions

Choices that keep it warm, not cutesy.

Two typefaces, clear jobs

Baloo 2 (a rounded, friendly sans) carries body, UI, and labels — approachable without being a comic font. Fraunces, an optical serif, does every headline, with its italic reserved for the emotional word ("little boat", "each one cut by hand"). The contrast of soft-round against bookish-serif is the whole tone.

Warm brown ink, never black

Body text is #4a3b2e, a warm brown, on cream. True black would look printed and cold; brown reads like ink on craft paper and keeps contrast comfortable (still AA-legible) without harshness.

A palette that is a journey

The page descends through the story's day: butter-cream hero → coral studio → teal ocean → deep night-blue for the "make a wish" and shop. Each section's torn top edge is cut from the next color, so the paper appears to physically overlap.

Shadow does the lifting

Depth is never a gradient. Every "cut" piece gets a soft offset box-shadow plus a hard 3px ledge, so cards, waves, and the moon each throw their own shadow onto the layer beneath — exactly how the physical spreads are lit.

Signature techniques

The three tricks that carry it.

1 · Torn edges, drawn with turbulence

Straight dividers would break the illusion instantly. Instead, an SVG feTurbulence noise field feeds a feDisplacementMap that shoves the edge of each wave and cloud around by a few pixels — a repeatable "hand-torn" edge. Two filters at different frequencies give variety between layers.

index.html — the torn-edge filter, applied to every wave & cloud path
<!-- displaces any shape's edge with fractal noise -->
<filter id="torn" x="-5%" y="-30%" width="110%" height="160%">
  <feTurbulence type="fractalNoise"
    baseFrequency="0.012 0.11" numOctaves="3" seed="3" result="t" />
  <feDisplacementMap in="SourceGraphic" in2="t"
    scale="19" xChannelSelector="R" yChannelSelector="G" />
</filter>

2 · Layered float, like a hanging mobile

Nothing on the page is perfectly still. The fox bobs, the waves drift against each other at different speeds, and the hanging stars sway on their threads. Three small keyframe loops, each on its own tempo, so the motion never syncs up and never feels mechanical. All of it collapses under prefers-reduced-motion.

style.css — three floats at three tempos
/* the fox rocks in its boat */
@keyframes bob {
  0%,100% { transform: translateY(0) rotate(-.4deg); }
  50%      { transform: translateY(-14px) rotate(.4deg); }
}
/* wave layers slide past each other */
@keyframes drift { from { transform: translateX(-2%); } to { transform: translateX(2%); } }
/* hanging stars swing on their string */
@keyframes sway { 0%,100% { rotate: -3deg; } 50% { rotate: 3deg; } }

3 · "Draw a star for the fox"

The interactive centerpiece: a night-sky <canvas> with a hand-drawn crescent moon and paper boat, where click-and-drag sprinkles five-pointed stars that twinkle in with a spring. Each star is plotted from scratch by walking ten points around two radii. The animation loop only runs while stars are still growing, and pauses when the tab is hidden.

app.js — a five-pointed star, drawn point by point
const spikes = 5, outer = s.r, inner = s.r * 0.44;
for (let i = 0; i < spikes * 2; i++) {
  const rad = i % 2 === 0 ? outer : inner;   // alternate tip / valley
  const a = (Math.PI / spikes) * i - Math.PI / 2;
  const px = Math.cos(a) * rad, py = Math.sin(a) * rad;
  i === 0 ? ctx.moveTo(px, py) : ctx.lineTo(px, py);
}
ctx.closePath(); ctx.fill();

Assets & provenance

Where the fox came from.

Two fox illustrations

The site ships with two paper-collage fox scenes — one in the hero (fox sailing a striped boat under a crescent moon), one in the studio section (fox reclining at dusk). Everything else on the page — every wave, cloud, star, moon, and book cover — is drawn in CSS and SVG to match their palette and paper grain, so the generated art and the coded art are indistinguishable as material.

source
Generated with Higgsfield nano_banana_2, prompted for a layered paper-collage / paper-cut illustration style.
format
WebP, for small file size at high fidelity on the paper texture.
files
assets/fox-1.webp (hero), assets/fox-2.webp (studio spread).
matched by
Palette sampled directly from the artwork; a page-wide SVG feTurbulence grain unifies photo and code.

The iteration protocol

Three critique passes, then a director's note.

Every site in this showcase is built, screenshotted at desktop and mobile, and critiqued in writing like a hostile art director before anything is called done. Here is what actually changed on Paper Moon.

  1. 1
    First render, first cuts

    Full layout stood up: hero, six book cards, studio, star canvas, shop, footer. Critique flagged a mobile hero collision (a hanging star landed on the italic "boat"), a dead zone in the upper-right of the hero, and a stranded process step.

  2. 2
    Balancing the composition

    Moved the hanging moon, stars, and a new paper bird into the empty upper-right so the hero reads as a balanced mobile. Filled the dark shop's dead space with a layered-gradient starfield and a floating crescent. Made hero buttons full-width on mobile so no label clipped.

  3. 3
    Polish & a bad crescent, fixed

    A shop moon built from two overlapping radial gradients had rendered as a muddy olive disc — replaced with the clean inline-SVG crescent used elsewhere. Added a star-swing-on-hover micro-interaction. Final pass: zero console errors, no horizontal scroll, reduced-motion honored.

  4. QA
    Director's note: the Shop button

    QA caught the nav "Shop" pill as dark text on a dark-brown pill — low contrast, read as disabled. Fixed to a butter-yellow pill with bold night-blue text (~9:1 contrast, well past WCAG AA), echoing the hero moon, with a lighter-yellow hover that lifts on a deeper shadow.

Reproduce this

If you want to build one like it.

  • Sample your palette from the art. If you have illustrations, pull the CSS variables straight from their pixels so coded layers match the material.
  • Make one physical rule. Here it was "cut paper under a low lamp." Every shadow, edge, and motion choice can then be checked against it.
  • Torn edges over straight ones. One reusable feTurbulence + feDisplacementMap filter turns any SVG path into a hand-torn edge.
  • Layer motion at odd tempos. Several slow loops that never sync feel alive; one uniform animation feels like a screensaver. Gate all of it behind prefers-reduced-motion.
  • Give visitors one thing to make. The star canvas turns a landing page into a small toy — pause its loop on document.hidden so it costs nothing when unseen.
  • Critique like a stranger. Screenshot at 1440 and 390, then hunt for the thing that looks AI-default. Every real fix here came from that pass, not the first draft.