Repository navigation
feat(layers): unify TreeLayer array and streamed inventory APIs - #806
charlieforward9 wants to merge 9 commits into
Conversation
CoverageStmts: 40.21% ▲+6.76% | Branch: 31.30% ▲+7.10% | Funcs: 33.52% ▲+5.48% | Lines: 39.71% ▲+6.33%
|
|
ba091e9 to
b45becb
Compare
b45becb to
e2318e8
Compare
590bdeb to
0e66a35
Compare
e2318e8 to
5f8b7c4
Compare
d2a71e9 to
92916af
Compare
5f8b7c4 to
4216f6e
Compare
4216f6e to
0485485
Compare
eb378bc to
4b06275
Compare
b1eaf7c to
a34fd82
Compare
4b06275 to
34b2bd2
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 34b2bd2. Configure here.
| ...TreeTileLayer.defaultProps, | ||
| data: {type: 'data', value: []}, | ||
| getTileData: {type: 'function', value: null, optional: true}, | ||
| getDistantCanopyColor: {type: 'accessor', value: (canopy: TreeCanopyCluster) => canopy.color}, |
There was a problem hiding this comment.
Playground rejects streamed trees
TreeLayer now accepts getTileData and inherits streaming defaults, but TreeLayerPropsSchema still lists only row-mode props. Playground rejects documents using the recommended streaming API because defineLayer makes the schema strict. The registry completeness test also fails on new defaults such as transitionDuration and maxVisibleTiles.
Add the public streaming props to TreeLayerPropsSchema and exclude internal-only defaults from the completeness check.
Knowledge Base Used: Playground and template workflow
34b2bd2 to
704a1c2
Compare
a34fd82 to
10b3ad5
Compare
7687eed to
d93fa81
Compare
2fdbd69 to
5c8e157
Compare
d93fa81 to
8ee4d66
Compare
| maxCanopyPixels: pixelBudget, | ||
| maxCanopySplats: canopyBudget, | ||
| _splatBudgetGroup: this.state.splatBudgetGroup, | ||
| maxShadowSplats: Math.floor( | ||
| (this.props.maxShadowSplats ?? 50000) * this.state.frameBudget.scale | ||
| ) |
There was a problem hiding this comment.
When a host supplies lower limits through _subLayerProps.trees, getSubLayerProps applies them first. These later assignments replace maxCanopySplats, maxShadowSplats, and maxCanopyPixels with the inventory-wide values. Nearby trees therefore ignore the host's lower limits, despite the documented promise that nested tree caps remain effective.
Keep the shared parent budget, but preserve a lower child cap.
5c8e157 to
d3ba115
Compare
48d811d to
ac3e9f1
Compare
d3ba115 to
7d3e9da
Compare
| this.state.splatBudgetGroup.maxSplats = canopyBudget; | ||
| this.state.splatBudgetGroup.maxShadowSplats = Math.floor( | ||
| (this.props.maxShadowSplats ?? 50000) * this.state.frameBudget.scale | ||
| ); |
There was a problem hiding this comment.
Streamed trees escape shared limits
When a host supplies _splatBudgetGroup to share a rendering limit across sibling layers, a streamed TreeLayer stops honoring that limit. The public layer forwards the group, but TreeTileLayer creates its own group without connecting its parent. Near trees and distant crowns can therefore spend their own allowance on top of the siblings' work.
Set the inventory group's parent from the inherited group, and refresh that link when props change.
ac3e9f1 to
40f776c
Compare
| transparency: 'weighted', | ||
| _splatBudgetGroup: this.state.splatBudgetGroup, | ||
| pixelError: 2.5, | ||
| foveationStrength: 1, |
There was a problem hiding this comment.
Distant crowns ignore focus settings
TreeLayer exposes foveationStrength in streaming mode, but distant crowns always receive 1. Setting it to 0 disables the preference for central detail on nearby trees but not distant crowns. Forward the authored value so hosts can control detail consistently across both representations.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Use one public TreeLayer for supplied rows or geographic getTileData inventory streaming with the same top-level accessors. An internal tile component owns traversal, cache/request limits and covered replacement. WorldTreeLayer remains a deprecated wrapper for existing treeProps callers.
Retain parent coverage until children are ready and preserve original owner picking across merged batches. Distant-crown picks include tile/source-tile metadata. Public streamingStats distinguish inventory residency from canopy/shadow submissions. Shared parent quotas retain each child's local caps.
Reject simultaneous nonempty data and getTileData; mode changes rebuild the renderer without recursive traversal or duplicate IDs. Interrupted replacements retime connected coverage contributors while independent neighboring fades finish on schedule. Numeric coverage accessors invalidate tree attributes without manual triggers. Strict playground schemas expose the same flat public inventory API.
Base: #794. Coit depends directly on #814 and does not require this PR. Geographic inventory traversal and Cartesian RAD hierarchy selection keep their own source contracts.
Final integration validation: immutable install, lint, package build, strict public/example types, production example bundles and website build pass. All 1,128 Node tests and 22 renderer browser contracts pass. All 28 Tree Lab, Citrus, forest and world application cases pass across the full-suite and focused final-fixture reruns. Renderer tests require software WebGPU and exercise both sorted backends.
The inventory browser fixture waits for the destination camera pages before asserting that coverage-only edits retain row-array identity.
Stack graph:
Full stack record.