Skip to content
VibeFather
Join

2 cases built from this template

Same prompt, different [VARIABLES]. Click one to preview it above.

About this template

A single-page developer portfolio staged as a cozy isometric 3D room floating on a soft pastel gradient. The room is the whole first screen, and every object in it is a way in: the bookshelf opens About, the desk monitor opens Projects, the guitar in the corner opens Music and the little wall mailbox opens Contact. Hover an object and it lifts, brightens and shows a small floating label; click it and the camera glides in on it while a side panel slides open. Close the panel and the camera eases back home. A desk lamp doubles as a light switch: click it, or the sun and moon toggle in the corner, and the room crossfades to a deep blue night where the lamp throws warm light, the monitor glows and a strand of fairy lights twinkles along the wall.

It suits front-end developers, creative technologists, game makers and designers who code, anyone who wants a portfolio that people remember and share rather than scroll past. Everything in the scene is modeled from code primitives with flat, toy-like materials, so there are no model files to license or replace. The panels hold real content: a portrait and short bio with stack and "now" lists, four project cards with code-drawn thumbnails that expand into details, a playlist with a working silent player for your side music project, and contact rows that copy to the clipboard.

A plain HTML navigation mirrors the four objects for keyboard and screen-reader users, Escape always returns to the room, and reduced-motion mode swaps every camera move for an instant cut. On phones the room is re-framed to fit the width and the panels become bottom sheets. To make it yours, change your name, role, city, focus and music alias; the bio, projects and tracks are rewritten to match while the room, palette and interactions 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].

# Isometric 3D Room Portfolio

Build this website exactly as described below. Replace the [VARIABLES] with your own values; keep everything else.

## Brief
A single-page personal portfolio for a developer, staged as a cozy low-poly isometric 3D room. The room fills the screen; the bookshelf, desk monitor, guitar and wall mailbox are the navigation. Hover lifts and labels an object, click glides the camera to it and opens an About, Projects, Music or Contact panel, and a desk lamp flips the room between a pastel day and a deep blue night.

- Audience: Recruiters, studio leads and potential clients looking at [BRAND]'s work, plus other developers who will share a portfolio that is fun to poke at.
- Goal: Make [BRAND] memorable in under ten seconds, show four strong projects, and get the visitor to copy the email address or press 'Write an email'.
- Tone: Warm, playful and precise: a tidy toy diorama with honest, specific copy written in the first person. Short sentences, concrete numbers, no buzzwords.

