Skip to content

feat(editor): indent guides, one caret column, and a band for the reference rows - #47

Closed
pythonlearner1025 wants to merge 1 commit into
mainfrom
feat/tree-reference-rows
Closed

pythonlearner1025 wants to merge 1 commit into
mainfrom
feat/tree-reference-rows

Conversation

@pythonlearner1025

Copy link
Copy Markdown
Member

What part this touches

The Objects panel of the Kite3D editor, and the tree it draws.

packages/editor/src/components/Tree2.tsx is the editor's own copy of Blueprint's tree.
TreeNode2.tsx draws one row: a caret, an icon, a name.
tree2.scss styles both. BPHierarchyComponent.tsx fills the tree with the scene.

Since #42 a mesh also gets reference rows under it. A reference row is the mesh's geometry, one of
its materials, or a texture slot of a material. A reference row points at a resource. It is not a
child: the same resource appears under every object that uses it, and nothing there can be dragged,
reordered or deleted.

This change is the "Chosen" card of the owner's mock, tree-options.html.

The problem

Open a mesh in the Objects tree. Its reference rows read as its children. The next sibling mesh
reads as one of them too.

Two causes. I measured both on /Users/minjunes/games/terminator-next, headless, at 1512x982.
The branch is Map, Bunker_7, Walls, Wall_segment_1, Wall segment asset, Wall segment concrete.

First, a row with no caret started 26 px left of a row with one. This rule collapsed the caret slot:

