Skip to content

KaiSong06/Cursor-for-ID

Repository files navigation

Stage — Interior Design Generator

A weekend hackathon demo: describe your room → AI asks clarifying questions → streams a furnished mid-century-modern living room in 3D → refine conversationally → buy the pieces from real stores.

Built on React 19 + Vite + R3F 9.5 + Fastify + @google/genai (Gemini 2.5 Flash) with editorial warm chrome (Fraunces + Inter, OKLCH palette) and a priority-tier-aware cinematic camera reveal.

Quick start

# 1. Install
npm install

# 2. Set up environment
cp .env.example .env
# Edit .env and set GEMINI_API_KEY=<your key from https://aistudio.google.com/app/apikey>
# Enable Cloud Billing on the GCP project to unlock Tier 1 (150 RPM).

# 3. Run dev (starts Fastify on :3000 + Vite on :5173)
npm run dev

# 4. Open the demo
open http://localhost:5173

Without a GEMINI_API_KEY, the server falls back to the golden cache in public/cache/golden/*.json, so the demo runs end-to-end with zero API cost. The cache is real curated content, not a stub — so use it freely while iterating on UX.

Demo mode (kiosk + scripted)

VITE_DEMO_MODE=1 npm run dev

In demo mode:

  • Free-text prompt is replaced with a single "Stage this room" button
  • Q&A overlay can't be dismissed (Escape and click-outside are blocked)
  • Cmd+Shift+C forces the cache replay path (presenter escape hatch)
  • Cmd+Shift+R reloads the demo to the start state
  • Errors are swallowed silently into a hidden window.__telemetry buffer
  • beforeunload blocks accidental navigation

The locked demo viewport is 1440×900.

Architecture

src/
├── client/                          # React 19 + R3F frontend
│   ├── components/
│   │   ├── scene/                   # 3D scene: Canvas, Room, Lighting, Furniture, CameraRig
│   │   ├── overlay/                 # PromptInput, QAOverlay, RoomOutlineIntro, RefineButton
│   │   └── shell/                   # ChatRail, SidePanel, Tagline, ShopLookButton
│   ├── hooks/                       # useStreamingScene, useCameraChoreography, useFallbackCache
│   ├── lib/                         # sse-client, scene-state reducer, demo-mode installer
│   └── styles/                      # tokens.css (OKLCH), typography.css (Fraunces+Inter)
├── server/                          # Fastify backend
│   ├── routes/                      # POST /api/session, GET /api/design/stream (SSE)
│   ├── gemini/                      # @google/genai pipeline + schemas + system prompts
│   ├── merge/                       # JSON Merge Patch enforcer + scripted-target resolver
│   ├── autofix/                     # Pure-logic post-processing (snap, nudge, clamp, validate)
│   └── cache/                       # Golden cache loader + per-session state
└── shared/                          # Types + catalogue, imported from both halves
    ├── catalogue.ts                 # CatalogueItem type + 14-piece MCM CATALOGUE constant
    ├── scene.ts                     # SceneState, Piece, ROOM dimensions
    └── events.ts                    # SSE payload types

public/
├── cache/golden/                    # phase1.json, phase2.json, refinement.json (committed)
├── models/                          # Normalized GLB files (drop downloads here)
└── shop.html                        # Generated by `npm run build:shop`

Furniture catalogue

The demo ships with 14 mid-century-modern pieces in src/shared/catalogue.ts. Each entry has:

  • A primitive geometry description (Three.js box / cylinder shapes) used by default — so the demo runs end-to-end without any GLB files.
  • An empty glb_url slot ready to drop in a real GLB.

Adding real Poly Haven assets

  1. Browse https://polyhaven.com/models/furniture and download the GLBs into assets/raw/. Use the catalogue id as the filename (e.g. assets/raw/sofa_mcm_01.glb).

  2. Run normalization (recenters to floor + XZ centerline; no Blender needed):

    npm run normalize-assets
  3. Update each entry's glb_url in src/shared/catalogue.ts:

    glb_url: "/models/sofa_mcm_01.glb",
  4. Restart npm run dev. The <FurnitureItem> renderer prefers the GLB but falls back to the primitive on load failure.

Pre-warming the golden cache

Once the live Gemini path works, capture a known-good run for demo reliability:

GEMINI_API_KEY=<key> npm run prewarm-cache

The script:

  1. Calls Phase 1 with the scripted prompt
  2. Runs Phase 2 streaming with the scripted answers (no TV / evening / solo)
  3. Runs auto-fix + asserts ≥6 items + ≥1 anchor
  4. Runs the scripted refinement and asserts a non-empty diff
  5. Writes all 3 artifacts to public/cache/golden/*.json

Re-run until you get a layout you like — the cache files are committed to git so the presenter laptop has a known-good run.

Scripts

npm run dev               # Both servers in dev mode
npm run build             # Production client + server build + shop.html
npm run typecheck         # Both client + server tsc passes
npm test                  # Vitest (auto-fix + enforcer suites)
npm run normalize-assets  # Recenter Poly Haven GLBs in assets/raw/
npm run prewarm-cache     # Capture a fresh golden cache (needs GEMINI_API_KEY)

Demo flow (60–75s)

  1. Intro Open → 2-second SVG room outline draws itself
  2. Prompt Click "Stage this room"
  3. Q&A Three clarifying questions (TV / lighting / use)
  4. Reveal Streaming Phase 2 — sofa lands first (anchor camera lock), then primary, accent, decor in order
  5. Pull-back Camera pulls back to a hero overview
  6. Refine Click "Face the reading chair toward the bookshelf" — only the reading chair rotates, every other piece stays put
  7. Buy Click any item's Buy link, or "Shop this look" for the full list

License

Hackathon code, no formal license. Real retailer URLs are not affiliate links. 3D primitives are MIT-equivalent. If you wire in real Poly Haven GLBs, they're CC0; Sketchfab assets require attribution (see AttributionsModal).

About

Hack Dartmouth - Best use of Gemini + 5th Overall

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors