Interior-design playground built with Vue 3 + TypeScript + Fabric.js v6: upload a photo of a room, drag furniture onto it, repaint walls, preview floor textures, measure real distances, and save or export the result — entirely client-side.
- Room photo canvas — upload any photo (downscaled to 1920 px), fit-contain background
- Furniture library — 8 bundled SVG items + your own PNG uploads, drag & drop, resize/rotate, layers panel, z-order, opacity, shadows
- Wall paint — outline a wall polygon, pick a color;
multiply/soft-lightblends keep the photo's shadows and texture visible through the paint - Floor textures — outline the floor, choose wood/marble/tile/vinyl; scale, rotation and skew sliders fake the perspective recede
- Measure & calibrate — mark a span of known length once, then measure anything in meters; recalibrating rewrites existing labels
- Undo/redo — 50 steps of serialization snapshots; masks, background swaps and deletes all round-trip
- Save/load — projects persist to localStorage with thumbnails; uploaded images externalized to an asset registry
- Export — PNG / JPEG / PDF at 1×, 2× or native photo resolution, cropped to the photo, overlays excluded
- Ergonomics — zoom-to-cursor, space-drag pan, alignment snap guides, grid, full keyboard map (Del, arrows,
[], Ctrl+Z/Y/S)
npm install
npm run dev # Vite dev server
npm run build # typecheck + production build
npm run test # vitest unit testsThe Fabric Canvas lives as a plain module variable in src/services/fabricService.ts and is the single source of truth for object state — it never enters Vue reactivity (Vue Proxies break Fabric internals). Data flows one way: components call service functions → Fabric mutates and fires events → a single bridge in useCanvas.ts projects read-models into Pinia stores → the UI re-renders. Undo/redo and save/load share one serializeScene/applyScene pair, with uploaded images externalized to asset:// references so snapshots stay small. Grid, snap guides and measurements are overlays that never enter history, saves or exports.
Full decision log in DECISIONS.md; build plan and per-phase acceptance criteria in PLAN.md.
- True floor perspective via homography (canvas patterns can't do projective transforms — WebGL would)
- IndexedDB storage for bigger photos
- SVG furniture as
loadSVGFromURLgroups for infinite-resolution scaling
