Dream Home Designer
A browser home-design tool that pairs a floor-plan editor with a Florida ownership-cost estimate, so a buyer sees the monthly number beside the layout.
- 1,149
- tests behind the model and app
- 8
- migrations applied to the production database
- 8
- starter homes, four of them Central Florida plans
- 01Interface
- TypeScript (strict)
- React 18 + Vite
- three.js via react-three-fiber
- 02Edge
- Cloudflare Pages + Pages Functions
- Cloudflare D1
- Cloudflare R2
- 03Application
- Anthropic API
- 04Intelligence
- Leonardo AI
- 05Operations
- vitest + Testing Library
- 06Supporting
- zustand
- Immer
Dream Home Designer holds live data, so this shows the verified technology stack by layer rather than a screenshot. Layers, not connections — which service calls which is not something a dependency list can prove. Hosts, ports and topology are deliberately absent.
Problem
A buyer deciding what to build or renovate is working with two disconnected things: a floor plan that says nothing about money, and a payment calculator that says nothing about the house. Generic floor-plan apps stop at geometry. They will happily let someone add three hundred square feet without ever surfacing what those feet cost to own, and the mortgage calculators that would answer it know nothing about the drawing. So the question that actually decides the purchase, what this specific layout costs every month in this specific county, gets answered in a different tab or not at all.
In Florida that gap is wider than it sounds, because the two largest variable costs, property tax and insurance, both swing hard by county rather than by state. A payment estimate that averages them is not a rounding error, it is the wrong number. The repo names the county-resolved ownership estimate as the tool's actual differentiator over any generic floor-plan app, and the build treats it that way: the monthly figure sits beside the plan, not behind a separate calculator.
What was built
Underneath everything is a pure-TypeScript home model with no React, no three.js and no store imports, so the entire correctness surface stays unit-testable in isolation. Walls are a planar straight-line graph supporting weld, split and join, with doors and windows placed as 1D parametric openings along a wall rather than as free-floating objects. Rooms are never stored as polygons: they are detected fresh from the wall graph on every change. Every mutation funnels through a single dispatch surface built on Immer's produceWithPatches, which is what makes undo, redo, an audit trail and AI-driven edits fall out of one mechanism instead of four. Above that sits a 2D SVG editor, a lazy-loaded 3D view, and a Cloudflare Pages Functions backend over D1 and R2 for accounts, sync, sharing and the AI endpoints.
Technical approach
The interesting decision is what the model refuses to store. Room geometry is derived, never persisted: a half-edge face trace recomputes rooms from the wall graph on every change and discards the unbounded exterior face. Room identity is persisted separately and re-matched across edits by a boundary signature, so a room keeps its name and finishes even after the walls around it move. Splitting the two is what stops a single wall drag from silently orphaning everything attached to a room, and the spec is explicit that a room is one or the other, never both.
Walls are a planar straight-line graph with weld, split and join operations, and openings are the same idea applied one dimension down: a door is a parametric position along a wall rather than a free-floating object with its own coordinates. That means moving a wall carries its openings automatically instead of leaving them behind in space.
The second constraint is a performance invariant stated in the strongest terms the repo uses anywhere: room detection must never run inside a pointermove. Gesture edits go through begin, update and commit with detection skipped, and the full face trace runs once on commit, because putting it back in the drag path is described as the single biggest performance regression available in this codebase.
Holding all of it together is a deliberate dependency rule. The model layer imports no React, no three.js and no store, so every geometric and financial claim is unit-testable without mounting anything. The schema is a frozen v1 contract, extendable by adding sibling collections but never by redesigning or repurposing an existing field.
Creative approach
Craft
The interface commits to one metaphor, the homeowner's drafting sheet, and then takes the vernacular seriously rather than decoratively: real title blocks, sheet numbers in the architectural style, and an inspector panel laid out like a schedule table instead of a properties sidebar. The ground is warm vellum rather than the dark grey that CAD tooling defaults to, which is a deliberate choice about audience: this is read by someone imagining a house, not by a drafter at work.
Gold carries selection and primary actions and nothing else. That restriction came out of a measured failure rather than taste. Paper-white on gold tested at 2.4:1, well under the accessible threshold, so gold was confined to states where it never has to carry text.
Reframe
The first-visit experience was rebuilt after walking the live site as a stranger rather than as its author, which is a different exercise from testing it. Everything worked; it just asked for things too early.
The email capture had been firing on arrival, before the visitor had done anything worth capturing, which inverts the trade: it spends the one moment of goodwill a new visitor has on a request rather than on showing them something. It now waits for three edits or two minutes, so the ask arrives after the tool has demonstrated it is worth an address. The generic product tour went too, replaced by a one-time card that rings the actual control it is describing. Pointing at the real interface beats narrating a copy of it, and it cannot drift out of sync with the thing it explains.
Process and what failed
AI shipped behind a full lead form, name and email and phone with explicit consent, rather than the email-only gate these features usually get. That trades signup volume for contact quality on purpose, on the reasoning that a design tool feeding a brokerage funnel needs reachable people more than it needs a large list.
It was then switched off for a morning and restored the same day, once the gate had been re-walked on production rather than assumed from the config. That is the honest shape of a live feature: a flag to flip and a gate to verify, not a launch event.
Spend is bounded the same way, by a hard daily ceiling in configuration rather than by trusting usage to stay reasonable. A generative feature attached to a public tool has no natural upper bound, so the limit belongs somewhere it cannot be forgotten.
Outcome
The app is live and was walked end to end on production, with every planned milestone shipped, AI on behind the lead gate, and uptime monitors plus scheduled health, backup and funnel jobs running against it rather than manual checks.
Traffic is deliberately narrow. One campaign link sits behind a single video, and the decision rule was written before launch: it refuses to read a verdict until the experiment reaches its minimum click count. That threshold had not been met when this page was written, so there is no conversion figure here. The absence is the discipline working, not a gap in the record, and quoting an early number from a sample that small would be the more misleading choice.
Related work
- Live2026Evolve University PlatformA self-hosted learning, community, and accountability platform for real estate teams built to beat Skool, Circle, and Kajabi on the dimensions that matter to sales-driven orgs…
- Live2026Monarch MovementA self-hosted community and onboarding platform that turns a real estate team's recruiting SOP into software members can't skip a step of.
- Live2026The Alliance HubA multi-tenant culture-operations platform for a real-estate team's physical hub, built by hard-forking a sibling product and re-deriving its tenancy, security and design…