## Stack
- Framework: Vite 5 + React 18 + TypeScript
- Styling: Tailwind CSS 3.4
- Libraries: react (MIT), react-dom (MIT), three (r16x) (MIT), @react-three/fiber 8 (React 18 compatible) (MIT), @react-three/drei 9 (RoundedBox, Html, Sparkles, ContactShadows) (MIT), gsap 3 (GSAP Standard License (free, commercial use allowed)), lucide-react (ISC), tailwindcss (MIT), postcss (MIT), autoprefixer (MIT), vite (MIT), @vitejs/plugin-react (MIT), typescript (Apache-2.0), @types/three (MIT), @fontsource-variable/fredoka (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 react-ts template. One HTML page at the project root: index.html (entry src/main.tsx), lang en, <link rel='icon' href='./favicon.svg' type='image/svg+xml'>, <title>[BRAND] — [ROLE]</title>.
  - vite.config.ts: base './', plugins [react()], build { outDir 'dist', sourcemap false, assetsInlineLimit 0, chunkSizeWarningLimit 1500 }. Do not copy src/ into dist/.
  - Tailwind 3.4 through PostCSS, content ['./index.html', './src/**/*.{ts,tsx}']. In tailwind.config.ts extend colors with every Design color (kebab-case keys: peach, lavender, coral, butter, lilac, leaf, shelf, wood, ink, ink-muted, panel, panel-night, night-text, screen-ink, screen-glow, lamp, hairline) and fontFamily display ['Fredoka Variable', 'system-ui', 'sans-serif'], sans ['Figtree Variable', 'system-ui', 'sans-serif'], mono ['JetBrains Mono', 'ui-monospace', 'monospace']. Night mode uses a 'night' class on <html> (darkMode: 'class').
  - src/fonts.ts imports '@fontsource-variable/fredoka', '@fontsource-variable/figtree', '@fontsource/jetbrains-mono/400.css' and '@fontsource/jetbrains-mono/500.css'; import it and src/index.css from main.tsx.
  - File layout: src/content.ts (all copy, projects, tracks, contact rows, typed); src/lib/brand.ts (firstName, brandSlug, email, codeUrl, notesUrl); src/lib/storage.ts (safe get/set with try/catch, keys prefixed brandSlug + ':'); src/lib/palette.ts (day/night color pairs and light intensities); src/store.ts (tiny external store with useSyncExternalStore holding focus, hovered, night, playing, trackIndex, elapsed, plus a nightMix ref).
  - 3D components in src/scene/: Stage.tsx (Canvas, camera, lights), CameraRig.tsx (GSAP proxy tween, home/focus math, resize), Room.tsx (floor, walls, window, rug, skirting), Interactive.tsx (hover/click wrapper), Bookshelf.tsx, DeskSet.tsx (desk, monitor with CanvasTexture, keyboard, mug), DeskLamp.tsx, Guitar.tsx (ExtrudeGeometry body) and Amp.tsx, Mailbox.tsx, Decor.tsx (plant, beanbag, chair, wall art, fairy lights), Ambient.tsx (Sparkles, clouds, stars, music notes), themed.ts (useThemedColor hook that lerps a material color each frame from nightMix).
  - UI components in src/ui/: NameChip.tsx, NavBar.tsx, NightSwitch.tsx, IntroCard.tsx, Hint.tsx, Panel.tsx, AboutPanel.tsx, ProjectsPanel.tsx (ProjectCard.tsx, Thumb.tsx with the four SVG motifs), MusicPanel.tsx (Record.tsx, Player.tsx, TrackList.tsx), ContactPanel.tsx (CopyRow.tsx, Toast.tsx). src/App.tsx composes the backdrop, Stage and overlay and syncs the hash.
  - Detect reduced motion once with matchMedia('(prefers-reduced-motion: reduce)') (and listen for changes); pass a reduced flag through the store so GSAP durations become 0 and idle animations stop.
  - Detect touch with matchMedia('(hover: none)'): skip hover effects and focus directly on tap.
  - Before the first build, download the two images listed under Assets into public/images/ with curl -L -o using the exact file names. The build itself never fetches anything.
  - Write ASSETS.md at the project root as described under Assets.

## Variables
- [BRAND] — Your name (default: "Iris Calloway"). The portfolio owner's full name (invented by default). Drives the name chip, title, intro line (first word), email, code and notes URLs and storage keys.
- [ROLE] — Role (default: "Creative front-end developer"). Short job title shown under the name and in the title.
- [LOCATION] — City (default: "Portland, Oregon"). Where you are based. Used in the name chip, bio and Contact panel.
- [FOCUS] — What you build (default: "interactive data stories and small web toys"). One lowercase phrase that completes 'I build …'. Drives the intro line and the tone of the projects.
- [MUSIC_ALIAS] — Music project name (default: "Low Tide Radio"). Invented name of your side music project shown in the Music panel. If you have no music hobby, keep the panel as a 'what I listen to while coding' playlist of invented tracks.
- [CREDIT] — keep a small "Template by VibeFather" link to https://vibefather.ai/t/isometric-3d-room-portfolio 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
- Day backdrop top `#FDE8D7` — Top stop of the daytime page gradient behind the canvas (peach).
- Day backdrop bottom `#E4E0F6` — Bottom stop of the daytime page gradient (lavender).
- Night backdrop top `#121836` — Top stop of the night gradient.
- Night backdrop bottom `#2B2459` — Bottom stop of the night gradient.
- Wall left day / night `#F6E6D3 / #3A3F6E` — Left wall (x = -5 plane) day and night colors.
- Wall right day / night `#EFD7C0 / #30355F` — Right wall (z = -5 plane), slightly darker than the left wall.
- Floor day / night `#D8B28C / #3C3452` — Floor slab top; floor edge/sides use #B98F69 / #2A2440.
- Rug `#9DCBB6` — Round rug; night tone #4A6B78.
- Wood `#C98D5E` — Desk top, bookshelf frame edges, picture frames, chair seat; darker wood #A26C43 for legs.
- Shelf blue `#8FA7D6` — Bookshelf body and the mailbox body.
- Coral `#F08A6B` — Primary accent: mailbox flag, active nav item, play button, CTA buttons, focus ring in day mode.
- Butter `#FFD27A` — Lamp shade, book spines, music note particles.
- Lilac `#C8B6FF` — Book spines, beanbag, project thumbnail tints.
- Guitar amber `#E9A23B` — Guitar body top; sides and back #B86B2A, neck #7A4A2A.
- Leaf `#6FAF7E` — Plant leaves; pot #E7C9B0.
- Screen ink `#1E2238` — Monitor screen background and night panel text on light chips.
- Screen glow `#7CE0D3` — Code bars on the monitor, monitor point light at night, night-mode focus ring.
- Lamp light `#FFC873` — Lamp point light and fairy-light emissive color at night.
- Panel day `#FFF9F2` — Panel and chip surfaces in day mode (at 94% opacity with 12px backdrop blur).
- Panel night `#1B2047` — Panel and chip surfaces in night mode (at 92% opacity with 12px backdrop blur).
- Ink `#2C2433` — Primary text in day mode.
- Ink muted `#6E6475` — Secondary text in day mode; night secondary text is #A9A6CC.
- Night text `#F3EEFF` — Primary text in night mode.
- Hairline `#EADBCB` — Day borders and dividers; night borders #343B72.

### Typography
- Display: name chip, panel titles, hover labels, intro line: Fredoka (Fontsource variable) (OFL), weights 500/600
- Text: bios, card copy, buttons, nav: Figtree (Fontsource variable) (OFL), weights 400/500/600
- Mono: eyebrows, stack chips, track durations, contact values: JetBrains Mono (Fontsource) (OFL), weights 400/500

### Layout & motion
- Spacing: Overlay inset 24px desktop / 16px mobile. Panel padding 28px desktop / 20px mobile, 20px gaps between panel blocks, 10–14px gaps inside lists. 4px base scale (4, 8, 10, 12, 14, 16, 20, 24, 28, 40).
- Radius: Overlay pills 999px; panels 24px; cards and images 18px; thumbnails 12px; 3D RoundedBox radius 0.06–0.12 world units so everything looks soft and toy-like.
- Motion: One shared state store drives everything: { focus: null | 'about' | 'projects' | 'music' | 'contact', hovered: string | null, night: boolean, playing: boolean, trackIndex: number }. Hovering an HTML nav item sets hovered to the same id as hovering the 3D object, so both highlight together.
- Motion: Easing: GSAP 'power3.inOut' for camera moves, 'power2.out' for hover lift, 'back.out(1.6)' for the intro drop-in. CSS transitions use cubic-bezier(0.22, 1, 0.36, 1).
- Motion: Intro (once on load): the room group rises from y -1.2 to 0 and scales 0.92 to 1 over 1.2s power3.out; then the interactive objects (bookshelf, desk set, guitar, mailbox, lamp) drop from y +1.5 into place with a 70ms stagger, 0.6s back.out(1.6). The overlay chips fade in 300ms after.
- Motion: Idle life: the room group bobs y ±0.06 on a 6s sine; the plant's leaf group sways ±0.05 rad on a 3.4s sine; 40 dust motes (drei Sparkles, size 2.5, speed 0.25, opacity 0.5, color #FFFFFF by day and #FFC873 by night) drift inside the room volume; the monitor cursor block toggles visibility every 530ms; by day two code-drawn clouds slide across the window sky plane (loop 40s), by night 30 star points twinkle.
- Motion: Hover (pointer devices only): object group lifts y +0.15 over 0.25s power2.out, every mesh in it gets emissive #FFFFFF at intensity 0.16 (night: emissive #FFC873 at 0.22), cursor becomes pointer, and a drei <Html> label (pill, Fredoka 500 15px) appears 0.5 units above the object, fading and rising 6px over 180ms. The mailbox flag also rotates up 70 degrees; the guitar tilts 3 degrees.
- Motion: Focus: GSAP tweens a proxy { px, py, pz, tx, ty, tz, zoom } over 1.1s power3.inOut; every frame the orthographic camera is placed at proxy position, looks at the proxy target and applies proxy zoom with updateProjectionMatrix(). The panel slides in from the right (desktop: translateX(100%) to 0 over 450ms, starting 350ms into the camera move) or up from the bottom (mobile). Back/close or Escape reverses both, panel first, then camera home.
- Motion: Day/night: GSAP tweens a single nightMix value 0 to 1 (or back) over 0.9s power2.inOut; every frame each themed material lerps between its day and night color (THREE.Color.lerpColors), light intensities lerp between their day and night values, and the two backdrop gradient layers crossfade by opacity. The lamp head bulb's emissive intensity goes 0 to 2.5, the lamp point light 0 to 18, fairy lights 0 to 1.8. The UI switch thumb slides 24px and its icon swaps sun/moon with a 90-degree rotate.
- Motion: Music playing: the record disc in the Music panel spins (360 degrees per 2.4s, linear), the progress bar advances in real time, and in the room three small butter-colored music notes (code-drawn planes) float up from the amp and fade over 2.2s, looping with 0.7s offsets.
- Motion: prefers-reduced-motion: camera moves and the day/night change become instant (duration 0), no intro, no bob, no sway, no Sparkles, no floating notes, no record spin, panels appear without sliding (opacity only, 120ms). Hover keeps the emissive highlight and label but no lift.
- Imagery: The hero is the 3D room itself, a dense, polished diorama that fills the first screen, so there is no hero photo. Everything in the scene is modeled from code primitives (drei RoundedBox, boxes, cylinders, spheres, THREE.ExtrudeGeometry from 2D shapes) with flat meshStandardMaterial (roughness 0.85, metalness 0) and soft shadows. Wall art, the monitor screen and project thumbnails are code-drawn (CanvasTexture or inline SVG) as abstract shapes in the palette: no real posters, album covers, logos or readable brand marks anywhere. The only photographs are two AI-generated images of the fictional owner inside the About panel (a head-and-shoulders portrait and an over-the-shoulder desk shot), both in the same muted pastel peach-and-lavender grade as the room.

## Pages & Sections
### Room (single page with four panels) (`index.html`)
1. **Content file and copy rules** — All copy below is written for the default values ([BRAND] = Iris Calloway, [ROLE] = Creative front-end developer, [LOCATION] = Portland, Oregon, [FOCUS] = interactive data stories and small web toys, [MUSIC_ALIAS] = Low Tide Radio). Put every string, number, project, track and contact value in src/content.ts and render from it. Derived values live in src/lib/brand.ts: firstName = first word of [BRAND]; brandSlug = [BRAND] lowercased, accents stripped, every run of non-alphanumeric characters replaced by '-'; email = 'hello@' + brandSlug without hyphens + '.dev'; codeUrl = 'github.com/' + brandSlug; notesUrl = brandSlug without hyphens + '.dev/notes'; localStorage keys are prefixed with brandSlug + ':'. If any variable value differs, rewrite the intro line, the bio, facts, stack chips, 'now' list, all four projects (names, one-liners, roles, metrics, details and thumbnail motifs), the music blurb, EP name and the six track titles so they are specific and believable for the new person, keeping the same structure and counts (4 facts, 8 stack chips, 3 'now' rows, 4 projects with 3 detail bullets each, 6 tracks, 4 contact rows). Everyone and everything is invented; no real employers, clients, artists or songs.
   Layout: Not a visible section: a rule for how the builder stores and rewrites copy.
2. **Stage: full-screen canvas and backdrop** — The page is one fixed full-viewport stage (100dvh, overflow hidden, no page scroll). Behind a transparent R3F <Canvas> sit two absolutely positioned gradient layers: day = linear-gradient(180deg, #FDE8D7 0%, #E4E0F6 100%) with a soft radial highlight rgba(255,255,255,0.55) at 50% 40%; night = linear-gradient(180deg, #121836 0%, #2B2459 100%) with a radial rgba(124,224,211,0.08) at 50% 45%. Night layer opacity follows nightMix. A soft elliptical contact shadow (drei ContactShadows, opacity 0.35, blur 2.6, far 4, color #6B5A7A) sits under the floating room. <title>: '[BRAND] — [ROLE]'. If WebGL is unavailable, render the gradient, the overlay UI and the panels with a small card 'Your browser can't draw the 3D room, but everything is in the menu.' and the nav still opens every panel.
   Layout: Canvas: orthographic, flat (NoToneMapping), shadows enabled (PCFSoftShadowMap), dpr [1, 2], antialias. Camera home: position (20, 18, 20), lookAt (0, 1.6, 0), near 0.1, far 200. Home zoom = Math.min(innerWidth / 18, innerHeight / 15) on desktop and innerWidth / 15.5 on screens under 768px, recomputed on resize; on mobile the home target shifts to (0, 2.4, 0) so the room sits in the upper 60% above the bottom nav. No OrbitControls: the view is fixed.
   Motion: Backdrop layers crossfade with nightMix. Room intro and idle bob as described under Design motion.
3. **The room: shell, lights and decor** — World units, y up, floor top at y = 0. Floor: RoundedBox 10.6 × 0.5 × 10.6 (radius 0.12) centered at (0, -0.25, 0), top color floor, sides via a second slightly larger box in the darker edge tone. Left wall: box 0.4 × 6 × 10.6 at (-5.1, 3, 0). Right wall: box 10.6 × 6 × 0.4 at (0, 3, -5.1). A 0.12-high skirting strip in wood along both walls. Window on the left wall centered at (-4.88, 3.6, 0.6): wood frame 0.12 thick, 2.4 wide × 2.0 tall, a cross mullion, sill 0.18 deep; behind it a sky plane that lerps #BFE3F5 (day) to #1A2250 (night), with two code-drawn rounded cloud shapes by day and 30 tiny star points by night. Round rug: cylinder radius 3, height 0.04 at (0.4, 0.02, 0.4) with an inner ring 2.3 radius in a lighter tint. Wall art above the desk on the right wall at (-1.6, 4.1, -4.88): wood frame 1.6 × 1.2 holding a CanvasTexture (512×384) of an abstract composition: cream ground, one coral circle, a lilac half-circle, a butter arc and three thin ink lines. A second narrow frame 0.6 × 1.4 at (1.5, 4.2, -4.88) with three vertical stripes (leaf, shelf blue, coral). Floor plant at (4.1, 0, -4.1): pot cylinder (radius 0.45, height 0.8, top radius 0.5), soil disc, seven leaves as flattened spheres (scale 0.25 × 0.05 × 0.6) fanned on thin stems in leaf green. Beanbag at (2.9, 0, 1.9): squashed sphere radius 1 scaled (1, 0.6, 1) in lilac. Desk chair at (0.4, 0, -2.6): wood seat RoundedBox 1.1 × 0.15 × 1.1 at y 1.0, backrest 1.1 × 1.1 × 0.12, a single center cylinder post and a five-spoke base of thin boxes. Fairy lights: a catenary of 14 small spheres (radius 0.07) along the top of the right wall from x -4.6 to 4.6 at y ≈ 5.6 (sagging 0.25 between hooks), alternating butter, coral and screen glow colors, emissive only at night, each twinkling with its own phase (0.8–1.8 intensity, 2–3.5s).
   Layout: Lights. Day: hemisphereLight (sky #FFF4E6, ground #C9B8E8, 1.15), directionalLight #FFFFFF 1.7 at (8, 14, 6) casting shadows (mapSize 2048, shadow camera ±9, bias -0.0004, radius 4), ambientLight 0.25. Night: hemisphere lerps to (#3B4A8F, #1A1533, 0.35), directional lerps to #8FA8FF at 0.35 (moonlight through the window), lamp pointLight #FFC873 intensity 18, distance 9, decay 2, castShadow at the lamp head, and a monitor pointLight #7CE0D3 intensity 3, distance 3 just in front of the screen. All furniture casts and receives shadows; walls and floor receive.
   Motion: Plant sway, clouds/stars, fairy-light twinkle and dust motes as under Design motion.
4. **Interactive objects (the navigation)** — Five clickable groups, each wrapped in an <Interactive id> component that handles pointer over/out/click (stopPropagation), the hover lift, emissive highlight, label and cursor. 1) Bookshelf → About, label 'About me': against the left wall at (-4.4, 0, 3.0), body 1.0 deep × 4.0 tall × 2.4 wide in shelf blue with wood top and four shelves; books as boxes 0.18–0.32 wide and 0.6–0.95 tall in coral, butter, lilac, leaf, cream and ink, a few leaning 12 degrees, one stack lying flat; a tiny succulent and a small round clock (two ink hands, no numerals) on top. Focus target (-4.1, 2.2, 3.0), focus zoom ×2.1. 2) Desk set → Projects, label 'Projects': desk against the right wall at (0.4, 0, -4.1): wood top RoundedBox 3.4 × 0.16 × 1.6 at y 1.6, four darker legs; monitor on a short stand: RoundedBox 1.8 × 1.1 × 0.1 in #F3EEFF with a screen plane 1.64 × 0.94 using a CanvasTexture (512×294) of a code editor: #1E2238 ground, 12 rows of rounded bars of varying length and indentation in screen glow, coral, lilac and butter, a thin left gutter; a separate tiny cursor block plane that blinks. Plain keyboard slab (no logo, rows of tiny key bumps), a mug (cylinder + torus handle) in coral, a stack of two notebooks. The whole desk group is the clickable object. Focus target (0.4, 2.3, -4.0), zoom ×2.4. 3) Guitar → Music, label 'Music': a generic acoustic guitar leaning against the left wall near the back corner at (-4.5, 0, -3.4), rotated so its back rests on the wall at 14 degrees. Body: ExtrudeGeometry from a figure-eight Shape (two circles 0.55 and 0.68 radius blended with bezier waist) depth 0.28 with bevel 0.04, amber top, darker sides; dark sound hole disc; bridge bar; neck box 0.16 × 1.5 × 0.08 in dark wood with 5 thin fret lines; a plain trapezoid headstock with six tiny cylinder pegs, no logo or recognizable shape. Next to it a small amp cube 0.9 × 0.8 × 0.6 in ink with a woven grille square and two knobs. Focus target (-4.2, 1.6, -3.2), zoom ×2.3. 4) Mailbox → Contact, label 'Contact': mounted on the right wall at (3.6, 2.8, -4.7): a rounded-top box (box plus half-cylinder) 0.7 wide × 0.6 tall × 0.9 deep in shelf blue, a small door line, a coral flag on a thin post that flips up on hover, a white envelope corner peeking out. Focus target (3.6, 2.8, -4.4), zoom ×2.8. 5) Desk lamp → toggles night (no panel), label 'Lights on' / 'Lights off': on the desk at (1.7, 1.68, -4.4): round base, two-segment arm of thin cylinders with ball joints, cone shade in butter tilted toward the monitor, an inner bulb sphere with emissive lamp light. Clicking does not move the camera; it toggles night and plays a tiny 120ms press (shade dips 0.05).
   Layout: Camera focus math: keep the same view direction as home; proxy position = target + (20, 18, 20) × 0.5 offset normalized to the home direction; zoom = home zoom × factor. On desktop (panel open on the right, 440px wide) shift the target along the camera's screen-right vector (1, 0, -1)/√2 by (440 / 2) / zoom world units so the object sits in the center of the visible area left of the panel. On mobile shift the target along the camera up vector by (0.36 × innerHeight) / zoom so the object sits in the top third above the bottom sheet. Clicking empty space or the floor while focused closes the panel.
   Motion: Hover and focus behavior exactly as under Design motion. While focused, other objects are not hoverable except the lamp.
5. **Overlay UI: name chip, nav, switch and hint** — Top-left name chip: '[BRAND]' (Fredoka 600, 20px) over '[ROLE] · [LOCATION]' (Figtree 500, 13px, muted). Top-right: the HTML nav (buttons 'About', 'Projects', 'Music', 'Contact', each with a Lucide icon: UserRound, Monitor, Guitar, Mail) and the day/night switch (a 56 × 32 pill with a sliding thumb showing Lucide Sun or Moon, aria-label 'Turn the lights off' / 'Turn the lights on', role='switch', aria-checked). Bottom-left intro card (desktop only, max-width 360px, hidden while a panel is open): eyebrow 'PORTFOLIO, BUT IT'S A ROOM' (JetBrains Mono 500, 11px, letter-spacing 0.12em, coral), headline 'Hi, I'm [firstName]. I build [FOCUS].' (Fredoka 600, 28px, line-height 1.15), and a line 'Click anything in the room to look closer, or use the menu.' (Figtree 400, 15px, muted). Bottom-right hint chip (desktop, auto-hides after the first focus): Lucide MousePointerClick + 'Hover to explore · Esc to step back'.
   Layout: Overlay is a pointer-events-none layer with pointer-events-auto chips, inset 24px on desktop. Chips: panel surface (day #FFF9F2 at 94% / night #1B2047 at 92%), 12px backdrop blur, 1px hairline border, radius 999px for nav and switch, 20px for cards, shadow 0 10px 30px rgba(44,36,51,0.10). Nav buttons 40px tall, 14px horizontal padding, Figtree 600 14px, active (focused section) gets a coral fill with white text, hovered gets a hairline-tinted fill. On screens under 768px: the name chip stays top-left (16px inset), the switch top-right, and the nav becomes a fixed bottom bar (16px from the bottom, centered, 4 icon-over-label buttons 64px wide), the intro card and hint are hidden and a single line 'Tap an object to look closer' shows above the bottom bar until the first tap.
   Motion: Chips fade in after the intro. Nav hover syncs the 3D highlight. Visible focus rings: 2px coral (night: screen glow) offset 2px.
6. **Panel shell and routing** — One <Panel> component renders the active section. Header: eyebrow in JetBrains Mono (e.g. 'ABOUT', 'PROJECTS · 4', 'MUSIC', 'CONTACT'), title in Fredoka 600 32px, and a round 40px close button (Lucide X, aria-label 'Back to the room'). Below the content a footer row with 'Previous' and 'Next' text buttons (Lucide ChevronLeft/Right) cycling About → Projects → Music → Contact, which re-tween the camera to the next object without returning home. The URL hash mirrors focus (#/about, #/projects, #/music, #/contact; empty hash = room) and opening the page with a hash focuses that object after the intro. Escape closes; focus moves into the panel on open (the title, tabIndex -1) and back to the nav button that opened it on close. The panel is role='dialog' aria-modal='false' aria-labelledby the title.
   Layout: Desktop: fixed right panel, top 16px, right 16px, bottom 16px, width 440px, radius 24px, panel surface, padding 28px, content scrolls inside (thin custom scrollbar). Mobile: bottom sheet, left/right 8px, bottom 8px, height 72dvh, radius 24px top and 16px bottom, a 40 × 4 grab handle at the top (tapping it closes), padding 20px.
   Motion: Slide in/out as under Design motion; content inside fades up 8px with a 40ms stagger per block.
7. **About panel (bookshelf)** — Top row: portrait image (public/images/portrait.webp, 112 × 140, radius 18px, object-cover) beside the name '[BRAND]', role '[ROLE]', and a small availability pill with a pulsing leaf dot 'Booking two projects per quarter'. Bio: 'I'm a creative front-end developer in Portland, Oregon. For seven years I've been turning spreadsheets, sensor feeds and museum archives into things people can poke at. I lead front end at Hollowtree Labs, a four-person studio that builds exhibits for science centers, and on weekends I make small web toys nobody asked for.' Facts grid (2 × 2 cards, number in Fredoka 600 28px, label in Figtree 13px): '7 yrs' shipping front ends; '31' projects launched; '3' museum installs; '1' cat named Semicolon. Stack chips (JetBrains Mono 12px, hairline pills): TypeScript, React, three.js, GLSL, D3, Svelte, Figma, Node. Working shot image (public/images/desk.webp, full width, 4:3, radius 18px) with caption 'Most of this portfolio was built at that desk.' 'Now' list with Lucide icons: BookOpen 'Reading — a field guide to Pacific tide pools'; Sparkles 'Learning — raymarching in fragment shaders'; Hammer 'Building — a tiny synth that runs in a browser tab'.
   Layout: Single column inside the panel; 20px gaps between blocks; facts grid 2 columns with 10px gap; chips wrap with 6px gap.
   Motion: Availability dot pulses (scale 1 to 1.6, opacity 0.6 to 0, 2s loop; off under reduced motion).
8. **Projects panel (desk)** — Intro line: 'Four things I'm proud of. Tap a card for the details.' Four cards, each: a 16:10 code-drawn SVG thumbnail, name (Fredoka 600 20px), one-liner, role and metric in JetBrains Mono 12px, tech chips, and an expand toggle (Lucide ChevronDown rotating 180 degrees) revealing three detail bullets. 1) 'Tidepool' — 'A tide and swell planner for sea kayakers on the Oregon coast.' Role: design + build. Metric: 12k monthly paddlers. Chips: React, D3, Service Worker. Details: 'Offline-first so it works at the launch ramp with one bar of signal'; 'Tide curves redraw at 60fps as you scrub the day'; 'Built with two local paddling clubs over one winter'. Thumbnail: lilac ground, three layered sine waves (shelf blue, screen glow, white) and a coral dot riding the top wave. 2) 'Paper Orbit' — 'A touch-screen solar system for a children's science museum.' Role: lead developer. Metric: 40k visitors in its first season. Chips: three.js, GLSL, Kiosk mode. Details: 'Planets drawn as folded-paper shaders so they read from across the room'; 'Runs for 10 hours a day on a fanless mini PC'; 'Kids can fling moons; the physics forgive them'. Thumbnail: ink ground, four concentric ellipse orbits, butter sun, coral and leaf planets. 3) 'Quiet Hours' — 'A browser extension that batches notifications into three calm check-ins a day.' Role: solo maker. Metric: 4.8 rating from 2,300 installs. Chips: TypeScript, WebExtensions, IndexedDB. Details: 'Everything stays on your machine'; 'A weekly digest shows the hours you got back'; 'Open source, with 60 contributors'. Thumbnail: cream ground, five stacked rounded notification pills fading in opacity, a butter moon in the corner. 4) 'Glyph Garden' — 'A playground for testing variable fonts by growing them.' Role: side project. Metric: featured in two type newsletters. Chips: Svelte, Canvas, Variable fonts. Details: 'Drag a slider and the letters sprout weight and width'; 'Exports a specimen sheet as SVG'; 'Started as a weekend experiment, still maintained'. Thumbnail: butter ground, a large 'Aa' in Fredoka 600 in ink with a leaf-green sprout curling from the a.
   Layout: Cards stack vertically with 14px gap; card radius 18px, hairline border, 14px padding; thumbnail full width radius 12px; details animate height (CSS grid-rows 0fr to 1fr, 300ms).
   Motion: Card hover: translateY(-2px) and shadow deepens (no lift under reduced motion). Thumbnails have one subtle loop each (wave offset drift, orbit rotation 30s) paused under reduced motion.
9. **Music panel (guitar)** — Header block: 'Low Tide Radio' as the alias ([MUSIC_ALIAS], Fredoka 600 26px), line 'Lo-fi instrumentals I record on the guitar in the corner, mostly after midnight.' EP card: a CSS-drawn record (320px max, radial-gradient grooves in ink, coral label circle with the alias initials in Fredoka) beside 'Desk Weather · EP', '6 tracks · 21 min'. Player: current track title, elapsed / total in JetBrains Mono, a progress bar (coral fill on hairline track, clickable to seek), controls Lucide SkipBack, Play/Pause (56px coral circle), SkipForward, Lucide Repeat toggle. Track list (click to play): 1 'Sunday Compiler' 3:12; 2 'Low Battery Lullaby' 2:48; 3 'Window Seat (Demo)' 4:05; 4 'Kettle On' 2:31; 5 'Night Build' 5:02; 6 'Soft Reset' 3:40 — current row gets a lilac tint and three animated equalizer bars. Note under the list in muted 13px: 'Audio files aren't bundled in this build, so the player runs silently.' No audio element, no external embeds.
   Layout: EP card is a 2-column grid (record 132px / text) on desktop and stacked on mobile; track rows 44px tall with number, title, duration right-aligned.
   Motion: The player is a real timer: elapsed advances once per second while playing, auto-advances to the next track (or repeats). Record spin, equalizer bars and room music notes run only while playing and not under reduced motion.
10. **Contact panel (mailbox)** — Intro: 'I'm booking two client projects per quarter: museum exhibits, data stories, and launch pages with a bit of play in them. Email is fastest; I reply within two working days.' Four rows, each a hairline card with a Lucide icon, label (Figtree 500 13px muted), value (JetBrains Mono 15px) and a Copy button (Lucide Copy, swaps to Check for 1.6s): Mail 'Email' → email ([email protected]); Code2 'Code' → codeUrl; NotebookPen 'Notes' → notesUrl; MapPin 'Based in' → '[LOCATION] · working remotely'. Copy uses navigator.clipboard.writeText inside try/catch with a hidden-textarea fallback, then shows a toast 'Copied to clipboard' (bottom center, 1.8s). Below: 'Office hours: Tue & Thu, 9am–1pm local time' and a mailto button 'Write an email' (coral, Lucide Send). No form.
   Layout: Rows stack with 10px gap; each row is a 3-column grid (icon 36px / label+value / copy button 36px); value truncates with ellipsis on narrow screens.
   Motion: Copy icon cross-fades to Check; toast slides up 12px and fades (opacity only under reduced motion).

## Assets
- image: Two template photos made for this design (AI-generated fictional person, redistributable with the template). Download each with curl -L -o into public/images/ before the first build: https://media.vibefather.ai/assets/792508cf-aec9-4dc1-96e2-a2e170c43946/portrait.webp → public/images/portrait.webp (About panel top row; object-position 50% 30%; alt '[BRAND] looking out of a window in a softly lit home studio'); https://media.vibefather.ai/assets/792508cf-aec9-4dc1-96e2-a2e170c43946/desk.webp → public/images/desk.webp (About panel working shot; alt '[BRAND] working at a light oak desk by the window'). Credit both as 'Generated by VibeFather with qwen-image-3.0-pro, redistributable with this template'. They are placeholders the owner swaps for their own photos.
- image: Everything else is drawn in code: the room, furniture, guitar, lamp and plant from three.js primitives; the monitor code screen and both wall artworks as CanvasTexture drawn at runtime; project thumbnails and the record as inline SVG/CSS; clouds and stars as small meshes or points. No model files, textures, HDRIs or stock images.
- icon: lucide-react (ISC) for every UI icon: UserRound, Monitor, Guitar, Mail, Sun, Moon, X, ChevronLeft, ChevronRight, ChevronDown, MousePointerClick, BookOpen, Sparkles, Hammer, SkipBack, Play, Pause, SkipForward, Repeat, Copy, Check, Code2, NotebookPen, MapPin, Send. No brand icons. public/favicon.svg: a 32×32 rounded square in #F08A6B with a tiny cream isometric cube outline.
- font: @fontsource-variable/fredoka, @fontsource-variable/figtree and @fontsource/jetbrains-mono (400, 500), all OFL-1.1, imported in src/fonts.ts. drei <Html> labels use the same CSS fonts; no 3D text, so no font JSON files are needed.
- image: Write ASSETS.md at the project root with a table (path, source URL, author, license): one row per photo (source the media.vibefather.ai URL above, author 'VibeFather (qwen-image-3.0-pro)', license 'Redistributable with this template'), rows for the three Fontsource packages (OFL-1.1) and lucide-react (ISC), and a line stating that all 3D geometry, textures, thumbnails and art are code-drawn.

## Don'ts
- No backend, API routes, databases, auth or form submission; contact is copy-to-clipboard plus a mailto link only.
- No audio files, audio streaming or third-party embeds of any music or video service; the music player is a silent timer UI.
- No external 3D models, baked textures, HDRIs or Blender files: build every object from three.js primitives and code-drawn CanvasTextures; do not copy any published room portfolio's model, layout or furniture arrangement.
- No character avatars, mascots, pets as 3D figures or drivable vehicles in the scene.
- No real brand logos or recognizable product designs on any object: plain monitor, plain keyboard, generic guitar headstock, no consoles, sneakers or branded gear.
- No real posters, album covers, game or anime artwork; wall art is code-drawn abstract shapes only.
- No real artist names, real song titles or copyrighted music anywhere; all tracks and the alias are invented.
- The portrait and desk photo show a fictional AI-generated person only, never a real person's likeness.
- No copy, slogans or section names lifted from any existing portfolio; write all copy fresh in US English.
- Self-host everything: fonts through Fontsource npm packages, icons through lucide-react, images downloaded into public/images/. No CDN <script> or <link> tags, no Google Fonts, no analytics.
- No commercial fonts and no restricted UI library source (Aceternity UI, Tailwind Plus / Tailwind UI); write the overlay components yourself.
- Production build with one command (npm run build) to dist/: minified, no source maps, relative asset paths (Vite base './'), no src/ copied into dist/, dist/ under 10 MB.
- Single page: every internal link is ./index.html or a hash route (#/about, #/projects, #/music, #/contact); never link to a bare directory.
- No page scroll on the stage; only panel content scrolls. No OrbitControls or free camera; the camera only moves through the focus tweens.
- Must work at 1440×900 and 390×844 with zero console errors; every section is reachable by keyboard through the HTML nav, Escape closes panels, focus rings are visible.
- Respect prefers-reduced-motion: instant camera cuts and day/night switch, no intro, bob, sway, particles, notes or spinning record.
- Wrap every localStorage read and write (night mode, last track) in try/catch; the site must work with storage blocked.
- Never mention VibeFather or any other brand inside the site except the optional credit footer link; no dates or years in the copy.

---
— Prompt by VibeFather · https://vibefather.ai/t/isometric-3d-room-portfolio · 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: "Isometric 3D Room Portfolio"
colors:
  day_backdrop_top: "#FDE8D7"
  day_backdrop_bottom: "#E4E0F6"
  night_backdrop_top: "#121836"
  night_backdrop_bottom: "#2B2459"
  wall_left_day_night: "#F6E6D3 / #3A3F6E"
  wall_right_day_night: "#EFD7C0 / #30355F"
  floor_day_night: "#D8B28C / #3C3452"
  rug: "#9DCBB6"
  wood: "#C98D5E"
  shelf_blue: "#8FA7D6"
  coral: "#F08A6B"
  butter: "#FFD27A"
  lilac: "#C8B6FF"
  guitar_amber: "#E9A23B"
  leaf: "#6FAF7E"
  screen_ink: "#1E2238"
  screen_glow: "#7CE0D3"
  lamp_light: "#FFC873"
  panel_day: "#FFF9F2"
  panel_night: "#1B2047"
  ink: "#2C2433"
  ink_muted: "#6E6475"
  night_text: "#F3EEFF"
  hairline: "#EADBCB"
typography:
  display_name_chip_panel_titles_hover_labels_intro_line: { family: "Fredoka (Fontsource variable)", weights: [500, 600] }
  text_bios_card_copy_buttons_nav: { family: "Figtree (Fontsource variable)", weights: [400, 500, 600] }
  mono_eyebrows_stack_chips_track_durations_contact_values: { family: "JetBrains Mono (Fontsource)", weights: [400, 500] }
spacing: "Overlay inset 24px desktop / 16px mobile. Panel padding 28px desktop / 20px mobile, 20px gaps between panel blocks, 10–14px gaps inside lists. 4px base scale (4, 8, 10, 12, 14, 16, 20, 24, 28, 40)."
radius: "Overlay pills 999px; panels 24px; cards and images 18px; thumbnails 12px; 3D RoundedBox radius 0.06–0.12 world units so everything looks soft and toy-like."
---

# Isometric 3D Room Portfolio — 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
- **Day backdrop top** `#FDE8D7` — Top stop of the daytime page gradient behind the canvas (peach).
- **Day backdrop bottom** `#E4E0F6` — Bottom stop of the daytime page gradient (lavender).
- **Night backdrop top** `#121836` — Top stop of the night gradient.
- **Night backdrop bottom** `#2B2459` — Bottom stop of the night gradient.
- **Wall left day / night** `#F6E6D3 / #3A3F6E` — Left wall (x = -5 plane) day and night colors.
- **Wall right day / night** `#EFD7C0 / #30355F` — Right wall (z = -5 plane), slightly darker than the left wall.
- **Floor day / night** `#D8B28C / #3C3452` — Floor slab top; floor edge/sides use #B98F69 / #2A2440.
- **Rug** `#9DCBB6` — Round rug; night tone #4A6B78.
- **Wood** `#C98D5E` — Desk top, bookshelf frame edges, picture frames, chair seat; darker wood #A26C43 for legs.
- **Shelf blue** `#8FA7D6` — Bookshelf body and the mailbox body.
- **Coral** `#F08A6B` — Primary accent: mailbox flag, active nav item, play button, CTA buttons, focus ring in day mode.
- **Butter** `#FFD27A` — Lamp shade, book spines, music note particles.
- **Lilac** `#C8B6FF` — Book spines, beanbag, project thumbnail tints.
- **Guitar amber** `#E9A23B` — Guitar body top; sides and back #B86B2A, neck #7A4A2A.
- **Leaf** `#6FAF7E` — Plant leaves; pot #E7C9B0.
- **Screen ink** `#1E2238` — Monitor screen background and night panel text on light chips.
- **Screen glow** `#7CE0D3` — Code bars on the monitor, monitor point light at night, night-mode focus ring.
- **Lamp light** `#FFC873` — Lamp point light and fairy-light emissive color at night.
- **Panel day** `#FFF9F2` — Panel and chip surfaces in day mode (at 94% opacity with 12px backdrop blur).
- **Panel night** `#1B2047` — Panel and chip surfaces in night mode (at 92% opacity with 12px backdrop blur).
- **Ink** `#2C2433` — Primary text in day mode.
- **Ink muted** `#6E6475` — Secondary text in day mode; night secondary text is #A9A6CC.
- **Night text** `#F3EEFF` — Primary text in night mode.
- **Hairline** `#EADBCB` — Day borders and dividers; night borders #343B72.

## Typography
- **Display: name chip, panel titles, hover labels, intro line** — Fredoka (Fontsource variable) (OFL), weights 500/600. Self-host the font files.
- **Text: bios, card copy, buttons, nav** — Figtree (Fontsource variable) (OFL), weights 400/500/600. Self-host the font files.
- **Mono: eyebrows, stack chips, track durations, contact values** — JetBrains Mono (Fontsource) (OFL), weights 400/500. Self-host the font files.

## Spacing & shape
- Spacing: Overlay inset 24px desktop / 16px mobile. Panel padding 28px desktop / 20px mobile, 20px gaps between panel blocks, 10–14px gaps inside lists. 4px base scale (4, 8, 10, 12, 14, 16, 20, 24, 28, 40).
- Radius: Overlay pills 999px; panels 24px; cards and images 18px; thumbnails 12px; 3D RoundedBox radius 0.06–0.12 world units so everything looks soft and toy-like.

## Motion
- One shared state store drives everything: { focus: null | 'about' | 'projects' | 'music' | 'contact', hovered: string | null, night: boolean, playing: boolean, trackIndex: number }. Hovering an HTML nav item sets hovered to the same id as hovering the 3D object, so both highlight together.
- Easing: GSAP 'power3.inOut' for camera moves, 'power2.out' for hover lift, 'back.out(1.6)' for the intro drop-in. CSS transitions use cubic-bezier(0.22, 1, 0.36, 1).
- Intro (once on load): the room group rises from y -1.2 to 0 and scales 0.92 to 1 over 1.2s power3.out; then the interactive objects (bookshelf, desk set, guitar, mailbox, lamp) drop from y +1.5 into place with a 70ms stagger, 0.6s back.out(1.6). The overlay chips fade in 300ms after.
- Idle life: the room group bobs y ±0.06 on a 6s sine; the plant's leaf group sways ±0.05 rad on a 3.4s sine; 40 dust motes (drei Sparkles, size 2.5, speed 0.25, opacity 0.5, color #FFFFFF by day and #FFC873 by night) drift inside the room volume; the monitor cursor block toggles visibility every 530ms; by day two code-drawn clouds slide across the window sky plane (loop 40s), by night 30 star points twinkle.
- Hover (pointer devices only): object group lifts y +0.15 over 0.25s power2.out, every mesh in it gets emissive #FFFFFF at intensity 0.16 (night: emissive #FFC873 at 0.22), cursor becomes pointer, and a drei <Html> label (pill, Fredoka 500 15px) appears 0.5 units above the object, fading and rising 6px over 180ms. The mailbox flag also rotates up 70 degrees; the guitar tilts 3 degrees.
- Focus: GSAP tweens a proxy { px, py, pz, tx, ty, tz, zoom } over 1.1s power3.inOut; every frame the orthographic camera is placed at proxy position, looks at the proxy target and applies proxy zoom with updateProjectionMatrix(). The panel slides in from the right (desktop: translateX(100%) to 0 over 450ms, starting 350ms into the camera move) or up from the bottom (mobile). Back/close or Escape reverses both, panel first, then camera home.
- Day/night: GSAP tweens a single nightMix value 0 to 1 (or back) over 0.9s power2.inOut; every frame each themed material lerps between its day and night color (THREE.Color.lerpColors), light intensities lerp between their day and night values, and the two backdrop gradient layers crossfade by opacity. The lamp head bulb's emissive intensity goes 0 to 2.5, the lamp point light 0 to 18, fairy lights 0 to 1.8. The UI switch thumb slides 24px and its icon swaps sun/moon with a 90-degree rotate.
- Music playing: the record disc in the Music panel spins (360 degrees per 2.4s, linear), the progress bar advances in real time, and in the room three small butter-colored music notes (code-drawn planes) float up from the amp and fade over 2.2s, looping with 0.7s offsets.
- prefers-reduced-motion: camera moves and the day/night change become instant (duration 0), no intro, no bob, no sway, no Sparkles, no floating notes, no record spin, panels appear without sliding (opacity only, 120ms). Hover keeps the emissive highlight and label but no lift.

## Imagery
The hero is the 3D room itself, a dense, polished diorama that fills the first screen, so there is no hero photo. Everything in the scene is modeled from code primitives (drei RoundedBox, boxes, cylinders, spheres, THREE.ExtrudeGeometry from 2D shapes) with flat meshStandardMaterial (roughness 0.85, metalness 0) and soft shadows. Wall art, the monitor screen and project thumbnails are code-drawn (CanvasTexture or inline SVG) as abstract shapes in the palette: no real posters, album covers, logos or readable brand marks anywhere. The only photographs are two AI-generated images of the fictional owner inside the About panel (a head-and-shoulders portrait and an over-the-shoulder desk shot), both in the same muted pastel peach-and-lavender grade as the room.

## Tone
Warm, playful and precise: a tidy toy diorama with honest, specific copy written in the first person. Short sentences, concrete numbers, no buzzwords.

---
— Prompt by VibeFather · https://vibefather.ai/t/isometric-3d-room-portfolio · CC BY-NC 4.0 (non-commercial; commercial use needs a VibeFather Pro license) · Request removal: https://vibefather.ai/takedown