Repository navigation
feat(points): set the point render order without reordering the data - #277
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
b4f2a5d to
7f72f36
Compare
|
Update — Rebased onto New
Correction to What: 🤖 Generated with Claude Code |
Points were always drawn in index order, so the only way to choose what ends up on top was to reorder every input array, remap the links and keep a permutation map for callbacks. That also changes the layout, since the simulation deals its random values by index, and reordering at runtime zeroes velocities through setPointPositions. setPointRenderOrder(order) changes only the drawing order. Indices, the simulation and every other per-point array keep their meaning. - The order lists indices back to front. A partial list puts the listed points on top and keeps the rest underneath in index order; a repeated index takes its last position, so appending one brings it to the front. Invalid entries are ignored; null, [] or anything that resolves to index order keeps the unindexed draw path. - A uint32 element buffer drives every pass that paints in draw order: the point draw, the picking fill and the label-sampling fill. So the point on top is the one hover, click and getSampledPoints report. - The occlusion core pass draws the order reversed, and depth now comes from a per-point rank attribute instead of the point index. In an indexed draw gl_VertexID is the element value, not the draw position, and depth is the only thing the core and fringe passes agree on. - GraphData resolves the order only when it is reassigned or the point count changes, since render() runs update() every time. With no order set, output is pixel-identical to the previous commit. With an order, it is pixel-identical to the old code drawing the input physically permuted the same way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Nikita Rokotyan <nikita@rokotyan.com>
…uns create() first
setConfigPartial({ spaceSize }) and turning enableSimulation on call
create() without first letting GraphData resolve pending input. The
render-order flag was cleared there against the old order, so the next
render() resolved the new order but never uploaded it.
- create() now calls updateRenderOrder() unconditionally. It is a
reference and size check unless the resolved order changed, so it is
free on every other create(), and the flag is gone.
- Docs: label sampling follows the render order but, as before, gives
highlighted points no priority. Only picking reports the point on top
while highlighting.
- createAtlas gets its JSDoc back, and the occlusion comments say
"render order" where they said "index order".
- Story: per-point translucency doesn't switch culling off, so the
readout no longer says it does, and a repeat click moves a point to
the front instead of counting it twice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Nikita Rokotyan <nikita@rokotyan.com>
…p its JSDoc note
Render order had no tests in the suite, so the resolver — plain CPU
code, and the part most likely to regress — and the path where a
config change runs create() before the order is resolved could both
break unnoticed.
- Resolver tests drive GraphData directly: partial lists, repeated and
invalid entries, orders that collapse to index order (and so keep the
unindexed draw), an out-of-range index that applies once the point
count grows and drops when it shrinks, an array edited in place.
- GPU tests stack every point on one spot inside a single sampling
cell, so getSampledPoints reports the point drawn last: the render
order read back from the GPU, through the public API.
- One test sets an order right before setConfigPartial({ spaceSize })
and expects it drawn after the next render(); the rest pin behavior
that already holds.
- The setPointRenderOrder @note had a sentence spliced onto one line;
it is rewrapped with the wording unchanged.
Every resolver rule and the create()-before-update path now has a
test that fails if it stops holding.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Stukova Olya <stukova.o@gmail.com>
… picks the point on top With a render order set, the visible draw, the engine's own picking fill and the label-sampling fill all paint through the order buffer, but the host picking pass (`drawToRenderPass` with `picking`, added for deck.gl after this branch was cut) drew unindexed. A host pick at a pixel covered by several points then reported the highest index, not the point the visible draw put on top. The rule: every pass that paints points in draw order binds the order buffer and the render-rank attribute. The host picking model now gets both at creation and sits in the `updateRenderOrder()` fan-out, so it is rebound when the order changes and unbound before the buffer goes. - `getDrawCommandAttributes()` includes `renderRank`, so the picking model's per-pick rebind carries it like every other draw attribute. - The new test stacks four points under a host pick pass and reads the red byte: it fails without this change (`expected 3 to be 1`). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Stukova Olya <stukova.o@gmail.com>
…e host pick pass The entry was drafted before the branch had tests or a host picking pass to cover, and still carried the commit placeholder. It now names the four commits, says that a host's pick pass follows the order like label sampling does, and points at the vitest file. The note that `draw-points.vert` no longer reads `pointsTextureSize` goes — the host picking varying reads it again since the rebase. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Stukova Olya <stukova.o@gmail.com>
5baacdc to
e14de59
Compare
|
Update — Rebased onto New:
🤖 Generated with Claude Code |
… host picks the point it sees While `highlightedPointIndices` is set, the visible draw and the engine's own picking fill paint greyed points first and highlighted points on top, so a highlighted point wins the pixel whatever its place in the draw order. The host picking pass drew every point in one pass, so a greyed point later in the order won a host's pick over a highlighted point it was drawn under: deck's hover and click named the point visibly underneath. The rule: every picking pass layers the way the visible draw does. The host pass now draws the same two layers through the same skip uniforms, one pass when nothing is highlighted; the render order still applies within each layer. - The host pick test highlights two of four stacked points and reads the pick byte, with and without an order that puts a greyed point last: it fails without this change (`expected 3 to be 2`). - The JSDoc and the API reference name the host's pick pass among the picks that follow the order and the highlight layering. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Stukova Olya <stukova.o@gmail.com>
…t layering The note said a host's pick pass follows the render order only, like label sampling. Since `704fde4` it layers highlighted over greyed like the visible draw, so the note says that, and why the one-pass draw was wrong. The commit list gains the fix. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Stukova Olya <stukova.o@gmail.com>
|
Update — A fast-forward on
🤖 Generated with Claude Code |
Why
Points are always drawn in index order, so a higher index is drawn on top. Until now, the only way to choose what's on top was to reorder every input array, remap the link endpoints and keep a permutation map for callbacks and index-based config. That also changes the layout, because the simulation deals its random values by index. Reordering at runtime is worse:
setPointPositionszeroes velocities and re-uploads everything.What
graph.setPointRenderOrder(order: ArrayLike<number> | null)changes only the drawing order. Point indices, the simulation and every other per-point array keep their meaning.null,[]or any list that resolves to index order keeps today's unindexed draw path.getSampledPointsfollow the render order, so the point on top is the one they report.How
renderRankattribute instead of the point index, because depth is the only thing the core and fringe passes agree on. In an indexed draw,gl_VertexIDis the point index, not the position in the order.GraphDatare-resolves the order only when it's reassigned or the point count changes.Demo
render-order-demo.mp4
New story: Examples / Points / Render Order.
Testing
All in the browser, since the repo has no unit-test runner:
main(A/B full-frame compare, 20k points) with culling on and off, translucent points, and highlighting.maindrawing the input arrays physically permuted the same way.history/2026/2026-09-30-point-render-order.md.npm run buildand eslint pass.🤖 Generated with Claude Code
Summary by CodeRabbit