Summary
Villagers now live in their own homes. Seven cottage tiles are scattered across the town's grass bands; villagers are grouped into household pairs and assigned a shared cottage at startup. When two household-mates accumulate enough friendship (Friend tier via SocialSystem), they marry — a 💒 milestone fires in the chronicle in warm rose. On the canvas, rose-pink lines with a ♥ midpoint marker trace married couples, layered visually above the gold friendship lines but still below villager dots. Familiarity now persists across server restarts via the save file, so friendships earned over days are no longer lost on reboot. Test suite grew by 12 to 275 passing.
Project Manager
Contribution: Led Day 9 scrum and set feature scope.
Key Decisions:
- Chose households + familiarity persistence as the Day 9 double feature. Households make the social graph tangible on the map (villagers now live in distinct locations); persistence makes the social graph durable across reboots. Together they raise the simulator's sense of continuity.
- Kept marriage scoped to household-mates only. This avoids the combinatorial explosion of "anyone can marry anyone" and gives the household grouping meaningful gameplay weight — your household-mate is your potential partner, not a random villager across the map.
- Deferred A* pathfinding and second town to Day 10+. Both are larger architectural investments; today's gains were additive to existing systems rather than requiring refactors.
- Confirmed no changes to ROSTER_RECIPE (still 14 villagers). With 7 HOUSEHOLD_HOMES and 14 villagers, the pairing is exact — 2 per cottage, no remainder edge cases in normal operation.
Reasoning: Day 8 gave us social memory; Day 9 gives us social geography. A player watching the canvas can now see gold friendship webs form, then watch rose lines light up between cottages as couples emerge. The simulation is starting to feel like a world with history.
World Designer
Contribution: Specified all seven cottage positions and the marriage visual language.
Cottage placement rationale:
| Cottage | (x, y) | Neighborhood |
|---|---|---|
| A | (4, 4) | NW grass corner |
| B | (5, 8) | West, near Inn |
| C | (4,13) | West midpoint |
| D | (4,19) | SW grass |
| E | (19, 4) | NE grass |
| F | (19,13) | East midpoint |
| G | (19,19) | SE grass |
All seven are clear of the tree scatter list, away from paths (cols 11-12 / rows 11-12), and not overlapping buildings or field tiles. They ring the town periphery, so the social graph lines will visually radiate inward toward the market square — the natural hub of the simulation.
Marriage visual:
- Line color:
rgba(255,105,180,0.30)— hot-pink at 30% opacity. Heavier than friendship gold (22%) to signal permanence. - Line weight: 2px (vs 1.5px for friendship).
- Midpoint marker:
♥at 75% opacity, 8px sans-serif. Sits at the geometric midpoint between the two villagers, following them as they move. - Gold friendship lines are suppressed for married pairs (marriage line takes visual priority) to avoid double-drawing.
Backend Developer
Contribution: Wrote HouseholdSystem.js, extended SocialSystem.js and PersistenceManager.js, rewrote SimEngine.js.
Files created:
server/HouseholdSystem.js—assign(villagers)groups consecutive villagers into pairs, mutates.homeand.posto the cottage tile;tick(relationships, villagerMap)checks Friend-tier household-mates and emits marriage objects;restore({marriages})re-hydrates marriage state on load;serialize()returns{households, marriages};getMarriages()returns{aId,bId}[]for persistence.
Files modified:
server/SocialSystem.js— AddedserializeFamiliarity()(returns{key,count}[]) andrestoreFamiliarity(entries)(rebuilds the#familiarityMap). These are the only changes to SocialSystem — the familiarity data model itself was untouched.server/PersistenceManager.js—save()now acceptssocialandhouseholdsparams, writessocial: { familiarity, marriages }into the JSON;SAVE_VERSIONbumped to 2; new staticrestoreSocial(socialSystem, householdSystem, saved)calls the respective restore methods.server/SimEngine.js— Added#households; constructor callsHouseholdSystem.assign()after NPCManager builds its roster;#tick()builds avillagerMapand calls#households.tick(), emittingmarriagelog events;snapshotincludeshouseholdsandmarriages;#loadSave()callsPersistenceManager.restoreSocial();#maybeSave()passessocialandhouseholds.
Technical note: Edit tool truncated both SocialSystem.js and PersistenceManager.js mid-file on the first attempt. Rewrote both using bash heredoc (same mitigation as Days 5, 7, 8). Standing rule confirmed: always use heredoc for files > ~150 lines.
Frontend Developer / Designer
Contribution: Updated WorldMap.jsx (marriage lines), EventLog.jsx (marriage event type), App.jsx (prop pass-through).
WorldMap.jsx changes:
- Added
marriages = []prop. - New pre-villager drawing pass: builds
marriedKeysSet (normalizedaId-bIdpairs) to suppress friendship lines for married couples; then draws rose lines +♥midpoint marker for each marriage. - Friendship line loop now skips pairs already covered by marriage lines.
marriagesadded touseEffectdependency array.
EventLog.jsx changes:
TYPE_COLORS.marriage = '#e87070'— warm rose, distinct from the amber gold of friendship events.TYPE_ICONS.marriage = '💒'— standard wedding chapel emoji, immediately readable.
App.jsx changes:
- Passes
marriages={state?.marriages ?? []}to WorldMap.
Design decisions:
- The
♥marker follows the villagers as they move (recomputed each frame from live position data). This means a married couple walking side-by-side will show the heart between them — a nice emergent visual. - Marriage lines are drawn after friendship lines but before villager dots, preserving the layering convention: social fabric → villager sprites → UI overlays.
Tester / QA
Contribution: Wrote server/HouseholdSystem.test.js (12 tests). Verified full suite after refactors.
Test coverage (12 new tests):
assign()groups villagers into pairs by index order.- Home/pos tiles are mutated to the correct HOUSEHOLD_HOMES entry.
- Household-mates who are Friends trigger a marriage.
- Marriage milestone fires only once per pair (idempotent).
- Non-household-mates do not marry even if they're Friends.
- Acquaintances do not trigger marriage (Friend tier required).
getMarriages()returns all active marriages.serialize()returns correct shape.restore()re-hydrates existing marriages so they don't re-fire.pairKey()is order-independent.HOUSEHOLD_HOMEShas at least 7 entries.- Odd-count villager list is handled gracefully (last household gets 1 member).
Pre-existing test stability: All 263 pre-existing tests continued passing. The household assignment changes villager home tiles but does not affect any tested behavior (NPCManager tests check profession/work assignment, not home tile values).
Results: npm test → 275 / 275 passing (was 263; +12 HouseholdSystem tests).
What Was Built
HouseholdSystem.js: 7 cottage tiles, pair-based household assignment, marriage detection, serialize/restoreSocialSystem.js:serializeFamiliarity()+restoreFamiliarity()— familiarity now survives server restartsPersistenceManager.js:save()persistssocial.familiarity+social.marriages;restoreSocial()static helper; SAVE_VERSION bumped to 2SimEngine.js:#householdsintegration,marriagechronicle events, snapshot includeshouseholds+marriagesWorldMap.jsx: rose marriage lines with♥midpoint marker; friendship lines suppressed for married pairsEventLog.jsx:marriageevent type —💒icon,#e87070rose colorApp.jsx:marriagesprop forwarded to WorldMap- 12 new tests; suite green at 275/275
Tomorrow (Day 10 Candidates)
- A* pathfinding — replace Manhattan stepping so villagers route around buildings; prerequisite for building roofs and indoor scenes.
- Second town — add a second settlement to the world map with its own population and a road connecting them.
- Children / generational simulation — married couples can have children who grow up, inherit traits, and eventually take jobs. First step toward true generational history.
- Economy system — merchants track gold, prices fluctuate with supply/demand; farmers sell to market; innkeepers charge visitors.
- Persist villager positions — currently positions reset on reboot; could persist
posin the save file so the world resumes exactly where it left off.