2026 10 13 moving house temple design - xopherdeep/do-it-for-the-xp GitHub Wiki
Date: 2026-10-13. Status: implemented 2026-10-13 (moving temple commits through the Old House name plate, 8618f25e); see the plan docs/superpowers/plans/2026-10-13-moving-house-temple.md.
The owner: "the create pack for the move out pack doesnt build very good temples. can you make it loads smarter?"
What the builder does today (src/lib/services/core/packs/movingTemple.ts, run 2026-10-13 for a grown-up, a
12-year-old and a 6-year-old in the default three-bedroom home):
. . . . KEY . . . .
mb mb mb mon mb mb mb . .
DOOR map cmp hall hall hall camp VAN egg
. mb mb mb mb mb mb . .
- A comb. One straight hall, 12 dead-end rooms off it, one key. Nothing like a house: no loops, no floors.
-
A wall of minibosses. 10 of the 12 side rooms are sealed minibosses (
lockOnEnter); size 95 where 21 is a full temple; the only camp is at the very end. - The kids barely play. The grown-up holds 8 rooms; the 12-year-old and the 6-year-old get one fight each (their bedrooms) and a sleeping beast everywhere else. A house room takes only the first quest the pack made for it, so 15 of the 17 kid quests (mugs, game shelf, books, frames, garage gear, dust bunny hunt, pillow parade...) never enter the temple.
- The order is wrong. The Final Walkthrough is a side room fought before the van is loaded.
- Generated temples have no floor art (a black starfield). Out of scope here (section 9).
- One room, each hero's chore. A room of the house is one temple room; every hero meets the chore of theirs that is due there (the grown-up meets the Crockery Colossus in the kitchen, the 12-year-old the Mug Thug). This needs the engine to let a room hold several quests.
- Floors come from the setup. The Moving House dialog asks for 1 or 2 floors, and a basement when storage is ticked. Bedrooms go upstairs on a two-floor house; storage goes to the basement.
- The whole design below, including: every old-house quest and the pack's dailies inside; only the kitchen and the van seal; the van, then the walkthrough, then the egg; rebuilding resets the heroes' walk through this one temple.
RoomContent gains questIds?: string[]: the quests the room holds, in the Game Master's order. A room with a
single questId reads as [questId], so every existing temple behaves exactly as before.
Resolution for a hero (resolveRoomQuest, docs/Quest-Rooms-Spec.md 5.2, extended):
- Take the room's quests (
questIds, else[questId]) that are live (exist, not a draft). - Among those visible to the hero (on their board, or an Open Bounty, or assigned to them): pick by the existing
preference, lurking (open) before pending before cleared before away; ties go to list order.
Result
{ kind: "quest", source: "questId" }. - None visible but some live:
notYourswith the first live one (its beast sleeps here). - None live: the template (
content.quest) as today, elseemptyLair.
A single-quest room passes through these steps and gets the same answer resolvePick gives now; the existing
questRooms specs must pass unchanged.
Consequences, all through the one resolver: the run sync (templeSystem/questRooms.ts) seals or opens the room
from the resolved status; the battle loader fights the resolved quest; clearing the room completes that quest.
When a hero beats one beast and another of their chores in the room is open, the room lurks again: the next beast
is there the next time they walk in (after a win the hero is not thrown into a second fight on the spot; the
plan verifies how the return from battle behaves and keeps it that way).
A sealed room holds one quest. A lockOnEnter room that turns lurking again under a hero who just won is
sealed again on the way back from the battle (heroRuns reseals an uncleared fight room), which would throw them
into a second fight. So the guard and the van each hold a single quest; lists live only in open rooms.
Other readers read a list room by its headline quest: its biggest live quest, ties to list order
(headlineQuest in questRooms.ts).
-
isQuestRoom(questRooms.ts and templeQuestRows.ts): true for a non-emptyquestIdstoo. -
gmResolution(templeQuestRows.ts, the Game Master's temple quest list): the headline quest. The row's existingmoreQuestscount is the list's other live quests, and the tier mismatch flag is not raised for a room written withquestIds(a pack types its rooms by layout, not by quest). -
roomSizeShare(questRoomPicker.ts, the editor's size meter) and the tab's size: a list room counts at its headline quest (one fight at a time).sizedRoomOfalready works from the resolved quest. - Temple editor (
roomQuest.ts):describeRoomQuestshows a list room aspickedwith its headline quest;applyQuestPickreplaces the list with the single pick (deletesquestIds);releaseQuestdeletesquestIdstoo. No list editing UI in this round.
A room name. RoomContent gains name?: string ("Kitchen", "Twelve's bedroom"). The temple screen shows it
as a small cream plate in the header (StatusPlz), so a hero knows where in the house they stand. A room without a
name shows nothing: the nine shipped temples do not change.
Every quest of the pack's old-house phases (1 Declutter to 5 Moving Day) and the four dailies land in exactly one room. The unpack phase (6) stays out: it belongs to the new house (section 9). A room is built only when the family has it and at least one of its quests exists; a room whose quests all went missing is left out.
| Room | Built when | Quests (pack slugs), in list order |
|---|---|---|
| Front porch (entrance) | always | none |
| Front hall | always |
open-first, donation-run, light-boxes, pillow-parade; paperwork when there is no office; the packing station's quests when there is no dining room |
| Dining room = packing station | dining ticked |
supplies, box-labels, frames
|
| Living room | living ticked |
living-dining, game-shelf, daily tidy
|
| Kitchen (miniboss, sealed) | kitchen ticked | its first quest that exists: dishes, else pantry-fridge, else mugs, else daily dishes
|
| Pantry (open, beside the kitchen) | the kitchen has quests left | the kitchen's other quests, in that order |
| Laundry room | laundry ticked | laundry |
| Bathroom | bathroom >= 1 |
bathrooms, daily teeth
|
| Garage | garage ticked |
garage, garage-gear
|
| Yard (out the back door) | yard ticked | yard |
| Pet corner | pets ticked |
pets, daily feed-pets
|
| Home office | office ticked |
office, paperwork
|
| Guest room | guest >= 1 | guest-room |
| Storage (basement when ticked, else ground floor) | storage ticked | storage |
| Main bedroom | bedroom >= 1 and a grown-up plays | each grown-up's closet-grownup, beds-apart
|
| A bedroom per kid or little one | bedroom >= 1 | that hero's keep-donate-trash, books-kid, dresser-kid, backpack-kid, clear-old-room (kid) or toy-triage, books-little, toys-little, backpack-little, dust-bunny-hunt (little) |
| The moving van (boss) | always | load-van |
| Last look | always |
walkthrough, deep-clean
|
| Keys to the New House (Master Room) | always | the Pegasus chest |
* per-hero quests: every hero of the band has one, and all of them go in the list.
- Bedrooms: the grown-ups share the main bedroom ("Dad's bedroom" for one grown-up, "Main bedroom" for more); the
kids and little ones get
max(1, bedrooms - 1)rooms when a grown-up plays (bedroomswhen none does). With fewer rooms than kids, the kids share: they are dealt round robin (in the dialog's hero order) into the rooms there are, and a shared room is named for its kids ("Max and Pip's room"). No bedroom ticked: the bedroom quests go to the front hall. - One bathroom room holds the bathroom quests whatever the count; a second bathroom is the upstairs heal room (section 3), never a quest room.
- A family with no grown-up has no main bedroom; quests a family does not have are skipped (the pack decides who gets which quest; the temple only places them).
- The room's layout type:
miniboss(sealed) for the key guard,bossfor the van,monster(open) for every other quest room. The fight follows each resolved quest's own tier, as today. -
The key guard is a sealed room of one quest: the kitchen; else the garage (its first quest, with a "Workbench"
open room beside it for the rest); else a "Packing pile" off the front hall holding
open-first.
| Setup | 1F | 2F | B1 |
|---|---|---|---|
| 1 floor | every room | none | none |
| 2 floors | porch, hall, living, dining, kitchen, laundry, garage, yard, pets, the bathroom, stairs up | landing (stairs down, save point), upstairs hall, the bedrooms, guest, office, one heal room ("Medicine cabinet" when the home has 2+ bathrooms, else "Linen closet") | none |
| + basement (storage ticked) | stairs down (the small-key door) | as above | landing (stairs up), storage, a "Forgotten box" chest |
The floor list is B1, 1F, 2F (only the ones built), so the entrance is [index of 1F, row, col]. Stairs come in
twins on the same cell of both floors (R8) and carry targetLevel and targetCoords so the screen never guesses.
A pure, seeded function grows each floor from its hub (1F: the front hall north of the porch; 2F and B1: the landing). Each room has a parent and a list of preferred directions from it, the way homes are built:
- 1F: hall -> living (west), dining (north of living), kitchen (north of hall, or east of dining), laundry and garage (off the kitchen), yard (north of the kitchen: the back door), bathroom and office/guest (off the hall), stairs (off the hall).
- 2F: landing -> upstairs hall -> bedrooms, bathroom, guest, office.
A room takes the first preferred free cell next to its parent, else any free cell next to it, else the nearest free cell next to any placed room of its floor. The seed is a hash of the answers that shape the house (rooms, floors, heroes, bands) and never the move date: the same answers give the same house. Each floor is trimmed to its bounding box and must fit 9x9 (R10); the largest home the setup allows must fit, and a test proves it.
Rooms that touch are open to each other (the engine has no inner walls), so a compact plan gets real loops, as a house has. Three cells must touch only what they are meant to, and the planner reserves walls around them:
- The junk drawer (a chest with the Boss Key) touches only the key guard (R4).
- The small-key room (section 3, below) touches only the room whose door it is locked from.
- The van touches only the porch (its one door, locked with the master key, R6) and Last look.
- Last look touches only the van and the Master Room; the Master Room touches only Last look (R7).
So the driveway runs off the porch: porch -> van -> Last look -> Keys to the New House. A hero comes in the front door, crosses the house to the kitchen, takes the van keys from the junk drawer, walks back out to the van and loads it, takes the last look, and hands over the keys.
- Map chest: in the front hall's first free neighbour. Compass chest: next to the living room or dining room (else the hall).
- One small-key door on the way into the quiet wing: the basement stairs, else the garage, else the yard. Its key is in a chest "Under the couch cushions" next to the living room (else next to the hall). With no quiet wing there is no small-key door.
- Camp "Sleeping bags" next to the porch, before the van. Heal room upstairs as listed. Save point: the upstairs hall. At most one save room per floor (R10).
The same id (gen-move-house), name ("The Old House"), theme and element as today, generated: true, a
dungeonLayout of floors of tokens and a rooms table (unique tokens per room, the generator's naming). The
description names the key guard: "...the key to the van is in the junk drawer behind the kitchen."
Under "Rooms in the home", one more row: Floors: 1 / 2 (radio buttons in the bands' style), and a
Basement tick box shown only while storage is ticked. MovingAnswers gains floors?: 1 | 2 (default 1) and
basement?: boolean (default false); the pack ignores them, only the temple reads them. The preview line reads
"...and a 2-floor house temple with 16 rooms". The summary after the build lists the rooms floor by floor in one
short line each.
The temple keeps its id, so loading the pack again replaces the record and nothing else. Before the merge load the
dialog clears every hero's saved progress in this one temple (TempleProgressDb.clearProgress(heroId, MOVING_TEMPLE_ID) for each hero of the family): the rooms moved, so their opened chests, keys and visited rooms
would land on the wrong cells. Quests, their done or not done state, and every other temple's progress stay. The
summary already asks for a reload, which drops any run still in memory.
- Nobody plays, or
load-vanis missing: no temple (null), as today; the pack still loads. - A 2-floor house with nothing upstairs (no bedroom, guest or office) is built as 1 floor. Small floors are not padded: R10's six rooms a floor is not checked by the solver or the audit, and empty filler rooms make a dull house.
- The planner never throws on a shipped setup; a plan that fails the solver is a bug the test matrix catches.
-
tests/unit/questRooms*.spec.ts: list rooms resolve per hero (open beats pending beats done beats away, list order breaks ties),notYourswhen none is the hero's, template fallback when none is live, a singlequestIdunchanged;gmResolutionrows androomSizeSharefor list rooms; the editor helpers. -
tests/unit/movingTemple.spec.tsrewritten: a matrix of setups (1 and 2 floors, basement on and off, each room ticked and not, bedrooms 0 to 8, 1 to 6 heroes in mixed bands): the solver solves it with no reasons, the audit passes, every old-house quest and daily the pack made sits in exactly one room, no unpack quest is in, every hero who plays has a quest in at least one room (at least three rooms each in the default home), only the guard and the van seal, the van leads to Last look and then the Master Room, each floor fits 9x9, same answers give the same record and the move date does not change it. -
tests/e2e/specs/moving-temple.spec.jsupdated: build with 2 floors, enter on the porch ("Front porch" in the header), step north into "Front hall". The floor plan itself is proved by the unit matrix, not by a walk. - Gate:
chemx verify(with--buildfor the .vue changes).
- Engine:
src/lib/engine/core/dungeons/types.ts,src/lib/services/temples/questRooms.ts,src/lib/services/temples/templeQuestRows.ts,src/lib/services/temples/questRoomPicker.ts,src/app/Admin/XpCompendium/views/XpTemples/components/XpTempleCreator/hooks/grid/roomQuest.ts(and the quest card that reads it). - Room name:
src/app/Console/TempleGrounds/TempleGrounds.vue(+ its.ts/.scss). - Builder:
src/lib/services/core/packs/movingTemple.ts, split so no file grows past a few hundred lines (for examplemovingTemple/rooms.tsfor section 2,movingTemple/planner.tsfor section 3). - Setup:
src/lib/services/core/packs/movingPack.ts(the two answers),src/app/SideMenu/XpSettings/components/MovingHouseModal.vue.
- The New House temple, built from the unpack phase.
- Floor art for generated temples (wood, tile, carpet, grass per room kind instead of the starfield).
- Editing a room's quest list in the temple editor.