Skip to content

feat(examples): add editable SF city with clipped street corridors - #53

Open
repalash wants to merge 9 commits into
mainfrom
feat/sf-city-slice
Open

repalash wants to merge 9 commits into
mainfrom
feat/sf-city-slice

Conversation

@repalash

@repalash repalash commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Adds an offline, editable North Beach / Washington Square slice: 419 buildings, 74 streets and 191 mapped trees from four DataSF snapshots. Stable feature IDs, local overrides and generated glTF assets let individual objects improve without rebuilding the project from scratch.

Street surfaces now clip overlapping corridors, remove sidewalks crossing carriageways, add 15 cm curb faces and lowered crossing approaches, and cut the rendered ground beneath streets to prevent terrain poke-through. These curb shapes remain procedural; terrain still interpolates older city ground samples, and facades/trees remain placeholders.

Regeneration preserves user asset registrations and replacements, unknown light extensions, placement edits and extras. The example declares its direct threepipe dependency without upgrading the pinned engine. A standalone runtime export includes only intended demo assets; no hosted release has been published yet.

README and limitations · Before · After

Standalone city demo

Validation (implementation 026f8e1; preservation follow-up 65b95ee):

  • Repository build, typecheck and lint pass; build emits existing vendored ThreePipe declaration diagnostics.
  • All 10 CLI tests and five Node script tests pass. Script regressions are now included in CI.
  • Browser walkthrough: three Play/Stop cycles, saved edit, regeneration, custom registration and added-object reload, then Play/Stop again. Wait for editor restoration before restarting Play.
  • Standalone runtime: repeated bookmarks, orbit/zoom, interrupted loading, manifest failure and reload recovery; no page errors.
  • Follow-up regression and browser reload also preserve an owner-added object inside a generated tile, retaining its parent relationship.
  • Rebuilding 999 files is byte-identical. 497 glTF documents pass buffer, finite-extrema and matrix/TRS checks.
  • Editor font and optional meshopt CDN requests hit certificate errors in this environment; the uncompressed city renders.

Remaining quality work: datum-aligned LiDAR terrain, building-front corridor fitting and rounded surveyed curb returns, authored SF facades/landmarks, runtime collision and production LOD/streaming. Screenshot rates are not a measured performance budget.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T08:39:56.145102Z 44b50c3 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e5d99cac96

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/sf-city/scene/compose.mjs Outdated
Comment thread examples/sf-city/scene/compose.mjs
Comment thread examples/sf-city/main.js Outdated
@repalash repalash changed the title feat(examples): add editable SF city generation slice feat(examples): add editable SF city with clipped street corridors Oct 22, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 65b95ee283

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/sf-city/main.js Outdated
Comment thread examples/sf-city/assets/models/city/build.mjs Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 92570fc122

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/sf-city/scene/export.mjs Outdated
Comment thread examples/sf-city/main.js Outdated
Comment thread examples/sf-city/lib/generated-placement.js Outdated
Comment thread examples/sf-city/scene/data.mjs Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2ed9c36146

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -0,0 +1,22 @@
// Only untouched references to the baked, untextured asset kit may use simplified batching.
export function isGeneratedPlacement(node, placement, registry) {
if (!placement?.baked || !node.visible) return false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Exclude component-bearing placements from static batches

When a user attaches a movement, animation, or physics component to an otherwise untouched generated placement, the component keeps updating the placement node while main.js snapshots its child meshes' world matrices once and then hides those meshes, so the visible batch remains frozen. The fresh case not covered by bakedMeshes' descendant filtering is a component on the placement node itself; reject nodes with EntityComponentPlugin from batching or synchronize their batch transforms.

AGENTS.md reference: examples/sf-city/AGENTS.md:L144-L145

Useful? React with 👍 / 👎.

@@ -0,0 +1,22 @@
// Only untouched references to the baked, untextured asset kit may use simplified batching.
export function isGeneratedPlacement(node, placement, registry) {
if (!placement?.baked || !node.visible) return false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Respect hidden ancestors when selecting batch inputs

When a user hides a generated tile group or the city root while its child placements retain their default visible: true, modelRoot.traverse still visits those descendants and this check tests only the child. main.js then copies their meshes into a runtime root outside the hidden ancestor, causing the entire hidden subtree to reappear during Play; require effective ancestor visibility or use visible-only traversal.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ed0a3e103d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/sf-city/main.js
}
runtime.add(sun)
const ownedAO = !viewer.getPlugin(SSAOPlugin)
const ao = ownedAO ? await viewer.addPlugin(SSAOPlugin) : viewer.getPlugin(SSAOPlugin)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Roll back partial Play startup failures

When viewer.addPlugin(SSAOPlugin) rejects during Play startup, such as during unsupported renderer or plugin initialization, execution reaches finally with started === false, but that path only disposes the material pool and environment. The generated city lights have already been reduced to 25% intensity and owned geometry has been allocated, so no cleanup function is returned to restore them; the editor remains dim after the failed Play, repeated attempts compound the intensity reduction, and geometry leaks. Roll back every acquired runtime resource and mutation on this failure path.

AGENTS.md reference: examples/sf-city/AGENTS.md:L64-L64

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 44b50c3d00

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +44 to +45
next.extras = {...old.extras, ...values.extras, gltfUUID: old.extras?.gltfUUID || uuid(id), cityId: id,
cityGenerated: {...values, extras: undefined, rootPath: values.extras?.rootPath}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve unknown nested city metadata during regeneration

When an editor or plugin adds its own key under an existing node's extras.city object, this shallow spread replaces the entire object with the generated values.extras.city, silently deleting the unowned nested metadata on the next city:build. Merge the generated city fields into the existing object just as the light extension is merged.

AGENTS.md reference: examples/sf-city/AGENTS.md:L126-L126

Useful? React with 👍 / 👎.

widthSource: p.widthSource, species: p.species, sourceHash: p.sourceHash}}})
;(groups[p.tile] ||= []).push(index)
}
const groupIndices = Object.keys(groups).sort().map((tile) => upsert(`sf-tile:${tile}`, {name: `Tile ${tile}`, children: groups[tile]}))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Remove reparented placements from their previous groups

When a user reparents a generated placement in the editor, the new parent's children still contains that node index, while this upsert unconditionally adds the same index back to its generated tile. The resulting glTF assigns one node to two parents; loaders may reparent it according to traversal order, so either the user's group or the generated tile loses the object after rebuilding. Remove the index from other parents when restoring generated membership, or preserve the edited parent.

Useful? React with 👍 / 👎.

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.

1 participant