Case study
Urcrib
Live, in previewYour home at its real size. Measure the room with what you have, place real furniture at real size, and find out what won't fit before you pay for it.
The scripted part of this conversation carries the verified facts. Live answers only use what's on this site.
Hi, this is Urcrib, the one I designed and built entirely on my own. It turns a room you already live in into a plan you can buy against. It's live in preview, and I've been strict about what it claims. Ask away, or just scroll.
So what is Urcrib?
Thought for 2s
Furnishing here is a run of irreversible purchases made with no information: a wardrobe built to a guess, carried across town, stuck at the door. Urcrib lets you measure with what you have (floor tiles, paces, a tape), builds a scaled plan, places real furniture at its real size, and tells you what won't fit and why, before you pay.

- pieces of furniture at real size
- 204pieces of furniture at real size
- fit rules checked on every move
- 26fit rules checked on every move
- layouts to start from
- 33layouts to start from
- when you count floor tiles
- ±5%when you count floor tiles
What did you do on it?
Thought for 3s
All of it. I designed and built Urcrib end to end: the name and brand, the product decisions, the customer app, the vendor portal, the staff console, and the geometry engine underneath them. I wrote the product spec and the engineering standards first, then built with AI coding agents working from those specs, reviewing every change against them.
- apps: planner, vendor portal, console
- 3apps: planner, vendor portal, console
- automated tests
- 1,275automated tests
- invariants, each with a check in CI
- 11invariants, each with a check in CI
- person
- 1person
What does planning a room look like?
Thought for 4s
You pick what you're furnishing (a flat, a bungalow, a storey building or a shop), start from a layout, and measure each room the way you can. Then you add pieces from the catalogue at true size and the plan tells you, in plain words, what fits and what to look at. It works on any phone, offline once opened.




How do you measure a room without a tape?
Thought for 2s
Not everyone has a tape measure, but a lot of floors are tiled. So you can count the tiles along a wall, say whether the end tile is cut, and the plan works out the length. The rule that holds it together: every length carries how it was measured, and how sure it is comes from that, never typed in. Pick a method and watch the plan's confidence change.
The shaded band is how wrong the wall could be. A tape is sure to ±30 mm; counted tiles to ±5%. The plan says so instead of pretending. Sample room.

/** The only constructor. It cannot be called without a source. */
export function dimension(
value: Millimetres,
source: Source,
detail?: DimensionDetail,
): Dimension {
if ((RESERVED_SOURCES as readonly Source[]).includes(source)) {
throw new SourceReservedError(source);
}
return {
value,
source,
toleranceMm: toleranceFor(source, value, detail?.knownDistance),
};
}Lengths are stored as whole millimetres everywhere, with no floats or unit strings. A wall you taped is surer than one you paced, and the plan never pretends otherwise.
Explain more
There's even a source called nominal, for the size a product is sold as: a bed sold as "6 by 6". It isn't a measurement, but it isn't a guess either, and filing it as either would have been a lie the fit checks then believed.
How does it decide what fits?
Thought for 3s
A rules engine of 26 rules checks every move: walkways, chairs pulling out from a dining table, a wardrobe door swinging open, a bed you can get round, a TV at a sensible distance. Every threshold lives in config, not in the code, so a market can be re-tuned without a release. And nothing it says blocks a placement: it explains, you decide.
/**
* INVARIANT 4.4 — rules are data.
*
* Every clearance threshold in the product lives in this file and nowhere
* else. The evaluator reads them; it never contains one.
*/
export type RuleId =
| 'primary_walkway'
| 'dining_chair_pullout'
| 'wardrobe_door_swing'
| 'bed_side_access'
| 'carried_up_the_stairs'
// …and 21 moreEach rule has a test that fires and one that doesn't, so a rule that quietly stopped working would fail the build.
Will it actually get through the door?
Thought for 4s
A three-seater that fits the parlour is still a wasted delivery if it won't pass the front door, and here that's found out on the day, by four men on a staircase. So Urcrib checks the doorway, the door head and the turn in from a corridor, using measurements you've already taken. It also works on its own at /delivery, with no account. Try it with a wardrobe.
It tries all six faces, because a wardrobe can lead with its narrow side. Simplified: the real check also covers the turn in from a corridor, the stairs and the lift.


The answer always says what it didn't check: if you didn't give a door height, it tells you the head wasn't checked.
Explain more
Angling a piece diagonally in the doorway was built and then taken out again. For a rectangle it can never squeeze a piece through an opening narrower than its own smallest side, and the six faces already try every orientation that leads with that side. The reasoning is written into the code so nobody reopens it on intuition.
Can you see it in 3D?
Thought for 2s
Yes, two ways. A flat 3D drawing that runs anywhere, and a full three.js view you can turn and look inside, across every floor and the stairs between. It's massing only, on purpose: photorealism is a non-goal, because a pretty render isn't a measurement. You can export the building as a 3D file for other tools.


