2 cases built from this template
Same prompt, different [VARIABLES]. Click one to preview it above.About this template
This is a one-page landing site for a design tool where the first screen is something you can play with. Inside a framed canvas window, each letter of the headline and a handful of small interface chips (a share button, a toggle, color swatches, live-cursor name tags, a slider) are separate physical pieces. They drop in one after another, bounce and pile up on the floor of the window. Visitors can grab any piece with a mouse or a finger, fling it across the frame and watch it knock the others over. On phones, tilting the device tips gravity so the pile slides toward the lower edge, with a small Enable tilt button only where the browser asks for permission. The physics is written by hand in plain TypeScript, with no physics library: a fixed-timestep loop, rotated-box collisions, friction, bounce, sleeping pieces and a pause whenever the hero scrolls away. That makes the template a readable lesson as well as a page, and the engine is reused for small looping scenes inside each feature card and for confetti after sign-up. Below the hero the page settles into a familiar order: a scrolling feature band, six feature cards, three pricing plans with a monthly and yearly switch, testimonials with portraits, a sign-up panel and an FAQ. The look is warm off-white with five candy colors, chunky rounded blocks, thick dark outlines and hard offset shadows, set in Bricolage Grotesque and Figtree. It suits founders and small teams launching a creative or productivity tool, and developers who want a hero that people stop to play with. To adapt it, change the brand, the one-line product description, the audience and the falling headline word; the chips, features, plans and answers are rewritten to match while the layout and motion stay the same.
The template prompt
The live demo was built from exactly this text — nothing added. The other cases only change the values of the [VARIABLES].
# Physics Playground Landing Page
Build this website exactly as described below. Replace the [VARIABLES] with your own values; keep everything else.
## Brief
A one-page landing site for [BRAND], [PRODUCT]. The first screen is a toy: inside a framed canvas-style arena, every letter of [HERO_WORD] and nine small UI chips (a Share button, a toggle, swatches, live-cursor tags, a slider) are separate rigid bodies driven by a hand-rolled 2D physics engine. They drop in staggered from above, bounce, stack and settle on the arena floor; visitors can grab any piece with mouse or touch and throw it, and on phones tilting the device redirects gravity. Below the hero the page calms down into a conventional SaaS rhythm: a feature marquee, a six-card feature grid where each card holds a small looping physics vignette, a three-tier pricing table with a monthly/yearly toggle, testimonials with portraits, a sign-up band that rains confetti blocks after a local-only submit, an FAQ and a footer.
- Audience: [AUDIENCE] who want a tool that feels playful but produces exact, hand-off-ready work; secondarily, developers and indie founders who want to learn how a from-scratch 2D physics loop works and reuse it on their own product page.
- Goal: Make visitors stay and play on the first screen, then move them down the page to pick a plan and leave an email in the sign-up band.
- Tone: Warm, witty and concrete. Short sentences, real numbers, no buzzwords. The visuals are tactile and sticker-like: chunky rounded blocks, thick near-black outlines, hard offset shadows, candy colors on a warm off-white canvas, bouncy but never chaotic motion.
## Stack
- Framework: Vite 5 + vanilla TypeScript
- Styling: Tailwind CSS 3.4
- Libraries: vite (MIT), typescript (Apache-2.0), tailwindcss (MIT), postcss (MIT), autoprefixer (MIT), lucide (vanilla package, individual icon imports) (ISC), @fontsource-variable/bricolage-grotesque (OFL-1.1), @fontsource-variable/figtree (OFL-1.1), @fontsource/jetbrains-mono (OFL-1.1)
- Build: `npm run build` → static files in `dist/`. No backend, no server code, no external APIs.
- Setup:
- Scaffold with npm create vite@latest using the vanilla-ts template. One HTML page at the project root: index.html with <div id="app"></div> and <script type="module" src="/src/main.ts">. No UI framework and no physics library: the engine is written by hand in src/physics/.
- vite.config.ts: base './', build { outDir 'dist', sourcemap false, assetsInlineLimit 0, target 'es2020' }. Do not copy src/ into dist/. package.json scripts: dev 'vite', build 'tsc --noEmit && vite build', preview 'vite preview'.
- Tailwind 3.4 through PostCSS with content ['./index.html', './src/**/*.ts']. In tailwind.config.ts add every color under Design to theme.extend.colors with the exact kebab-case names given (paper, paper-deep, card, ink, ink-soft, rule, tomato, butter, mint, sky, grape, tomato-tint, butter-tint, mint-tint, sky-tint, grape-tint). fontFamily: display ['Bricolage Grotesque Variable', 'system-ui', 'sans-serif'], sans ['Figtree Variable', 'system-ui', 'sans-serif'], mono ['JetBrains Mono', 'ui-monospace', 'monospace']. boxShadow: hard '4px 4px 0 #1A1714', 'hard-md' '6px 6px 0 #1A1714', 'hard-lg' '8px 8px 0 #1A1714'. borderWidth: 3 '3px'. maxWidth: container '1200px'.
- src/fonts.ts imports '@fontsource-variable/bricolage-grotesque', '@fontsource-variable/figtree', '@fontsource/jetbrains-mono/500.css'. src/main.ts imports src/fonts.ts and src/style.css first, then renders the page.
- src/style.css holds @tailwind base/components/utilities plus: body bg #FBF6EC, text #1A1714, font-sans, antialiased; .dot-grid background (radial-gradient(#1A171422 1.2px, transparent 1.4px) 0 0 / 22px 22px); .btn, .btn-primary, .btn-outline, .pill and .chip component classes; @keyframes marquee (translateX 0 to -50%), @keyframes pop-in (scale .6 opacity 0 to scale 1 opacity 1, cubic-bezier(.34,1.56,.64,1)); and a @media (prefers-reduced-motion: reduce) block that disables marquee and pop-in animations and all CSS transitions longer than 0.01s.
- File layout: src/content.ts (every string, number, chip definition, feature, plan, testimonial, FAQ item and image path, typed, as one exported object); src/lib/brand.ts (brandSlug = [BRAND] lowercased with every run of non-alphanumeric characters replaced by '-' and trimmed of '-', emailDomain = brandSlug without hyphens + '.com'); src/lib/storage.ts (safe localStorage get/set wrapped in try/catch, keys prefixed with brandSlug + ':'); src/lib/motion.ts (reducedMotion boolean from matchMedia, plus a change listener that reloads the arena layouts).
- Physics module in src/physics/ (pure TypeScript, no DOM except in render.ts): vec.ts (tiny 2D vector helpers: add, sub, scale, dot, cross, rotate, length), body.ts (Body type: id, w, h, x, y (center), angle, vx, vy, av, invMass, invInertia, restitution, friction, isStatic, sleeping, sleepTime, grabbed), collide.ts (OBB vs OBB with the separating axis theorem over the 4 face normals, returning normal, penetration and 1–2 contact points found by clipping the incident edge against the reference face), world.ts (World class: bodies, gravity {x,y}, step(dt), addBody, removeBody, wakeAll, setBounds(width,height)), drag.ts (pointer grab and throw), loop.ts (fixed-timestep runner), render.ts (writes each body's transform to its DOM element).
- Engine constants (in src/physics/world.ts, exported so readers can tweak them): fixed step 1/120 s; at most 5 substeps per animation frame (drop leftover time beyond that); gravity magnitude G = 2600 px/s^2 pointing down; density 0.001 so mass = w*h*0.001 and inertia = mass*(w*w + h*h)/12; linear damping 0.02 per second and angular damping 0.6 per second applied as v *= 1 / (1 + damping*dt); max linear speed 4000 px/s; restitution 0.3 for letter blocks and 0.45 for chips; friction 0.55 for everything; static walls have invMass 0 and invInertia 0.
- World.step(dt): (1) integrate velocities of awake, non-static bodies with gravity and damping; (2) broad phase: skip pairs whose axis-aligned bounding boxes do not overlap and pairs where both bodies are asleep or static; (3) narrow phase with collide.ts; wake a sleeping body when an awake body touches it with relative speed above 30 px/s; (4) sequential-impulse solver, 10 iterations, per contact point: normal impulse with restitution applied only when approach speed exceeds 60 px/s, accumulated normal impulse clamped to >= 0, Coulomb friction impulse clamped to +/- friction * normal impulse, using the standard effective mass 1/(invMassA + invMassB + (rA x n)^2 invIA + (rB x n)^2 invIB); (5) integrate positions and angles; (6) positional correction: push each pair apart along the normal by max(penetration - 0.5, 0) * 0.35, split by inverse mass; (7) sleep: a body whose speed < 8 px/s and |av| < 0.08 rad/s for 0.6 s goes to sleep (velocities zeroed); a grabbed body never sleeps.
- Bounds: each world has three static walls built from its container size: a floor whose top edge is the container bottom (200 px thick), and left and right walls outside the container edges (200 px thick, 4000 px tall, extending far above the top). There is no ceiling: thrown pieces fly up and fall back. If any body ends up more than 120 px outside the container (after a resize, for instance) teleport it to just above the floor at the nearest valid x with zero velocity.
- loop.ts: Runner class with start(), stop(), and an accumulator over requestAnimationFrame timestamps (clamp frame delta to 1/20 s). It stops itself when every body is asleep and nothing is grabbed, and restarts on wake (pointer down, tilt change, Reset, Shake, resize). Each world's container is watched by an IntersectionObserver: out of view means stop, back in view means start. document visibilitychange also stops and starts it.
- render.ts: each body maps to an absolutely positioned element (top 0, left 0, will-change transform) inside its container. Every frame set transform = translate3d(x - w/2 px, y - h/2 px, 0) rotate(angle rad). Keep the hard shadow pointing down-right whatever the rotation: compute the offset (6, 6) rotated by -angle, round to 0.5 px, and set style.boxShadow = `${sx}px ${sy}px 0 #1A1714` only when the angle changed by more than 0.01 rad since the last write.
- drag.ts: pointerdown on a body element calls setPointerCapture, marks the body grabbed and awake, stores the grab point in body-local coordinates and adds class is-grabbed (inner wrapper scales to 1.06, shadow offset grows from 6 to 10 px, z-index 50, cursor grabbing). Each step, a spring-damper at the grab point pulls the body toward the pointer: desired velocity = (pointer - grabWorldPoint) * 25, clamped to 3500 px/s, applied as an impulse at the grab point equal to (desired - velocityAtGrabPoint) * effectiveMass * 0.5, so bodies swing and rotate naturally when held off-center. Keep the last 6 pointer samples with timestamps; on pointerup or pointercancel, set the body's linear velocity to the average pointer velocity over the last 100 ms (clamped to 3000 px/s), keep its angular velocity, and release. Hovered bodies show cursor grab. Set touch-action: none on every body element and on the arena so dragging never scrolls the page, but leave the page scrollable by touching the empty arena background (touch-action pan-y on the arena background layer).
- src/hero/arena.ts builds the hero world from content.ts: one letter body per non-space character of [HERO_WORD] and one body per chip, creates their DOM, places spawn positions, runs the drop-in, and wires Reset, Shake and tilt. src/hero/tilt.ts handles DeviceOrientationEvent. src/features/vignettes.ts creates one small World per feature card. src/signup/confetti.ts creates the sign-up band's confetti world. src/sections/*.ts each export a function returning that section's HTML string from content.ts; main.ts concatenates them into #app, then mounts the interactive parts (header, arena, marquee, vignettes, pricing toggle, FAQ, sign-up).
- Before the first build, download every image listed under Assets into public/images/ with curl -L -o using the exact file names given. The build itself never fetches anything.
- public/favicon.svg as described under Assets. index.html: lang en, <meta name='theme-color' content='#FBF6EC'>, <link rel='icon' href='./favicon.svg' type='image/svg+xml'>, <title>[BRAND] — sketch interface ideas together</title> (rewrite the part after the dash to fit [PRODUCT] when it changes).
- Write ASSETS.md at the project root as described under Assets. dist/ holds index.html, hashed JS/CSS, the woff2 font files, favicon.svg and the three portraits; keep it under 5 MB.
## Variables
- [BRAND] — Brand name (default: "Wobblebox"). Invented product name, one or two words. Used in the wordmark, title, footer blocks, email (hello@ + emailDomain) and localStorage keys. Never a real company.
- [PRODUCT] — What the product is (default: "a browser canvas for sketching interface ideas together"). One lowercase phrase starting with 'a' or 'an'. Drives the hero subline, title, feature cards, chip labels and FAQ. Works best for a playful creative or productivity tool.
- [AUDIENCE] — Who it is for (default: "product designers and the engineers who build their screens"). One lowercase phrase. Used in the hero note, pricing intro and testimonials roles.
- [HERO_WORD] — Physics headline (default: "SKETCH LOOSE"). The letters that fall in the hero. 6–14 letters, one or two words, uppercase. Each letter becomes a draggable block; a space separates the words.
- [CREDIT] — keep a small "Template by VibeFather" link to https://vibefather.ai/t/physics-playground-landing-page in the footer (default: yes; delete this line to remove it)
The copy under Pages & Sections is written for the default values. If your values differ, rewrite every headline, paragraph, label and image for them — same length, tone and structure. Layout, colors, type and motion stay as described.
Keep all copy, image paths and links in one content file (for example `src/content.ts`), keyed by section, so the content can be swapped later without touching components.
## Design
### Colors
- paper `#FBF6EC` — Page background and arena background (warm off-white canvas)
- paper-deep `#F3EADA` — Alternate section background (features, FAQ), input fills
- card `#FFFDF8` — Card and white chip fills
- ink `#1A1714` — All outlines (3px), hard offset shadows, headings and body text, footer background
- ink-soft `#5B544B` — Secondary text, captions, meta labels
- rule `#E4D9C6` — Hairline dividers inside cards and the FAQ
- tomato `#FF5A36` — Primary candy: primary buttons, Share chip, first letter in the color cycle
- butter `#FFC93C` — Candy: marquee band, featured pricing card, sign-up band background
- mint `#34D399` — Candy: toggle track, success states, comment chip
- sky `#4D8DFF` — Candy: cursor tag, links on hover, letter color cycle
- grape `#A77BFF` — Candy: second cursor tag, badges, letter color cycle
- tomato-tint `#FFE1D8` — Vignette background tint for tomato-accent feature cards
- butter-tint `#FFF1C7` — Vignette background tint for butter-accent cards
- mint-tint `#D5F6E9` — Vignette background tint for mint-accent cards
- sky-tint `#DCE8FF` — Vignette background tint for sky-accent cards
- grape-tint `#ECE3FF` — Vignette background tint for grape-accent cards
### Typography
- Display: letter blocks, section headings, prices, wordmark: Bricolage Grotesque Variable (OFL), weights 600/700/800
- Text: body copy, buttons, nav, FAQ: Figtree Variable (OFL), weights 400/500/600/700
- Mono: chip labels like 'Frame 12', code tags in vignettes, eyebrow labels: JetBrains Mono (OFL), weights 500
### Layout & motion
- Spacing: 8px base. Container max-width 1200px with 24px side padding (16px under 640px). Sections use 112px vertical padding on desktop and 72px on mobile. Card gaps 24px (16px mobile). Section headings: eyebrow (mono 13px uppercase, letter-spacing 0.08em, ink-soft) 12px above an h2 in Bricolage 800, 56px/1.0 desktop and 36px/1.05 mobile, letter-spacing -0.02em, then a 18px Figtree intro paragraph (max-width 560px, ink-soft) 16px below.
- Radius: Everything is chunky and rounded: letter blocks 18px (10px on mobile), chips and buttons 999px pills except square chips 14px, cards 24px, the hero arena frame 28px, the sign-up panel 32px, inputs 999px. Every bordered element uses a 3px ink border.
- Motion: Hero drop-in: letters spawn in reading order, 90 ms apart, from y = -140 to -620 px above the arena top with a random angle of +/-0.15 rad, then chips spawn 70 ms apart after the last letter at random x positions; all falling, bouncing and settling comes from the physics engine, not CSS.
- Motion: Buttons press like stickers: hover translate(-2px,-2px) with shadow 4px to 6px over 120ms ease-out; active translate(2px,2px) with shadow 0 over 60ms.
- Motion: Grabbed bodies lift: inner wrapper scale 1.06 and shadow offset 10px while held, spring back to 1.0 and 6px over 180ms cubic-bezier(.34,1.56,.64,1) on release.
- Motion: Marquee band scrolls left continuously at 40 s per loop, pauses on hover.
- Motion: Section headings and cards enter with a 'pop' when 20% visible: from translateY(24px) scale(0.96) opacity 0 to rest over 520ms cubic-bezier(.34,1.56,.64,1), cards staggered 70ms; triggered once by IntersectionObserver.
- Motion: Feature vignettes drop their pieces when the card enters view, then loop: after all pieces sleep and 5 s pass without interaction, pieces shrink to scale 0 over 200ms and re-drop.
- Motion: Pricing toggle knob slides with a 260ms overshoot easing; price digits roll vertically (old value slides up and out, new value slides up from below) over 250ms.
- Motion: Testimonial cards rest at small rotations (-2deg, 1.5deg, -1deg) and straighten to 0deg with translateY(-4px) on hover over 200ms.
- Motion: prefers-reduced-motion: no drop-in, no tilt, no Shake, no idle loops, no marquee movement, no pop-ins, no digit rolls. Hero and vignette pieces render pre-settled in a composed layout; dragging still works and released pieces settle under normal gravity.
- Imagery: The hero's visual anchor is the framed physics arena itself: a polished, invented canvas-app mock (dotted grid, mini toolbar, candy letter blocks and UI chips with thick outlines and hard shadows), never typography on a flat background. All UI chips, vignette pieces, icons and decorative shapes are drawn in code with HTML/CSS and Lucide icons; no screenshots of any real design tool and no product chrome that resembles one. The only raster images are three AI-generated testimonial avatars of fictional people, drawn as one series: flat vector illustration, no outlines, no facial features, warm off-white background with a soft pastel blob, head and shoulders. Portraits are cropped to 64px circles with a 3px ink border.
## Pages & Sections
### Home (`index.html`)
1. **Content file and copy rules** — All copy below is written for the default values ([BRAND] = Wobblebox, [PRODUCT] = a browser canvas for sketching interface ideas together, [AUDIENCE] = product designers and the engineers who build their screens, [HERO_WORD] = SKETCH LOOSE). Put every string, price and number in src/content.ts and render from it. If any variable value differs, rewrite the hero copy, the nine chip labels (keep their shapes, sizes and colors), the marquee items, the six feature cards and their vignette pieces, the plan features, testimonials and FAQ so they are specific and believable for the new product, keeping the same structure and counts. All people, companies and figures are invented. Fixed facts for the default: company '[BRAND] Labs', 418 Lantern Row, Suite 3, Portland, OR 97209 (invented street); email hello@ + emailDomain; support replies within 4 business hours on Team; 38,000 teams; 1.2 million canvases made; 4.8 out of 5 average rating from 2,300 reviews.
Layout: n/a
Motion: n/a
2. **Header (shared)** — Wordmark: a 30px square block (tomato fill, 3px ink border, 8px radius, hard 3px shadow, rotated -8deg) holding the first letter of [BRAND] in Bricolage 800 18px, followed by '[BRAND]' in Bricolage 800 24px. Nav links: 'Features' (#features), 'Pricing' (#pricing), 'Stories' (#stories), 'FAQ' (#faq), all written as ./index.html#… . Right side: text link 'Log in' (./index.html#signup) and a small primary button 'Start free' (./index.html#signup).
Layout: Sticky top, height 72px, paper background, container width. Wordmark left, nav centered (Figtree 600 16px, 32px gaps), actions right. After 16px of scroll a 3px ink bottom border appears. Under 768px the nav and Log in collapse into a 44px square menu button (Lucide 'menu', becomes 'x') that opens a full-width sheet below the header with the links stacked at 22px, each separated by a rule line, and the Start free button full width at the bottom.
Motion: Wordmark block wiggles (rotate -8deg to 6deg to -8deg over 400ms) on hover. Menu sheet slides down 12px and fades in over 200ms.
3. **Hero** — Visually hidden h1: 'Sketch loose with [BRAND], [PRODUCT].' Visible copy above the arena: eyebrow pill 'NEW · Multiplayer stickies in 3.0' (mono 13px, card fill, 3px ink border, a 8px mint dot at left); subline (Figtree 500, 22px desktop / 18px mobile, max-width 620px): '[BRAND] is [PRODUCT]. Rough enough to play with, exact enough to hand off.'; primary button 'Start sketching free' with Lucide 'arrow-right'; outline button 'See pricing'; note under the buttons (14px ink-soft): 'Free for 3 canvases · No card needed · Loved by [AUDIENCE]'. The arena below is a fake canvas window: top-left mini toolbar (a card-fill pill with five 32px icon buttons: Lucide mouse-pointer-2 (active, butter fill), square, circle, type, pen-tool), top-right controls: 'Shake' pill (Lucide 'sparkles', hidden on coarse pointers and under reduced motion), 'Reset' pill (Lucide 'rotate-ccw'), and 'Enable tilt' pill (Lucide 'smartphone', shown only when typeof DeviceOrientationEvent.requestPermission === 'function'). Bottom-left hint in mono 13px ink-soft: 'Grab anything. Throw it.' (fades out 600ms after the first grab). Letter bodies: one per non-space character of [HERO_WORD], each a rounded square with the letter in Bricolage 800, ink text, fill cycling tomato, butter, mint, sky, grape in order. Chip bodies (label · size in px at desktop · fill): 1 'Share' button with Lucide share-2 · 132x52 · tomato; 2 toggle chip with a 36x20 mint track and white knob on the right plus 'Snap to grid' · 168x52 · card; 3 swatch chip with four 22px circles tomato, butter, mint, sky · 136x52 · card; 4 cursor tag with Lucide mouse-pointer-2 + 'Maya' · 116x48 · sky; 5 cursor tag + 'Theo' · 112x48 · grape; 6 mono label 'Frame 12' · 128x44 · butter (desktop only); 7 slider chip: mono 'Opacity', a 64px track with a knob at 80%, '80%' · 184x52 · card (desktop only); 8 comment chip with Lucide message-circle + 'Looks great!' · 160x52 · mint; 9 square add button with Lucide plus in paper color · 56x56 · ink, 14px radius. All chips have a 3px ink border, Figtree 600 16px labels and the rotating hard shadow. Reset re-drops everything from the spawn positions; Shake gives every body an upward impulse of 900–1400 px/s with random sideways velocity +/-500 px/s and random spin +/-4 rad/s.
Layout: Section padding 40px top, 56px bottom. Copy block centered, text-center, stacked with 20px gaps; buttons in a row (stacked full width under 480px). Arena 40px below the note: full container width, height 480px desktop, 420px at 640–1023px, 400px under 640px; card-fill background with the .dot-grid pattern, 3px ink border, 28px radius, hard-lg shadow, overflow hidden; the toolbar and controls sit 16px inside the top corners above the bodies layer (z-index 60) and the floor is the arena's inner bottom edge. Letter size: 96x112 with 68px glyphs when arena width >= 900px, 72x84 with 50px glyphs from 640–899px, 46x54 with 32px glyphs under 640px. Chips scale to 0.75 under 640px and chips 6 and 7 are not created. Spawn x for letters follows reading order: lay the word out centered across the arena with 10px gaps and a 0.6-letter gap between words; if it is wider than the arena (mobile), spawn the first word centered and the second word centered 1 block higher so it lands on top. Chips spawn at random x between 15% and 85% of the arena width.
Motion: Physics drop-in on load (see Design motion) begins 250ms after first paint. Tilt (src/hero/tilt.ts): only on coarse pointers; on iOS the Enable tilt pill calls DeviceOrientationEvent.requestPermission() on tap and hides itself once granted (on denial it changes to 'Tilt blocked' for 2 s then hides); elsewhere listen right away. Map orientation to gravity: take gamma (or beta when screen.orientation.angle is 90 or -90, negated for -90), gx = G * clamp(angle / 35, -1, 1), gy = sqrt(max(G^2 - gx^2, (0.3 G)^2)), low-pass filter with factor 0.15 per event, and wake all bodies when gravity moves more than 2% of G. While tilt is active show a small mint pill 'Tilt on' in place of Enable tilt. Reduced motion: no drop-in; bodies start asleep in a composed layout: letters seated on the floor in reading order, centered with 10px gaps (two rows on narrow arenas, first word on top of the second), chips resting on the floor to the left and right of the word or on top of the letter row at fixed slots from content.ts; no tilt, no Shake, but dragging works.
4. **Feature marquee** — Items: 'Infinite canvas', 'Live cursors', 'Sticky components', 'Export to code', 'Version history', 'Pin comments', 'Offline mode', 'Dark canvas'. Between items a 14px square bullet rotated 12deg, cycling tomato, mint, sky, grape fills with a 2px ink border.
Layout: Full-bleed band, butter background, 3px ink borders top and bottom, height 72px (56px mobile). Items in Bricolage 700, 28px desktop / 20px mobile, 40px gaps. The track holds the list twice for a seamless loop.
Motion: CSS marquee keyframes, 40 s linear infinite, animation-play-state paused on hover. Reduced motion: static, centered, overflow hidden.
5. **Features** — id features. Eyebrow 'WHAT'S INSIDE'. h2 'Serious tools that like to play.' Intro: 'Everything a design team needs to go from scribble to shipped screen, without the heavy feeling.' Six cards (title · body · accent · vignette pieces): 1 'Live cursors, real names' · 'See who is on the canvas and where they are pointing. Up to 50 collaborators per board, each with their own color.' · sky · three cursor-tag pieces 'Ana', 'Raj', 'Jo' (sky, grape, tomato) that fall and bump; 2 'Components that snap' · 'Build a button once and reuse it everywhere. Change the original and every copy updates in under a second.' · tomato · five 64x28 blocks spawned at the same x so they land as a tower; 3 'Comments that stay put' · 'Pin feedback to the exact pixel. Resolve it with one click when the fix lands.' · mint · four comment pills ('Bigger?', 'Love it', 'Nudge 4px', 'Ship it') with Lucide message-circle; 4 'Every version, kept' · 'Scrub back through 12 months of history and restore any frame without losing today's work.' · butter · six 120x18 slabs labeled in mono 'v12' to 'v7' that pile like paper; 5 'Hand off as code' · 'Export any frame as clean React, Vue or HTML with Tailwind classes, ready to paste.' · grape · mono tag pieces '<div>', '<Button />', 'flex', 'gap-4', 'rounded-xl'; 6 'Works on a plane' · 'Edit offline. Changes sync the moment you reconnect, with conflicts shown side by side.' · mint · three 48px square icon pieces with Lucide cloud-off, refresh-cw and check.
Layout: paper-deep section background. Grid: 3 columns at >= 1024px, 2 columns at 640–1023px, 1 column below, 24px gap. Each card: card fill, 3px ink border, 24px radius, hard-md shadow, overflow hidden. Top: vignette area 200px tall with the accent's -tint color and the .dot-grid pattern, separated from the text by a 3px ink line; its own World with walls and floor. Bottom: 24px padding, a 28px accent-filled rounded square with an index number in mono, then title in Bricolage 700 24px and body in Figtree 16px ink-soft.
Motion: Cards pop in staggered. Card hover: translate(-2px,-2px), shadow 6px to 8px. Vignettes: drop when 30% visible, loop as described in Design motion, pieces are draggable with the same drag.ts, and each world stops when its card leaves view. Reduced motion: pieces pre-settled side by side on the floor (the tower and slab pile pre-stacked), no loop.
6. **Pricing** — id pricing. Eyebrow 'PRICING'. h2 'Pick a plan, keep the fun.' Intro: 'Start free. Upgrade when your team outgrows three canvases. Every plan is built for [AUDIENCE].' Toggle: 'Monthly' / 'Yearly' with a mint 'save 20%' badge next to Yearly; default Monthly. Plans: 'Doodle' · $0 both periods · 'For trying it on a side project' · features: 3 canvases, 2 editors, 30 days of version history, PNG and SVG export, community help · button 'Start free' (outline). 'Studio' · $12 per editor/month, Yearly shows $9 per editor/month with 'billed $108 yearly' · 'For freelancers and small teams' · features: unlimited canvases, unlimited viewers, 12 months of history, code export to React, Vue and HTML, custom component kits, offline mode · badge 'Most picked' · button 'Start 14-day trial' (primary). 'Team' · $24 per editor/month, Yearly $19 with 'billed $228 yearly' · 'For product teams shipping weekly' · features: everything in Studio, shared libraries across teams, admin roles and audit log, private canvases, priority support within 4 business hours · button 'Talk to us' (outline, links to ./index.html#signup). Under the cards: 'Students and teachers get Studio free with a school email. Nonprofits get 50% off Team.'
Layout: paper background. Toggle centered below the intro: a 3px-bordered pill with two 120px segments and a butter knob that slides behind the active label. Three cards in a row on desktop (stacked under 900px, Studio first on mobile), 24px gap, aligned to the top. Each card: card fill, 3px border, 24px radius, hard-md shadow, 32px padding; plan name Bricolage 700 24px; price in Bricolage 800 64px with '/editor/mo' in Figtree 16px ink-soft; billed note 14px; description; 3px rule; feature list with Lucide 'check' icons in 22px mint circles; full-width button at the bottom. Studio card: butter fill, scale 1.04 on desktop, hard-lg shadow, and a 'Most picked' badge (grape fill, ink border, mono 13px) rotated 6deg overlapping its top-right corner.
Motion: Knob slides with overshoot; prices roll per Design motion. Cards pop in staggered.
7. **Testimonials** — id stories. Eyebrow 'STORIES'. h2 'Teams that stopped dreading reviews.' Stat row of three chips: '38,000 teams', '1.2M canvases made', '4.8/5 from 2,300 reviews' (Lucide star in butter). Quotes: 1 'We replaced three tools and a whiteboard with one canvas. Our design reviews went from 60 minutes to 25.' — Priya Raman, Design lead, Fernbank Health (portrait-priya.webp, card accent tomato); 2 'The code export is the first one our engineers did not rewrite. We shipped the onboarding redesign two sprints early.' — Marcus Okafor, Front-end engineer, Tidewater Freight (portrait-marcus.webp, accent sky); 3 'I sketch with clients live on calls now. They drag things around, laugh, and sign off faster.' — Lena Vogt, Freelance product designer, Hamburg (portrait-lena.webp, accent mint).
Layout: paper background. Stat chips centered in a wrapping row (pill, card fill, 3px border, hard shadow, Bricolage 700 20px). Three cards in a row on desktop, stacked on mobile, 28px gap. Each card: card fill, 3px border, 24px radius, hard-md shadow, 28px padding, a 10px accent-colored band along the top edge inside the border, a large Bricolage 800 opening quote mark in the accent color, quote in Figtree 500 20px/1.45, then a row with the 64px circular portrait (3px ink border, object-fit cover) and name (Figtree 700) with role (14px ink-soft). Cards are rotated -2deg, 1.5deg and -1deg on desktop and not rotated on mobile.
Motion: Pop in staggered; hover straightens and lifts per Design motion.
8. **Sign-up band** — id signup. h2 'Your first canvas is ready when you are.' Sub: 'Free for 3 canvases. No card, no trial clock.' Form: email input (placeholder '[email protected]', aria-label 'Email address') and primary button 'Get my canvas'. Validation message under the field if the address does not match a simple email pattern: 'That email looks a little wobbly. Try again?' On valid submit: preventDefault, save { email, at } to localStorage key brandSlug + ':signup', replace the form with a success line 'You are in. Check your inbox for a link to your first canvas.' and a small mint pill showing the email, then drop 16 confetti blocks into the panel. If the key already exists on load, show the success state without confetti. The form never sends data anywhere.
Layout: Container-width panel with 32px radius, butter fill, 3px ink border, hard-lg shadow, 72px padding desktop / 40px mobile, centered text, min-height 360px, overflow hidden, position relative. h2 in Bricolage 800 52px desktop / 34px mobile. Input and button in one 3px-bordered pill row (card-fill input, button inside on the right) max-width 520px; stacked full width under 480px. The confetti world fills the panel behind the text (z-index below the copy, pointer events enabled only on the confetti pieces).
Motion: Confetti: 16 blocks 18–30 px, candy fills, 2px ink border, 4px radius, spawned across the panel top 60ms apart with random spin, then pile on the panel floor and stay draggable. Reduced motion: confetti appears already resting along the panel floor.
9. **FAQ** — id faq. Eyebrow 'FAQ'. h2 'Questions, answered.' Items: 'Is the free plan really free?' — 'Yes. Doodle includes 3 canvases and 2 editors with 30 days of history, for as long as you like. Upgrade only when you need more.' 'Can I bring in my existing files?' — 'Drop in SVG, PNG and PDF files or paste frames from your clipboard. Layers stay editable after import.' 'How does code export work?' — 'Pick a frame and choose React, Vue or plain HTML. You get components with Tailwind classes and your colors and spacing as CSS variables.' 'Does it work offline?' — 'On Studio and Team, yes. Keep editing on a plane; changes sync when you reconnect and any conflicts are shown side by side.' 'What happens to my canvases if I cancel?' — 'They stay readable and you can export everything as SVG or JSON at any time. Nothing is deleted for 12 months.' 'Do you have education or nonprofit pricing?' — 'Studio is free for students and teachers with a school email. Nonprofits get 50% off Team.'
Layout: paper-deep background. Two columns on desktop: left 4/12 holds the eyebrow, h2 and a small card 'Still curious? Write to hello@' + emailDomain (mailto link); right 8/12 holds the accordion. Single column on mobile. Each item: card fill, 3px border, 18px radius, hard shadow, 12px gap between items; question row in Figtree 700 18px with a 32px round butter button holding Lucide 'plus' on the right; answer in Figtree 16px ink-soft with 20px padding. Buttons have aria-expanded and aria-controls.
Motion: One item open at a time (the first open by default). The plus rotates 45deg and the answer's height animates over 240ms ease-out. Reduced motion: instant.
10. **Footer (shared)** — Top: '[BRAND]' spelled out in static letter blocks (same style as the hero blocks, 56px on desktop, 36px on mobile, alternating -4deg / 3deg rotations, candy fill cycle). Columns: Product (Features, Pricing, Stories, FAQ), Company (About, Careers — 'we are hiring 4 roles', Press kit), Resources (Help center, Templates, Community), Contact (hello@ + emailDomain, '[BRAND] Labs, 418 Lantern Row, Suite 3, Portland, OR 97209'). Bottom row: '© [BRAND] Labs' and small links 'Privacy' and 'Terms'. Every link points to ./index.html or ./index.html#<section-id>; the email is a mailto link.
Layout: ink background, paper text, 3px butter top border. Container with 72px top padding: the letter-block wordmark on the left, the four columns in a 4-column grid on the right (2x2 on mobile, below the wordmark). Column headings mono 13px uppercase butter; links Figtree 16px paper at 80% opacity, 100% on hover. Bottom row separated by a 1px line at 15% paper opacity, 14px text.
Motion: Each footer letter block wiggles (rotate to 0deg and back over 300ms) on hover. Reduced motion: none.
## Assets
- image: Template portraits made for this design (Generated by VibeFather with qwen-image-3.0-pro, redistributable with this template). All three show fictional people. Download each with curl -L -o into public/images/: https://media.vibefather.ai/assets/1869ad30-0c17-4c37-978d-8a5e2fdf32bf/portrait-priya.webp → public/images/portrait-priya.webp (Testimonial 1; alt 'Illustrated avatar of Priya Raman, a design lead'); https://media.vibefather.ai/assets/1869ad30-0c17-4c37-978d-8a5e2fdf32bf/portrait-marcus.webp → public/images/portrait-marcus.webp (Testimonial 2; alt 'Illustrated avatar of Marcus Okafor, a front-end engineer'); https://media.vibefather.ai/assets/1869ad30-0c17-4c37-978d-8a5e2fdf32bf/portrait-lena.webp → public/images/portrait-lena.webp (Testimonial 3; alt 'Illustrated avatar of Lena Vogt, a freelance product designer'). Three files in total. Render them with width and height attributes of 64 and loading='lazy'.
- image: Everything else is drawn in code: the hero arena (dot grid in CSS, toolbar, letter blocks, chips), the feature vignette pieces, the marquee bullets, the confetti and the footer letter blocks are HTML elements styled with Tailwind. No other bitmaps, no placeholder services, no screenshots of real software.
- image: public/favicon.svg, drawn by hand: a 64x64 viewBox with a tomato rounded square (x 6, y 14, 40x40, rx 10, 4px #1A1714 stroke) and a butter rounded square (x 26, y 6, 30x30, rx 8, same stroke) rotated 14deg around its center, overlapping the first at the top right.
- icon: Lucide (lucide npm package, ISC), imported icon by icon and rendered with lucide's createElement into the markup: menu, x, arrow-right, mouse-pointer-2, square, circle, type, pen-tool, sparkles, rotate-ccw, smartphone, share-2, message-circle, plus, cloud-off, refresh-cw, check, star. Icons use stroke-width 2.25 and currentColor.
- font: Self-hosted via Fontsource npm packages, imported in src/fonts.ts: @fontsource-variable/bricolage-grotesque, @fontsource-variable/figtree, @fontsource/jetbrains-mono (500). All OFL-1.1; Vite bundles the woff2 files into dist/.
- image: Write ASSETS.md at the project root with a table of path, source URL, author, license for: the three portraits (source: their media.vibefather.ai URLs, author: VibeFather, license: 'Generated by VibeFather with qwen-image-3.0-pro, redistributable with this template'); Lucide icons (https://lucide.dev, Lucide contributors, ISC); the three Fontsource font packages (Fontsource / original type designers, OFL-1.1); favicon.svg and all code-drawn shapes (original, made for this template).
## Don'ts
- No physics library of any kind (Matter.js, Planck.js, Rapier, Box2D ports, p2, cannon): the 2D engine is written from scratch in src/physics/.
- No backend: no server code, API routes, databases, auth or third-party APIs. The sign-up form only writes to localStorage and never sends data anywhere.
- No real design-tool brand names, logos, UI screenshots or recognizable product chrome. Every chip, toolbar and mock UI piece is generic and invented under [BRAND].
- No copy, slogans or headline wording taken from existing physics-hero sites or design-tool marketing pages; write all copy fresh from this prompt.
- No mascots, characters or borrowed illustrations; decorative shapes are generic geometry drawn in code.
- No real pricing, user counts or customer logos; all figures, testimonials, names and companies are invented. No logo wall.
- Fonts are self-hosted through Fontsource only. Never load fonts from fonts.googleapis.com, fonts.gstatic.com or any other CDN, and use no commercial fonts.
- No CDN <script> or <link> tags, no analytics, no hotlinked images: every image is downloaded into public/images/ before building.
- No Unsplash, Pexels, Pixabay or other stock-site images, and no placeholder-image services.
- Production build only: minified, no source maps, no src/ copied into dist/, relative asset paths (base './'), dist/ under 20 MB.
- Every internal link points to a file name (./index.html or ./index.html#section), never to a bare directory or '/'.
- No mention of VibeFather anywhere in the site except an optional credit link in the footer.
- Do not let dragging scroll the page or cause console errors; the site must run at 1440x900 and 390x844 with zero console errors and no horizontal scroll.
- Do not run the physics loop when the arena or a vignette is off-screen, when the tab is hidden, or when every body is asleep.
- Respect prefers-reduced-motion: no drop-in, tilt, Shake, idle loops, marquee movement or pop-ins; render composed, pre-settled layouts with drag still working.
- Do not request device-orientation permission on page load; only from a tap on the Enable tilt pill, and never show that pill where permission is not required.
- Do not change the stack (Vite 5, vanilla TypeScript, Tailwind CSS 3.4) or add UI frameworks unless the user asks.
---
— Prompt by VibeFather · https://vibefather.ai/t/physics-playground-landing-page · CC BY-NC 4.0 (non-commercial; commercial use needs a VibeFather Pro license) · Request removal: https://vibefather.ai/takedown
Free for personal projects under CC BY-NC 4.0. Commercial use comes with Pro.
DESIGN.md
The design system on its own — colors, type, spacing and motion. Apply this look to a project you already have.
---
name: "Physics Playground Landing Page"
colors:
paper: "#FBF6EC"
paper_deep: "#F3EADA"
card: "#FFFDF8"
ink: "#1A1714"
ink_soft: "#5B544B"
rule: "#E4D9C6"
tomato: "#FF5A36"
butter: "#FFC93C"
mint: "#34D399"
sky: "#4D8DFF"
grape: "#A77BFF"
tomato_tint: "#FFE1D8"
butter_tint: "#FFF1C7"
mint_tint: "#D5F6E9"
sky_tint: "#DCE8FF"
grape_tint: "#ECE3FF"
typography:
display_letter_blocks_section_headings_prices_wordmark: { family: "Bricolage Grotesque Variable", weights: [600, 700, 800] }
text_body_copy_buttons_nav_faq: { family: "Figtree Variable", weights: [400, 500, 600, 700] }
mono_chip_labels_like_frame_12_code_tags_in_vignettes_eyebrow_labels: { family: "JetBrains Mono", weights: [500] }
spacing: "8px base. Container max-width 1200px with 24px side padding (16px under 640px). Sections use 112px vertical padding on desktop and 72px on mobile. Card gaps 24px (16px mobile). Section headings: eyebrow (mono 13px uppercase, letter-spacing 0.08em, ink-soft) 12px above an h2 in Bricolage 800, 56px/1.0 desktop and 36px/1.05 mobile, letter-spacing -0.02em, then a 18px Figtree intro paragraph (max-width 560px, ink-soft) 16px below."
radius: "Everything is chunky and rounded: letter blocks 18px (10px on mobile), chips and buttons 999px pills except square chips 14px, cards 24px, the hero arena frame 28px, the sign-up panel 32px, inputs 999px. Every bordered element uses a 3px ink border."
---
# Physics Playground Landing Page — Design System
Apply this design system to an existing project. It describes the look and feel only; for the full site, use prompt.md.
## Colors
- **paper** `#FBF6EC` — Page background and arena background (warm off-white canvas)
- **paper-deep** `#F3EADA` — Alternate section background (features, FAQ), input fills
- **card** `#FFFDF8` — Card and white chip fills
- **ink** `#1A1714` — All outlines (3px), hard offset shadows, headings and body text, footer background
- **ink-soft** `#5B544B` — Secondary text, captions, meta labels
- **rule** `#E4D9C6` — Hairline dividers inside cards and the FAQ
- **tomato** `#FF5A36` — Primary candy: primary buttons, Share chip, first letter in the color cycle
- **butter** `#FFC93C` — Candy: marquee band, featured pricing card, sign-up band background
- **mint** `#34D399` — Candy: toggle track, success states, comment chip
- **sky** `#4D8DFF` — Candy: cursor tag, links on hover, letter color cycle
- **grape** `#A77BFF` — Candy: second cursor tag, badges, letter color cycle
- **tomato-tint** `#FFE1D8` — Vignette background tint for tomato-accent feature cards
- **butter-tint** `#FFF1C7` — Vignette background tint for butter-accent cards
- **mint-tint** `#D5F6E9` — Vignette background tint for mint-accent cards
- **sky-tint** `#DCE8FF` — Vignette background tint for sky-accent cards
- **grape-tint** `#ECE3FF` — Vignette background tint for grape-accent cards
## Typography
- **Display: letter blocks, section headings, prices, wordmark** — Bricolage Grotesque Variable (OFL), weights 600/700/800. Self-host the font files.
- **Text: body copy, buttons, nav, FAQ** — Figtree Variable (OFL), weights 400/500/600/700. Self-host the font files.
- **Mono: chip labels like 'Frame 12', code tags in vignettes, eyebrow labels** — JetBrains Mono (OFL), weights 500. Self-host the font files.
## Spacing & shape
- Spacing: 8px base. Container max-width 1200px with 24px side padding (16px under 640px). Sections use 112px vertical padding on desktop and 72px on mobile. Card gaps 24px (16px mobile). Section headings: eyebrow (mono 13px uppercase, letter-spacing 0.08em, ink-soft) 12px above an h2 in Bricolage 800, 56px/1.0 desktop and 36px/1.05 mobile, letter-spacing -0.02em, then a 18px Figtree intro paragraph (max-width 560px, ink-soft) 16px below.
- Radius: Everything is chunky and rounded: letter blocks 18px (10px on mobile), chips and buttons 999px pills except square chips 14px, cards 24px, the hero arena frame 28px, the sign-up panel 32px, inputs 999px. Every bordered element uses a 3px ink border.
## Motion
- Hero drop-in: letters spawn in reading order, 90 ms apart, from y = -140 to -620 px above the arena top with a random angle of +/-0.15 rad, then chips spawn 70 ms apart after the last letter at random x positions; all falling, bouncing and settling comes from the physics engine, not CSS.
- Buttons press like stickers: hover translate(-2px,-2px) with shadow 4px to 6px over 120ms ease-out; active translate(2px,2px) with shadow 0 over 60ms.
- Grabbed bodies lift: inner wrapper scale 1.06 and shadow offset 10px while held, spring back to 1.0 and 6px over 180ms cubic-bezier(.34,1.56,.64,1) on release.
- Marquee band scrolls left continuously at 40 s per loop, pauses on hover.
- Section headings and cards enter with a 'pop' when 20% visible: from translateY(24px) scale(0.96) opacity 0 to rest over 520ms cubic-bezier(.34,1.56,.64,1), cards staggered 70ms; triggered once by IntersectionObserver.
- Feature vignettes drop their pieces when the card enters view, then loop: after all pieces sleep and 5 s pass without interaction, pieces shrink to scale 0 over 200ms and re-drop.
- Pricing toggle knob slides with a 260ms overshoot easing; price digits roll vertically (old value slides up and out, new value slides up from below) over 250ms.
- Testimonial cards rest at small rotations (-2deg, 1.5deg, -1deg) and straighten to 0deg with translateY(-4px) on hover over 200ms.
- prefers-reduced-motion: no drop-in, no tilt, no Shake, no idle loops, no marquee movement, no pop-ins, no digit rolls. Hero and vignette pieces render pre-settled in a composed layout; dragging still works and released pieces settle under normal gravity.
## Imagery
The hero's visual anchor is the framed physics arena itself: a polished, invented canvas-app mock (dotted grid, mini toolbar, candy letter blocks and UI chips with thick outlines and hard shadows), never typography on a flat background. All UI chips, vignette pieces, icons and decorative shapes are drawn in code with HTML/CSS and Lucide icons; no screenshots of any real design tool and no product chrome that resembles one. The only raster images are three AI-generated testimonial avatars of fictional people, drawn as one series: flat vector illustration, no outlines, no facial features, warm off-white background with a soft pastel blob, head and shoulders. Portraits are cropped to 64px circles with a 3px ink border.
## Tone
Warm, witty and concrete. Short sentences, real numbers, no buzzwords. The visuals are tactile and sticker-like: chunky rounded blocks, thick near-black outlines, hard offset shadows, candy colors on a warm off-white canvas, bouncy but never chaotic motion.
---
— Prompt by VibeFather · https://vibefather.ai/t/physics-playground-landing-page · CC BY-NC 4.0 (non-commercial; commercial use needs a VibeFather Pro license) · Request removal: https://vibefather.ai/takedown