A web app for building 2D floor plans from measurements. Start a new plan, an origin is placed at (0, 0), and you build out rooms by typing in real-world measurements — the plan draws itself as you go.
Live site: https://smiry039.github.io/floorplan-mapper/ — works on mobile.
- Origin-based canvas with pan, zoom, a real-world metric grid, and a fit-to-plan button.
- Two ways to create rooms:
- Rectangle — type width × length, click to drop it.
- Walk the walls — stand at a corner and enter each wall's length + compass
direction. The polygon builds one wall at a time, so non-rectangular rooms
work too. Closing the loop reports the final wall length so you can sanity-check it.
- Complete as rectangle — after just two walls, square the room off in one click (assumes right angles) for quick room-by-room mapping.
- Snap to existing geometry — the start point (and each corner) snaps to existing room corners, doors and windows, so a new room can begin exactly off a neighbouring one.
- Note doors/windows mid-walk — drop a door or window on any wall as you go, with precise placement (anchor to either corner + width); they're baked into the room when you close it.
- Doors & windows — click a wall to place one; set its width and anchor
distance from either corner (with a live
↤ d1 · width · d2 ↦readout), plus hinge and swing. Doors render with a swing arc, windows as glazing. Selecting an opening shows its anchor dimensions right on the wall. - Shared (party) walls — rooms stay as polygons, but the scene is rendered
from a derived wall model (
src/lib/wallModel.ts) that merges every room edge lying on the same line into single wall segments (handling full and partial overlaps). Each wall owns the openings of all rooms on it, so a shared wall is drawn once, labelled once (X · shared), and a door/window punched into it clears both rooms. The scene draws in type layers (fills → walls → openings → labels) so no room ever paints over another's walls or openings. - Live dimensions — every wall is labelled with its length; every room shows its name and area.
- Editing — select rooms, drag to move, drag corners to reshape, recolour, rename, delete.
- Undo / redo, autosave to the browser, and JSON / PNG export (+ JSON import).
- Units — metric today, with a working imperial (ft/in) toggle already wired in.
- Dedicated mobile UI — below 760px a separate phone shell renders (not a reflow of the desktop): a compact header, a full-height canvas that's never covered, a slim contextual dock below it (e.g. a one-row direction strip + length + Add for walking walls), and clean bottom tabs (Select / Room / Walls / Openings). The canvas supports pinch-to-zoom, one/two-finger pan, and tap-to-place with finger-sized hit targets.
npm install
npm run devThen open the URL Vite prints (it tries to open automatically). Build a static
version with npm run build and preview it with npm run preview.
src/
types.ts Domain model (FloorPlan / Room / Opening), all geometry in meters
lib/
geometry.ts Vector & polygon math, compass bearings, snapping
units.ts Metric/imperial formatting + length parsing
view.ts World <-> screen transform
wallModel.ts Derives merged (shared) walls + resolved openings from rooms
io.ts JSON import/export, PNG raster export
id.ts id generation
store/planStore.ts Zustand store: document state, tools, selection, undo/redo
components/
Canvas.tsx SVG canvas: grid, pan/zoom, draft, all pointer interactions
PlanScene.tsx Renders the document in type layers from the wall model
OpeningPositionEditor.tsx Width + anchor-from-corner editor (draft & selected)
LengthField.tsx Unit-aware length input
Toolbar.tsx Tools, units, new/open/save/export
Sidebar.tsx Tool panels + selected-room/opening properties
WallWalker.tsx The measurement-entry panel for walking walls
World units are meters, origin at (0, 0), +x = east, +y = north.
Rendering flips the y-axis so north points up. Compass bearings are measured
clockwise from north (0° = N, 90° = E).
- Editable shared walls: dragging a shared wall (or a corner on it) should move both rooms together. Shared walls are now rendered as one (merged wall model) and openings are shared, but each room still owns its own vertices — so editing a shared wall only moves one side. Linking the vertices is the next step, plus wall thickness (double-line walls).
- Furniture / fixtures library with drag-and-drop.
- Angled & curved walls, measurement constraints, auto-closing helpers.
- Multi-floor plans and a scale/legend on export.
- Down the line: import from 3D scans / NeRFs.