Skip to content

docs: refresh README content + regenerate screenshots/demo - #97

Merged
thalida merged 56 commits into
mainfrom
docs/issue-96-readme-content
Jul 15, 2026
Merged

docs: refresh README content + regenerate screenshots/demo#97
thalida merged 56 commits into
mainfrom
docs/issue-96-readme-content

Conversation

@thalida

@thalida thalida commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Closes #96.

Content

  • Rewrote the intro / value prop and CTA in the repo's voice.
  • Added a user-facing How it works section (scan → manifest → 3D render).
  • Added an Info pane section (Overview + Legend).
  • Fixed the stale sections against the current code: Quick start (Projects page + branch pick + header switcher), Settings (the real World / Live updates / Appearance tabs incl. the accent+surface theme switcher), Scanning (remote clone/cache note), Development (uv prereq). Verified the Controls table and encodings still match.

Screenshots + demo

  • Regenerated all .github/readme/*.png from a new capture harness: codecity for banner/overview/buildings/streets/gem, fastapi/fastapi for the trees/fireflies (a multi-author forest, since codecity itself is too sparse).
  • Replaced the 21 MB demo.gif with a 2 MB looping demo.mp4 and a <video> embed.

Tooling (new)

  • app/src/city/capture/ — a debug-gated ?shot=/?orbit capture harness (reuses the real camera rig; never ships in a normal session).
  • just screenshots [names] — regenerate all or specific shots (app/scripts/screenshots.mjs).
  • just demo-video — record the orbit and encode demo.mp4 (app/scripts/demo-video.mjs, needs ffmpeg).

Note

GitHub's rendering of <video> with a relative path can be unreliable. If the demo doesn't autoplay in the rendered README, switch the src to the absolute raw URL (https://github.com/thalida/codecity/raw/main/.github/readme/demo.mp4), which resolves once merged to main.

🤖 Generated with Claude Code

thalida and others added 30 commits July 13, 2026 21:13
…sections

Content-quality pass for #96:
- Rewrite the intro/value-prop (plain, honest-data framing) and CTA.
- Add a user-facing "How it works" walkthrough (scan -> manifest -> render).
- Add an "Info pane" section (Overview + Legend).

Stale-content fixes verified against current code:
- Quick start: Projects page + branch pick + header switcher (was "paste a
  git URL into the source picker").
- Settings: real three-tab layout (World draft/Save, Live updates, Appearance
  with the accent+surface theme switcher), was a flat list.
- Scanning: note remote repos are cloned + cached, local read in place.
- Development: add uv to prerequisites (just fmt / gen-types).
- Drop two pre-existing em-dashes (house rule).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Regenerate .github/readme/*.png deterministically instead of hand-capturing,
so the shots stop drifting from the design.

- app/src/city/capture: a debug-gated ?shot=<name> harness. It waits for the
  city's first render, poses the camera by reusing the real rig (reset / focus)
  with subjects picked from the manifest's precomputed leaderboards (tallest
  building, densest street, biggest commit), then marks the frame ready. Lazy
  imported from main.tsx only when ?shot is present, so it never ships normally.
- scripts/screenshots.mjs + `just screenshots`: Playwright loads codecity
  pointed at its own repo, captures each shot's <canvas> to .github/readme/.
- Needs `just dev` running; reads its URL from `just url`.

The animated demo.gif is not automated (capture by hand). Shot framings are a
first pass and can be tuned in app/src/city/capture/shots.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Node resolves ESM imports from the script's own directory, not the cwd, so
scripts/screenshots.mjs couldn't find playwright (installed in app/node_modules)
even when run from app/. Relocate it to app/scripts/ and run it from there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the move: the new app/scripts/screenshots.mjs, the `just screenshots`
recipe now running it from app/, and the harness comment reference. (The prior
commit only recorded the old file's deletion.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The rig's focus methods are all top-down, so the buildings/streets/gem shots
came out flat and far. Add:

- rig.captureView({target, distance, elevation, azimuth}): a generic snap to
  any angle (not just top-down), for street-level framings.
- rig.captureAnchors(): world positions + scales (gem, tallest building, city
  center/radius) the poses frame against, so distances scale with the repo.
- shots.ts: buildings/streets/gem now aim close + low; ?elev=&az=&dist= URL
  overrides let you dial a shot in live in the browser before baking values.

trees/fireflies stay whole-city framings pending a bigger multi-author demo
repo (codecity itself is too sparse to show a forest / firefly swarm).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The trees + fireflies shots need a big multi-author repo, so capture them
against fastapi/fastapi (per-shot src/branch override in the script; codecity
stays the default for the other five).

- trees: wide low pull-back (captureView on city center) so the dense forest
  ringing the city fills the frame.
- fireflies: close on the busiest commit's tree (new rig.treeAnchor) so its
  authors' orbs are visible.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Targeting the gem/root point centered the glowing gem, so the shot read as a
gem close-up. Add rig.streetAnchor(path) and aim the streets shot at the
densest directory's street from a steeper top-down angle, so the labeled road
grid fills the frame.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- trees: adopt the low forest-immersion framing (dense trees fill the
  foreground, city behind) instead of a far aerial.
- fireflies: tighter on the busy tree so the author orbs read.
- gem: was a street-level shot with the gem a speck at the top; now close and
  looking down at it, distance scaled off the root-street width (rig anchor).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- gem: was clipped and near-level; double the distance and raise elevation to
  ~46 so it looks down on a fully-framed gem.
- fireflies: closer (radius*2, lower angle) so the orbs read bigger.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
reset() framed the whole city, leaving the repo-name label too small. Switch
the banner to captureView centered on the gem/label at the same low angle,
pulled in via cityRadius.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Targeting the gem put the city far-right with dead space; cityRadius*1.5 was
also too far, so the label was unreadable. Center on the city and pull in to
cityRadius*0.75.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eflies

- banner: aim just above the gem (toward the floating label) and pull in to
  cityRadius*0.55 so the repo label reads and stays framed.
- buildings: target the most color-varied street, excluding the root (whose
  street holds the gem), so the gem stays out of the shot.
- swap the trees and fireflies framings per request (trees tight on a tree,
  fireflies a wider forest immersion).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tree.radius*2 put the camera inside fastapi's huge busiest-commit canopy (green
blob). Pull back to radius*4 so the tree reads with its surroundings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ful (gem allowed)

- trees: wide forest immersion (radius*6); fireflies: tighter on the busy tree
  (radius*4).
- buildings: most color-varied street (mostColorfulDirPath), no longer excluding
  the root, so it can pick the gem-adjacent junction where the hues are.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
radius*4 -> radius*3 and a slightly lower angle, so a single tree with its
author orbs fills more of the frame.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`just screenshots fireflies trees` redoes just those; `just screenshots` still
does all. Unknown names are reported and skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
radius*2, low angle, aim below canopy center so the whole tree frames.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- bump the ready-wait to 360s (a big repo's first git-log walk is slow).
- capture harness signals ready even if a pose throws, logging the error, so a
  bad pose gives a screenshot instead of a 180s timeout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The busy commit we target has a max-size canopy, so radius-based distance zoomed
way out. Frame by tree height (consistent) for a genuinely tight tree shot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
captureView can now fit a bounding sphere to the live camera FOV (same math as
focusTree). fireflies uses it to fill the frame with one tree at a low angle,
instead of my hand-rolled distance that kept landing too far out.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
treeAnchor(sha) is null for commits the layout didn't place a tree for, and the
busiest commit often isn't placed, so both shots silently fell back to the
whole-city view. Walk commits (most authors first, for more orbs) and use the
first one that has a real placed tree.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Temporary instrumentation: forward the page console to the terminal and log
whether a placed tree was found and the distance the fit computed, to diagnose
why fireflies keeps framing the whole city.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Root cause of the wide fireflies/trees shots: on a fresh big-repo scan, trees
haven't finished placing at the first idle, so treeAnchor is null for every
commit and the shot fell back to the whole-city view. Shots now return false
when their target isn't ready; the harness polls (400ms x30, ~12s) until the
pose lands, then captures.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ding 1.15->1.6)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the fireflies/captureView diagnostic logs; keep only real page-error
forwarding in the capture script.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ance)

radius*6 was a fireflies-style close-up once it targeted a normal tree. Scale
the pull-back to cityRadius so the forest fills the frame with the city behind.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
thalida and others added 8 commits July 13, 2026 23:49
…ist 0.2->0.16)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fresh .github/readme/*.png from `just screenshots`: codecity for
banner/overview/buildings/streets/gem, fastapi/fastapi for trees/fireflies
(multi-author forest). demo.gif still pending.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an `orbit` capture shot that installs a per-frame window.__ccOrbit(azimuth)
framing the whole city, plus app/scripts/demo-gif.mjs + `just demo-gif`: step
the camera a full turn, screenshot the canvas each frame, and encode to
.github/readme/demo.gif with ffmpeg (two-pass palette). Requires ffmpeg.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The gif is automated now, so drop the "capture it by hand" notes in the
screenshots script + recipe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gif was a poor fit (a smooth 3D orbit ballooned to 21MB). Record the orbit as
video instead:

- orbit shot self-drives one time-based 360deg turn (fps-independent, seamless
  loop), marking data-cc-orbit-start/done.
- app/scripts/demo-video.mjs + `just demo-video`: Playwright records the canvas
  in real time (fast, no per-frame screenshots), pins it full-viewport via an
  init-script CSS so there's no chrome, trims to the orbit, and encodes a small
  h264 mp4 with ffmpeg.
- README embeds it with <video autoplay loop muted>; drop demo.gif + demo-gif.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ppy)

Headless Chromium renders WebGL in software at a low frame rate. Launch headed
(+ uncapped fps) so the orbit records smoothly; a window appears during capture.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Generated via `just demo-video`; replaces the 21MB gif.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@thalida thalida linked an issue Jul 14, 2026 that may be closed by this pull request
thalida and others added 18 commits July 14, 2026 00:55
Audited every claim against the code and fixed the stale ones:
- Trees: drop "age desaturation -> gray" (removed from code) and "facet detail"
  (facets are a fixed constant; only canopy width tracks files changed).
- Settings > Trees: real controls (visibility, color, height, width, outlines),
  not "density falloff / age desaturation / facet detail".
- Controls: clicking the gem resets the view, it doesn't select it; note that
  in the Controls table + Gem section.
- Buildings: window glow tracks creation recency, not last-modified.

Formatting: Settings > World as a list, How it works as numbered steps,
Development commands as a table (incl. screenshots/demo-video/lint/clean),
reworded the Scanning paragraph.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GitHub doesn't render <video> with a relative src. Point it at the raw main URL
so it plays in the rendered README (once this is merged to main).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removing the trailing sentences ran Live updates / Appearance / How it works
together; put the paragraph breaks back.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the World tab: bold lead-in + a bulleted list of each tab's controls.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tighten to match the terse, technical style of the original sections: drop
marketing framing (Info pane "travel guide"), use the project's vocabulary
(city model, skeleton/placeholder render, three.js), compact the How it works
steps and Scanning, and cut filler.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Break the run-on sentences into lists (Local directories now has a Tips block
like Quick start).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Group sections so concerns stop interleaving:
- Advanced setup: Local directories + Ignoring files (always-skip list +
  .codecityignore).
- Reading the city: the encodings (buildings/streets/trees/fireflies/gem) with
  the Info pane folded in.
- Settings, then How it works (now absorbs the Scanning read mechanism).
- Remove the Controls section.

Also: gem = root marker + interaction only, Info pane Overview as nested bullets.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Quick start as 1/2/3 steps + bold Tips; drop the recents/switcher tips.
- "Local repo" (no hyphen); split Always skipped / .codecityignore headers and
  drop the no-slash/has-slash bullets.
- Drop "Every model maps to real data"; gem as bullets; info pane "describes
  the city" (not "reads the city back to you").

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Advanced setup: nest the default-skip list under .codecityignore.
- Remove the Info pane section.
- Settings: sub-bullets for each control; poll interval as min/max.
- How it works: colon step labels, "Layout", note that Scan honors
  .codecityignore.
- Development: Setup / Commands / Worktrees / Backend subsections (prereqs +
  backend as bullets).
- Release: steps + a Verify signatures subheader.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the !.git/! prefix detail bullets, add a "Skipped by default" subheader for
the default-skip list, and give the gem bullets bold labels like the rest.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Convert the Settings section to a Tab / Section / Tweaks table.
- .codecityignore: drop the ! detail bullets, add a "Skipped by default" header.
- Gem bullets get bold labels.
- Clarify file created/last-modified dates vs commit date in How it works.
- localStorage -> localstorage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@thalida
thalida merged commit 11b745e into main Jul 15, 2026
1 check passed
@thalida
thalida deleted the docs/issue-96-readme-content branch July 15, 2026 02:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve the README content

1 participant