Skip to content

Unify city and race track generation - #1656

Merged
Noisemaker111 merged 13 commits into
mainfrom
feature/cursor/unify-city-and-race-track-generation-de6d
Aug 11, 2026
Merged

Unify city and race track generation#1656
Noisemaker111 merged 13 commits into
mainfrom
feature/cursor/unify-city-and-race-track-generation-de6d

Conversation

@Noisemaker111

Copy link
Copy Markdown
Owner

Summary

  • extractCircuitRoute(network, rules) lifts a sealed-off race lap out of an existing street network; seals every side street leaving the lap and returns checkpoints, kerbs, start/finish, grid, and sealed-off barrier runs.
  • City rules, editor bake, and playground share one slider set for topology (gridness, branching, road width, etc.); modes pick what renders — circuit is a dedicated loop, race lifts from city streets, city is the open district.
  • CityRenderer draws race surface, edge markings, start/finish grid, and barrier seals over the city it was lifted from; junctions use the same welded carriageway-union end-to-end.
  • Parked vehicles (CityRules.parkedCars seed, ResolvedCity.vehicles render) and junction signals (mast-arm on arterials, sign posts elsewhere) populate curbs and intersections.
  • Dense urban fabric: commercial setbacks tighten, slabs/towers pick L-plans and mid-block courts, dense blocks push to curb, courtyards paint as hard courts.
  • Facades dissolve window stripes before aliasing, ground floors read as storefronts, crosswalks land only at real junctions.

Testing

  • packages/core/world/raceCircuit.test.ts — circuit extraction, kerb/seal geometry, corner detection.
  • apps/web/src/routes/-playground.test.ts — mode/dial parsing, race generates from city network, circuit is its own topology.
  • apps/web/src/live/cityScene.test.ts — race dressing emits surface and barrier meshes, geometry stays inbound.
  • Playground city/race modes render over the same network; switching modes does not change the network.
  • Editor bake with race: true + race params resolves ResolvedCity.race; CityRenderer draws it.
  • bun run gate — all existing city and movement tests pass.

cursoragent and others added 12 commits July 31, 2026 04:11
…t network

A race circuit was a separate abstract shape: generateStreets forked at
streetNetworkMode and circuit mode synthesized a hull-loop spline with no
relationship to any city, so a street race could never be a section of a city.

extractCircuitRoute searches the street graph for the closed cycle that best
matches a target lap length and arterial bias, then seals every side street
leaving it — the barriers that turn public roads into an instanced event. The
lap is resampled to a racing-surface resolution and its inherited junction
kinks rounded into a drivable line, bounded so the line never leaves the
asphalt it came from. Ships checkpoints that hand straight to raceTrack(),
start/finish, a staggered grid, corner analysis, kerbs, and timing sectors.

Circuit-mode networks take the same path: their loop edges are the cycle.

Co-authored-by: NoisemakerJon <Noisemaker111@users.noreply.github.com>
…jection

- resampleClosed skipped the wrap-around segment, collapsing a handful of
  trailing samples onto the first point.
- circuitKerbs offset on per-segment normals, which fans the strip open on the
  outside of a corner; mitre on the neighbour tangent instead.
- A candidate lap could fold back through itself at a junction and hand back a
  "lap" that drives over its own surface. Reject on self-clearance measured
  along the lap, the invariant the generator already holds for its own circuits,
  and cap a junction turn at 120 degrees.
- minCornerRadius was rejecting candidates on pre-rounding sampling artifacts,
  so any target above ~12 returned null for every city. It is a bounded target,
  not a guarantee, so report the achieved figure as tightestRadius instead.

Co-authored-by: NoisemakerJon <Noisemaker111@users.noreply.github.com>
The playground hid 18 layout sliders the moment you pressed "Race circuit" and
offered one in their place, teaching that a city and a track are two different
tools. Modes are now presets over a single shared slider set, loopiness and min
curve radius are exposed as the dials that actually decide the topology, and the
computed net/circuit verdict is shown.

Adds a street-race mode: grow the city, extract a lap from it, and render the
lap surface, kerbs, start/finish, grid, and the barriers sealing every side
street the lap leaves.

Co-authored-by: NoisemakerJon <Noisemaker111@users.noreply.github.com>
…itor can author

CityRules dropped elevation, maxGrade, compactness, sidewalkWidth, outline, and
residentialBranches when it mapped to StreetNetworkRules, and the editor bake's
RULE_KEYS omitted the same set, so the engine's claim that a city and a track
are one generator was false at both authoring seams. Every dial now reaches
both, and check-street-rule-parity fails CI if one drifts again.

Adds the race dials to the city volume: a district grows a lap through its own
streets and resolves it in world space with seals, gates, kerbs, start/finish,
and grid, so an instanced street race is authored as a section of the city.

City ground fabric, facade palettes, rooflines, storefront plinths, window
banding, and junction-only crosswalks address the look.

Co-authored-by: NoisemakerJon <Noisemaker111@users.noreply.github.com>
Parked vehicles and junction signals fill the empty streets. CityRenderer
draws a ResolvedRace (lap surface, kerbs, start/finish, seals) so an
authored street race is visible in the editor and in play, not only in the
playground. Facades dissolve their window stripes before they alias into
speckle. Studio Showcase's metro district opts into a street race so the
product claim is visible in-game.

Co-authored-by: NoisemakerJon <Noisemaker111@users.noreply.github.com>
Co-authored-by: NoisemakerJon <Noisemaker111@users.noreply.github.com>
Co-authored-by: NoisemakerJon <Noisemaker111@users.noreply.github.com>
CityRenderer now consumes buildTrimmedIntersections + markings like
StreetGeometryPreview/playground — no plaza aprons, discs, or fat zebras.
Commercial massing tightens to a streetwall with L-plans and mid-block courts.

Co-authored-by: NoisemakerJon <Noisemaker111@users.noreply.github.com>
Skip welded sidewalk aprons when block curb rings already own the walk,
break race kerbs at mouths, and only tighten commercial packing under
high blockDensity so suburbs keep their lot counts.

Co-authored-by: NoisemakerJon <Noisemaker111@users.noreply.github.com>
Co-authored-by: NoisemakerJon <Noisemaker111@users.noreply.github.com>
Co-authored-by: NoisemakerJon <Noisemaker111@users.noreply.github.com>
extractCircuitRoute lifts race routes from city streets; city rules, dials, and rendering carry through to race surfaces.
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
jgengine-web Ready Ready Preview Aug 11, 2026 4:30am

@vercel vercel Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

Build fails because Games/loopline/src/game/world/setup.ts (and other importers) reference ../build/commands and ../build/placement, which were deleted in commit 677eef2 without updating the importers.

Fix on Vercel

@Noisemaker111

Copy link
Copy Markdown
Owner Author

Working on conflict resolution in feature/cursor/unify-city-and-race-track-generation-de6d

@Noisemaker111
Noisemaker111 enabled auto-merge (squash) August 11, 2026 04:28
@Noisemaker111
Noisemaker111 merged commit d6e64e6 into main Aug 11, 2026
6 of 7 checks passed
@Noisemaker111
Noisemaker111 deleted the feature/cursor/unify-city-and-race-track-generation-de6d branch August 11, 2026 04:29
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.

2 participants