.bp5-tree-node-content:has(.bp5-icon) {
  .bp5-tree-node-caret, .bp5-tree-node-caret-none {
    min-width: 0px;
  }

So rows at one depth began at different x. Both of these rows sit at depth 6:

row depth caret slot x caret width icon x name x
(BufferGeometry) 6 60 0 60 95
Map concrete 6 60 26 86 133

The texture rows at depth 7 put their icons at x 70. The mesh at depth 5 put its icon at x 76.
A row two levels deeper started 6 px further left than its own grandparent.

Second, the tree drew no indent guides. Nothing marked where a subtree ended. The last texture
row's name sat at x 105. The next sibling mesh Wall segment rust put its name at x 102. Three
pixels apart, so the mesh read as one more reference.

The fix

  • Every row draws one vertical guide per ancestor, the way VS Code and Godot draw them.
  • A guide's depth comes from the bp5-tree-node-content-N class the row already indents by.
    The guides and the indent can never disagree.
  • The caret column is 26 px on every row. It stays empty when there is nothing to open.
  • A row with no icon keeps an icon column of the same width.
    Its name then starts where its siblings' names start.
  • A reference row's own levels draw a dotted guide, not a solid one.
  • The reference rows of one object carry a tint and a 2 px rule at their left. The block starts at
    the first reference and ends at the last.
  • A material's texture slots stay inside that block, one level deeper, on a dotted guide.
  • The depth classes run to 20, the range Blueprint defines. A row deeper than ten now keeps the
    editor's 10 px step instead of falling back to Blueprint's 23 px.
  • Reference rows keep everything feat(editor): one Resources tab, and reference rows under each mesh #42 gave them: italic, the link glyph, no drag, no menu.

Two files changed: packages/editor/src/components/tree2.scss and TreeNode2.tsx. The stylesheet
does all the drawing. The component change is one empty span for the icon column.

The risk trade

The cost is horizontal space. A row with no caret gains 26 px, and a row with no icon gains 26 px.
In the Resources tab all 760 rows are flat leaves with no caret. Every one of them moves 26 px
right and gains nothing.

What lowers the cost: the tree already scrolls sideways, and the panel already resizes. On this
scene the open branch measured 325 px against a 276 px viewport before the change. The panel
scrolled already. Scrolled right, the names read in full, and the band scrolls with the rows.

The rejected alternative is option C of the mock: chips on the mesh row, and no reference rows at
all. It costs no rows and cannot be misread. It also drops the geometry name and the texture slots
from the tree. The owner picked the rows.

I also rejected leaving the caret column at zero and marking the references with the band alone.
The band would then hide a real defect: rows at one depth would still begin at different x.

Tests

No automated test is added. AGENTS.md bans proactive tests, and this is a stylesheet change with
no reported flake behind it. The proof is the manual headless run.

Every run used Playwright with the owner's Google Chrome, headless, viewport 1512x982, device pixel
ratio 2, a fresh profile. Nothing took focus. Every server ran with CI=1. I never ran
kite3d install.

cd /Users/minjunes/games/terminator-next && CI=1 node \
  /Users/minjunes/kite3d-worktrees/tree-rows/packages/kite3d/dist/cli.js dev --port 4475 --no-open

I confirmed before each run that the served editor was my build. I fetched each asset from the
server and matched its sha256 against packages/editor/dist/assets. All three matched both times.

The columns, before and after

The same branch, opened down to the first mesh's references and its material's texture slots.
"caret slot x" is the row's left edge plus its indent, which is where the caret sits.

row depth caret slot x caret width icon x name x
Wall segment concrete, before 5 50 26 76 102
Wall segment concrete, after 5 50 26 76 102
(BufferGeometry), before 6 60 0 60 95
(BufferGeometry), after 6 60 26 86 121
Map concrete, before 6 60 26 86 133
Map concrete, after 6 60 26 86 133
texture rows, before 7 70 0 70 105
texture rows, after 7 70 26 96 131
Wall segment rust, before 5 50 26 76 102
Wall segment rust, after 5 50 26 76 102

After the change every row at one depth shares its caret x and its icon x. The gap between the
texture names and the next sibling mesh's name grew from 3 px to 29 px.

What fails without the fix

I rebuilt the editor from git stash, served it, and ran the same scripts. The table above is that
run. Without the fix the geometry row and the material row sit at one depth. Their icons are 26 px
apart. The sibling mesh's name lands 3 px from the texture names.

The band

after-report.json reads the computed background of each row around the block. Seven reference
rows carry the band: the geometry, the material, and the material's five texture slots. The mesh
above it, the sibling mesh below it, and the next asset row all read background-image: none.

The screenshots I looked at

All under
/private/tmp/claude-501/-Users-minjunes-blitz/278f5f97-7e16-4722-b1bc-c061014966db/scratchpad/evidence/tree-reference-rows/.

  • compare-before-after.png: the panel before and the panel after, side by side.
  • compare-after-mock.png: the panel after, beside the "Chosen" card of the mock. The guides, the
    dotted levels, the tint and the left rule read at the same weight.
  • zoom-band-hover.png: the block at three times size, with a reference row hovered. The hover
    colour still shows through the tint.
  • shots/after-light-objects-expanded.png: the light theme. One colour token serves both themes.
  • shots/after-resources.png: the Resources tab. Its rows are all at depth 0, so no guides are
    drawn, and the rows read as before.
  • shots/after-scrolled-right.png: the tree scrolled 38 px right. The band scrolls with the rows.
  • shots/after-dark-mesh-closed.png: the mesh closed. The band goes with its rows.
  • zoom-selected-row.png: a selected row with the context menu open. The band and the selection
    highlight end at the same x, which is the tree's scrollport edge.

The edges

  • A row deeper than ten. The scene's deepest row is a texture at depth 7. So I read the served
    stylesheet instead, on a hidden probe row. Depths 1, 5, 10, 11, 12 and 20 all answered
    padding-left and guide width of 10 px times the depth. after-deep.json.
  • Hover over a reference row. The row keeps background-color: rgba(143, 153, 168, 0.15) under the
    band, so the hover still reads. Dark and light both.
  • A closed mesh. Zero rows carry the reference class, so no band is drawn.
  • The tree scrolled sideways. The band and the guides scroll with the rows. The 2 px rule scrolls
    out of view with the rest of the row. The selection highlight does the same.
  • A one row block. The CSS styles each reference row on its own. A mesh with only a geometry gets
    a block of one row. No special case exists to break.

No change in behaviour

I ran the same script against the build before the fix and the build after it. The two reports are
equal, field for field: behaviour-diff.txt says identical: True.

action result
click an object row the row is selected, the Inspector shows the object
double click an object row the row stays selected, the Inspector shows the object
right click an object row the context menu opens with Isolate
right click a reference row no menu opens, the resource goes to the Inspector
click a geometry or material row the resource goes to the Inspector, no tree row is selected
double click a material row the Resources tab opens on that material
drag a scene object row the tree takes bp5-tree-dragging-node, and drops it on drag end
draggable on a reference row false

Zero page errors in every run.

The suites

npm run typecheck      pass
npm run lint           pass
npm test -w packages/kite3d   5 files, 8 tests, all pass
npm run test:scripts          2 tests, all pass

Deploy

The editor bundle ships it. @kite3d/editor holds the stylesheet, and kite3d dev serves that
package's dist. Nothing in packages/kite3d changed.

npm ci
npm run build
npm run release

To roll back, publish the previous @kite3d/editor from npm, version 0.21.0-alpha.5. A user on an
older kite3d keeps the old editor, because kite3d pins the editor version it depends on.

🤖 Generated with Claude Code

…erence rows

The Objects tree drew no indent guides, and a row with no caret started 26 px
left of a row with one. A mesh's reference rows from #42 therefore read as its
children, and the next sibling mesh read as one of them.

- Every row draws one vertical guide per ancestor. The guide comes from the
  depth class the row already indents by, so the two can never disagree.
- The caret column is 26 px on every row, empty when there is nothing to open.
  A row with no icon keeps an icon column the same way.
- A reference row's own levels draw a dotted guide, not a solid one.
- The reference rows of one object carry a tint and a 2 px rule at their left,
  from the first reference to the last.
- The depth classes run to 20, the range Blueprint defines, so a row deeper
  than ten keeps our 10 px step.

Proved headless on /Users/minjunes/games/terminator-next at 1512x982. At one
depth every row now shares its caret x and its icon x: the geometry row's icon
moved from 60 to 86, where the material row's already was. The texture rows'
icons moved from 70 to 96, clear of the depth 5 mesh at 76. Click, double
click, drag and the context menu read byte for byte the same before and after.
npm run typecheck, npm run lint, npm test -w packages/kite3d (8 tests) and
npm run test:scripts (2 tests) all pass.
@pythonlearner1025
pythonlearner1025 deleted the feat/tree-reference-rows branch September 17, 2026 00:54
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