Is all of it actually working?
Thought for 3s
Not yet, and the product says so. The planner is real; everything that needs a server is an interface. I keep a ledger of every promise the site makes against what actually works, checked against the code. Before showing it publicly I changed the site from reading as finished to a clear Preview: everything in the planner is open and free, and what isn't ready says “soon”.
Then · Before the preview
Free with an account. Sign in and create an account. Plans kept in your account.
Now · Since 13 Oct 2026
Everything in the planner open, no account. Plans kept on this phone. Accounts and paying open soon.
Generated pictures of furniture are never used as a measurement: the image and dimension pipelines share no types, so a pretty picture can't sneak into a fit verdict.
How did you build three apps alone?
Thought for 4s
By writing the rules down first. The engineering standards list eleven invariants, each with a check in CI, and are written to be pasted into an AI coding agent's context. Every task names the invariant it touches, its boundary, the test that proves it, and when it's done. Then I verify before accepting, ending on one question: does the test fail when the code is reverted?
- Which invariant it touchesInteger millimetres, provenance, rules as data, prices with a vendor and date…
- The boundaryWhich package or app, and what not to touch.
- The test that proves itNamed before the code is written.
- Done, in observable termsNot "implemented", but what a person can now do.
“Does the test fail when the code is reverted?”
the last check before accepting any change
What does a furniture seller see?
Thought for 2s
A portal at vendors.urcrib.com where a quote request arrives already measured: the room, the piece, the doorway and the stairs it has to get through. The vendor answers with a quote, talks to the customer in messages, and lists their own pieces at the size they are sold. I designed it as a work queue, not a shop dashboard: what needs an answer today comes first. It runs on sample data, and says so on every screen.






- personas in the scripted test: customer, vendor, owner
- 3personas in the scripted test: customer, vendor, owner
- findings, ranked before anything was fixed
- 70findings, ranked before anything was fixed
Explain more
I tested the hand-offs between the three apps with a scripted run as three people: a customer who plans and asks for a quote, a vendor who answers it, and the owner who checks both. It found 70 problems, which I ranked before fixing any of them.
And the people who run Urcrib?
Thought for 3s
They get a console. A Today queue of what's waiting, catalogue checks where a size is verified before it's trusted, vendor checks (the call, the visit, the registration, the bank account), order decisions and disputes, trust and safety, support and a team page. The part I'm proudest of is invisible: every action goes through one door. A screen never changes anything itself. It asks one function, attempt, which checks the person's role, wants a reason for anything that touches someone else, needs a second person to approve refunds and price changes, and stops people changing their own access. Then it writes the audit log, whether the action went through or was refused.






Is this person switched on, and does their role allow it?
["Is this person switched on, and does their role allow it?","If one is required, is it worth reading? Kept in the log.","Refunds, price changes, one-to-one emails: someone other than whoever asked.","Nobody changes their own role or switches themselves off.","Written either way: done, or refused and why."]'refund.approve': { area: 'payments', needs: 'payments.refund.approve',
summary: 'approved a refund', reason: 'optional', secondPerson: true },
'staff.role': { area: 'team', needs: 'team.manage',
summary: 'changed somebody’s role', reason: 'required', notToSelf: true },
// The only door. Pure, so the rules are tested without a screen.
if (!actor.active) return 'Your access is switched off.';
if (!can(actor.role, action.needs)) return 'Your role does not allow this.';
if (reasonMissing(attempt)) return 'Say why, in a few words. It is kept in the audit log.';Explain more
Every action is a row of data: the permission it takes, whether it needs a reason, whether it needs a second person. So adding an action means adding a row, and the rules are unit-tested without rendering a screen. Someone allowed to act who hasn't yet said why hasn't tried anything; they have an unfinished form, so the log stays clean.
Who explains all this to people?
Thought for 4s
I wrote it, and I built the pages it lives on. There's a customer guide and a vendor guide at urcrib.com/guide and /vendor-guide: one long page on screen that prints as an A4 book, chapter by chapter. Every price, limit and tolerance in them is read from the same code the product uses, so the guide can't teach a figure the product doesn't have, and the pictures are the product's own screens, retaken by script when the UI changes. The blog is written in the console: drafts and published posts, five categories, a live preview of how a post will read. Publishing needs a reason, like everything else there. The site reads those posts through a small client package, next to the articles written in code. The brand kit at urcrib.com/brand reads the logo and colours from the design system itself, so it can't drift from the product, and builds its downloads in the browser.






Then · Usually
Help pages written once, with screenshots and prices copied in by hand. They go stale the first time the product changes.
Now · Here
Figures come from the pricing and geometry code, pictures are retaken by script, and the brand kit reads the design tokens. When the product changes, the words follow.
If you started over tomorrow, what would you do differently?
Thought for 3s
I'd keep the claims ledger from the first public page, not add it after launch. And I'd put the planner in front of someone who has never seen it sooner: that's the exit condition I set for the very first phase, and it's still the test that matters most.
- Write the invariants firstThey're what let agents build fast without breaking the product.
- Say only what's trueTrack every claim against working code from day one.
- Measure with what people haveTiles and paces, honestly labelled, beat waiting for a tape.
- Test with strangers earlyA scripted run finds broken hand-offs; only a real user finds confusion.
Thinking
The scripted part of this conversation carries the verified facts. Live answers only use what's on this site.















