Files
furniture/CLAUDE.md
T
2026-10-17 12:09:36 -04:00

3.8 KiB

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

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.