Portfolio polish: demo seed, world switcher, quality gate, and bug fixes#1
Merged
Conversation
Make the project demoable from a fresh clone for portfolio screenshots. - npm run seed (src/seed.ts): resets the DB and builds Desert Willow — 12 characters in 5 households, community lots (clinic, library, community center, school, campground) + 5 homes. Reuses seedData templates; keeps Manny + cat as the retired Reyes household. - Sleep is now a per-character scheduled activity: Shift.activity is "work" | "sleep" (backend schema + serialize/deserialize + resolver), sleep shifts point at the home lot. buildWorkIntent generalized to buildScheduleIntent; isShiftActive handles midnight-wrap shifts. Lets a future night-shift resident carry night work + a daytime sleep block. - Region view: day/night indicator chip + green Community / blue Residence lot badges; two toolbar scene-jump buttons (jumpToScene) to pose a weekday morning vs late evening. - Docs (README, CLAUDE.md) + a sleep-shift decision test. Co-Authored-By: Claude Opus 4.8 <[email protected]>
- Move the Live/Paused status + clock to its own row below the header on screens narrower than lg (stays inline in the toolbar on lg+). - Stack the "Region Overview" title and its action buttons onto separate rows below lg; keep them inline on lg+. - Prevent the header buttons (incl. "Edit region") from wrapping their text; the button group wraps as whole buttons instead. - Move the fill-metric color scale above the map panel to make it more prominent (removed the old bottom legend from the hex maps). - Rename the panel "Resident node health" -> "Resident health". Co-Authored-By: Claude Opus 4.8 <[email protected]>
The hex map SVG was set to width="100%", so a lot card that stretched wider (e.g. a lone card on the last row like the Nguyen house) scaled its hexes up. Render the SVG at its intrinsic pixel size and center it so every resident hex is the same size regardless of card width. Co-Authored-By: Claude Opus 4.8 <[email protected]>
Port 4000 is taken by another local service on this setup, so the backend runs on 4001 (PORT=4001). Match the /graphql dev proxy to it. Co-Authored-By: Claude Opus 4.8 <[email protected]>
Capture the Desert Willow region at a weekday morning (residents at the clinic, library, community center, and school) and at night (everyone home asleep), and embed them side by side in the README's day/night section. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The intro used a screenshot of a one-resident test world (Manny + cat), which is now superseded by the day/night region screenshots. Remove the image and file, and repoint the surrounding prose at the new shots. Co-Authored-By: Claude Opus 4.8 <[email protected]>
Make the app feel finished and demonstrate multiple towns. Seed: - Build two isolated worlds (src/seed.ts): Desert Willow (full, 12 residents) and Pinehaven (small companion town, 5 residents), via seedDesertWillow()/seedPinehaven() with a parameterized makeSchool(). World switcher + default landing (App.vue): - Header world dropdown fed by a new getWorldsWithRegions query. Needed a World.regions field resolver (resolvers/world.ts + index.ts); the worlds query now orders createdAt ASC so the oldest world is the default. - On load at '/', router.replace to the default world's Overview so data shows immediately. Last world persisted in localStorage; regionBase falls back to the active world's region so nav works from global pages. - Switching worlds keeps the current section (Residents -> Residents, etc.) instead of dropping to Overview. - Region views refetch on world/region change: added watch([worldId, regionId], loadData) to RegionOverview, ActivityLog, and LotsAndHouseholds (vue-router reuses the component across param-only navigations). Unfinished-page flag (frontend/src/config/features.ts): - showUnfinishedPages (env VITE_SHOW_UNFINISHED, default off) hides the placeholder nav items (Tickets, Alerts, Calendar, Analytics, Reports, Settings) by filtering the nav, not via route redirects. Docs: refresh the README seed section for two worlds, the switcher, and the feature flag. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The world and its single region shared a name (Desert Willow / Desert Willow), so the breadcrumb read "… > Desert Willow > Desert Willow > Overview" and looked like a bug. Name the regions after sub-areas instead: Desert Willow → Willow Flats, Pinehaven → Cedar Hollow. Regenerate the day/night screenshots to match. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The relationship graph highlighted a character's ties on hover but never said what they were, and no family/social structure was modelled. - Seed explicit, labelled relationships for both worlds (src/seed.ts): families (spouse, mother/father, daughter/son, siblings), coworkers, and schoolmates. A relationship's `labels` is a list, so relate() takes several per side (e.g. Manny & Elena are "spouse, best friend"). - RelationshipGraph: hovering a character now lists their relationships from their own perspective (e.g. "Priya Lin — daughter"); hovering an edge shows both directions; the type also appears on the highlighted edges via emphasis edgeLabel. - graphLinks now carries per-direction label arrays (labelsForward/ labelsBackward) instead of a single ambiguous label, joining multiple labels for display. The town loader already hydrates each character's relationships (with labels) from the backend, so these show at tick 0. Co-Authored-By: Claude Opus 4.8 <[email protected]>
It wrapped to two left-aligned lines in the 72px rail; add text-center so "SERVICE / DESK" is horizontally centered. Co-Authored-By: Claude Opus 4.8 <[email protected]>
Light mode isn't implemented, so the toggle did nothing. Hide it unless VITE_SHOW_UNFINISHED is set, like the other placeholder features. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The activity log filled with "Could not perform …: Unexpected error" (a masked INTERNAL_SERVER_ERROR). Root causes: - The "work" action has no item affordance, so it could never find an item and always threw. Treat work as itemless (like calls/texts) — you work by being at the workplace. - A stale/taken item hint failed the whole action. Fall back to any item at the current lot that allows the activity before giving up. - Expected conditions (no spot / all in use / no location) threw plain Errors, which GraphQL Yoga masks as "Unexpected error". Throw GraphQLError so the real, readable message reaches the client. Verified: work now succeeds, and a genuinely impossible action returns "No <action> spot available at this location" instead of a masked 500. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The Library (Lots/Households template tabs) started empty. Seed it from the same building templates used by the demo worlds — 6 lot templates (clinic, library, community center, campground, two houses) and 3 household templates (two-parent family, retired couple, working pair). Co-Authored-By: Claude Opus 4.8 <[email protected]>
Clicking a hex on the region map navigated straight to the character's lot. Instead open a popover with the existing CharacterDetailPanel (Needs / Bio / Relationships / Memories tabs), and add a "Go to <name>'s current lot" link that performs the old navigation. Relationships/ memories are hydrated on open via the character panel store. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The ☀️/🌙 buttons existed only to pose screenshots, and their 14-tick settle loop ran uninterruptibly — it kept advancing the sim while the status read "Paused", so play/pause appeared broken during a jump. Remove the buttons and all the jump machinery (App.vue handler, simulationStore.jumpToScene, simulationDateTimeAt), restoring plain play/pause. The day/night indicator, lot colour-coding, and the existing day/night screenshots stay; run the clock to see the town move. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The fixtures built tasks in the old flat shape (no steps/currentStepIndex), so advanceTask/buildCompletionIntent crashed on task.steps. Build the fixtures with the real createTaskFromIntent factory and assert against the current steps-based ActiveTask shape. Full suite now green (254 passing). Co-Authored-By: Claude Opus 4.8 <[email protected]>
Make `vue-tsc --noEmit` clean (was 30 errors) and add an npm `typecheck`
script.
- Source: remove the dead character side-panel in App.vue (its state was
never set); optional-chain currentLocation guards in
CharacterRelationshipsTab; fix applyActionEffects call in
DebugActionPanel to the {characterId,intent} shape; annotate the
romance/hobby option builders in useCharacterIntentOptions so
intent.action/source don't widen to string; default item name in the
db migration; cast db.close() (kuzu ships no types).
- Tests: type the task/ItemData/CharacterState fixtures to the current
ActiveTask/ItemData/CharacterState shapes (steps, currentStepIndex,
classification, social-invitation arrays) and give a mock a typed arg.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Set up ESLint 9 with typescript-eslint and eslint-plugin-vue (essential ruleset) plus `lint`/`lint:fix` scripts. Relax noisy stylistic rules and allow `_`-prefixed unused args; keep the correctness rules. Fix the 16 resulting errors — unused imports/vars/consts, an empty interface, dead computeds, and unused resolver args. `eslint .` is now clean. Also fix .gitignore (a missing newline had merged .DS_Store with the data.backup pattern). Co-Authored-By: Claude Opus 4.8 <[email protected]>
GitHub Actions workflow running on pushes to main and PRs targeting main. Installs with npm ci on the .nvmrc Node version, then runs lint, typecheck, and the test suite as separate steps so a failure clearly shows which gate broke. Co-Authored-By: Claude Opus 4.8 <[email protected]>
A tick does async GraphQL work, so at faster speeds the auto-tick interval fired again before the previous tick finished. Those ticks stacked up and kept draining — advancing happiness/needs — even after the user hit pause. Guard the interval so ticks never overlap and skip outright when paused, and clear any existing timer before starting a new one so intervals can't stack. Co-Authored-By: Claude Opus 4.8 <[email protected]>
With a line per resident, the names were hard to read off the paginated legend. Label each line at its right end with the character's name, tilted diagonally (colliding ones hidden), and tilt the time-axis labels so dense ticks don't clip. Widen the right margin to fit the labels. Co-Authored-By: Claude Opus 4.8 <[email protected]>
Residents autonomously "date" whoever's around — including parents, children, and siblings — which then earned "attracted to" / "casual relationship" labels on the relationship graph. Add a blood-family label set and: skip blood relatives when choosing a date partner, and never apply romantic milestone labels between them. Since milestone labels are recomputed each tick, existing family attractions clear themselves. Co-Authored-By: Claude Opus 4.8 <[email protected]>
Rewrite the apologetic "very early / rough edges / not there yet" note into a confident status statement that leads with what works and the engineering behind it, while staying honest that it's not feature-complete. Update the tests note to the passing lint/typecheck/ test + CI gate, point the empty-DB tip at `npm run seed`, and drop a defensive parenthetical. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This `let` (never reassigned) failed prefer-const; the earlier eslint --fix corrected it in the working tree but the fix wasn't committed, so CI would have flagged it. Commit the const. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The day/night section was renamed, breaking the intro's anchor link; point it at #day-and-night. Add a GitHub Actions CI status badge. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The eat-together relationship tests assert that characters eat during the local lunch window (hours 11-14). With ISOs like 19:00Z they landed at noon in MST (pass) but 19:00 in UTC (fail), so CI failed while local passed. - Pin TZ=UTC in vitest.config.ts so every invocation (CI, IDE, raw npx) is deterministic regardless of machine locale - Belt-and-suspenders TZ=UTC in the test scripts and the CI test step - Move the three lunch-window test ISOs to 12:00Z so they sit inside 11-14 Co-Authored-By: Claude Opus 4.8 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Turns the repo into a presentable portfolio project: a reproducible demo you can run in one command, a confident-but-honest README, and a real CI quality gate — plus a batch of UX and correctness fixes.
Demo & content
npm run seedbuilds two isolated worlds — Desert Willow (12 residents, 5 households) and Pinehaven (small companion town) — with community + residential lots, family/coworker/schoolmate relationships, and a template library. Each resident has a weekday work/school schedule plus a nightly sleep block, so the town visibly commutes: dispersed by day, home at night.VITE_SHOW_UNFINISHEDso the app reads as finished.Bug fixes
startActivityno longer floods the logs —workis itemless, item hints fall back to any suitable item, and expected conditions return cleanGraphQLErrors instead of masked 500s.Code health / CI
vue-tscclean (was 30 errors).main: lint + typecheck + tests. All green locally.Not included (deliberately)
🤖 Generated with Claude Code