# Furniture Optimizer (hackathon project) A web tool for venues (events, banquets, conferences) to lay out furniture in a room and, eventually, auto-optimize the layout. ## Current scope: Phase 1 (UI only) The ONLY feature right now is drag-and-drop layout: - Left palette with two source tiles: chair and table. - Large rectangular room on the right (fixed 10m x 8m, drawn to scale, 1m = 60px, faint 0.5m grid). - Click (no drag) a palette tile to open a settings menu for that furniture type: - Available: how many of that type the venue has (number stepper, min = number already placed). - Tables only: Seats per table (number stepper, min 1). - Palette tiles show a badge with remaining count (available minus placed). - Drag a tile into the room to create an item. The tile stays in the palette. If remaining is 0, the tile is greyed out and can't be dragged. - Distinguish click from drag with a small movement threshold (about 5px). - Drag existing items to move them. Items are clamped inside the room walls. - No overlap allowed. Invalid position = red outline while dragging; on drop, snap back to last valid position (or cancel the add if new). - Snap to the 0.5m grid on drop. Do not build anything beyond this unless asked. Do not design in a way that blocks the roadmap below. ## Tech stack - React + TypeScript, Vite - react-konva (Konva) for the canvas - State: single top-level store (useState/useReducer). Keep it centralized so an optimizer can read and write it later. ## Data model ```ts type FurnitureType = "chair" | "table"; interface FurnitureItem { id: string; type: FurnitureType; x: number; // meters, top-left, room coordinates y: number; width: number; // meters height: number; rotation: number; // degrees, always 0 for now locked: boolean; // always false for now, reserved } interface Room { width: number; height: number; } // meters // Per-type settings, edited via the palette menu interface FurnitureTypeConfig { type: FurnitureType; available: number; // inventory count seatsPerUnit?: number; // tables only: people who can sit at one } // remaining = available - items.filter(i => i.type === type).length ``` Seats per table is a type-level setting for now (applies to all tables). Per-table overrides come later. Chairs and table seats are independent for now. Default sizes: chair 0.5 x 0.5 m, table 1.8 x 0.8 m. ## Conventions - Store everything in meters. Convert to pixels only at render time (one `PX_PER_M` constant). - Collision = axis-aligned bounding boxes. Keep collision and clamping logic in pure functions (no React or Konva imports) so the optimizer can reuse them. - Keep geometry/rules logic separate from rendering components. - Small, typed, readable code. No new dependencies without a good reason. - Keep the UI minimal: light grey app background, room centered in the remaining space. ## Roadmap (not built yet, don't block) Venue-focused features planned for later phases: - Furniture inventory: set X amount of each furniture type - Semi-custom furniture: couches, chairs, tables of any size and seating count - Room import - Furniture placement rules - Locking furniture in place - Custom seating limits (per table or global) - Optimizers for: room loading/unloading flow, screen visibility, max comfort, max table access - Optimization approach idea: user-set rule priorities, possibly a neural net with weights and biases to score "optimal placements" (undecided; start with hard constraints like no overlap, then weighted scoring) - Input ideas: phone scanning of a room, manual entry ## Commands ``` npm install npm run dev # start dev server npm run build # production build npx tsc --noEmit # type check ``` ## Working agreement - Ask before expanding scope past Phase 1. - After changes, make sure the app builds and type checks. - Hackathon pace: prefer simple and working over clever.