Skip to content

fix(editor): the Inspector header stays one line on a long path - #46

Closed
pythonlearner1025 wants to merge 1 commit into
mainfrom
fix/inspector-header
Closed

pythonlearner1025 wants to merge 1 commit into
mainfrom
fix/inspector-header

Conversation

@pythonlearner1025

Copy link
Copy Markdown
Member

What part this touches

The editor's right panel holds the Inspector. Its first row is the Inspector header.

InspectorPanelComponent builds that header. It makes one title string and one icon, and it
makes the buttons that belong to what you picked: Reload Asset, Save Asset, Edit Asset. It hands
all of it to InsSectionHeader, which is a Blueprint ButtonGroup 30px tall. The group holds
InsSectionTitle first and the buttons after it.

InsSectionTitle is the file this PR changes. It draws the icon and the title text.

The title text says different things in different states. It is the document name when nothing is
picked. It is Editing: <asset path> when you open an asset. It is <asset path> > <object name>
when you pick a mesh inside a placed asset. It is the file path when you pick a file in the Files
panel. An asset path in this project is long, for example
assets/models/map/wall-12x3x1/wall-12x3x1.gltf.

The bug

The owner picked a mesh inside a placed asset in the terminator scene. The panel was about 300px
wide. The header read:

Editing: assets/models/map/wall-12x3x1/wall-12x3x1.gltf ⮕

The text wrapped onto three lines. The row is 30px tall and centres its content, so the text spilled
above the row. The first line ran under the panel's top edge and was cut off. The text covered the
Reload and Save buttons. The Geometry section row below sat against the wrapped text.

I reproduced it at a 260px panel. Six of ten header states wrapped. The header read scrollHeight
54 against clientHeight 30. The painted text started 24px above the header's own top edge.

Two lines of InsSectionTitle caused it. The title had width: "100%", so its flex base was the
whole row. It had no min-width, so its automatic minimum size was its min-content width, the
longest unbreakable run of the path. A flex item never shrinks below that. So the title kept its
width, wrapped inside it, and pushed the buttons out of the panel.

The fix

  • The title sets white-space: nowrap, so it never wraps.
  • The title sets min-width: 0 and drops width: "100%", so it shrinks and hands width back.
  • The buttons keep their place. Blueprint already gives them flex: 0 0 auto. No change was needed.
  • The title splits at its last slash. The part in front is the folder, the part after is the name.
  • The folder is dimmed with var(--pt-text-color-muted) and takes flex-shrink: 100. The name takes
    flex-shrink: 1. So the folder gives up its width first and the file name is what survives.
  • Both parts use overflow: clip, not overflow: hidden. A hidden box is a scroll container, and
    Chrome adds 11px of scrollbar width to its intrinsic size. That opened a hole in the middle of
    every path, even when nothing was truncated.
  • Both parts use text-overflow: ellipsis, so a cut is visible as ….
  • The title element carries the whole title in its title attribute, which is the tooltip.
  • The icon takes flex: 0 0 auto, so it never shrinks.
  • alignContent: "center" is deleted. It only centred wrapped lines, and the row cannot wrap now.

The risk trade

overflow: clip needs Chrome 90, Safari 16 or Firefox 81. An older browser falls back to visible,
and the folder would paint over the file name. The editor runs in a desktop browser the CLI opens,
so this is a browser from 2022 or later. I took the cost because overflow: hidden charges 11px of
scrollbar gutter on both parts of every path. I measured it: offsetWidth 143 against scrollWidth
132 for one folder span. That hole showed even when the path fit.

I rejected direction: rtl on one span, which the design note offered as the simpler option. I
rendered it against the split at four widths. It kept the picked child name and threw the file name
away, which is backwards. It also moved the trailing slash of a path to the front, so
assets/textures/roster/ drew as /assets/textures/roster. The screenshot is
/private/tmp/claude-501/-Users-minjunes-blitz/278f5f97-7e16-4722-b1bc-c061014966db/scratchpad/evidence/inspector-header/shots/variants.png
and .../shots/folder-variants.png.

I rejected splitting the arrow and the child name into a third part. At the narrow width the folder
already collapses to nothing, so the third part would win at most one more character.

flex-shrink: 100 is a ratio, not a threshold. It means the folder gives up width a hundred times
faster than the name. Nothing breaks at another value; the folder would just fight longer.

The split is a rule about strings: the text after the last slash is the name. A title with no slash
draws as one part, which is every short title (main.scene.gltf, Selection). I checked both.

Tests

No test was added. This is layout that a browser decides, and the existing suites do not render the
editor. The proof is the headless run below.

Headless Google Chrome 153, the owner's own binary, viewport 1512x982, device pixel ratio 2, a fresh
profile each run. Nothing took focus. The project is /Users/minjunes/games/terminator-next, served
with CI=1 on port 4474 with --no-open. I never ran kite3d install.

I confirmed the served editor was my build. I fetched each bundle and matched its sha256 against
packages/editor/dist/assets. All three matched, in
.../evidence/inspector-header/served-is-my-build-after.txt. The served bundle also holds the
pt-text-color-muted string this change adds.

The harness drags the right panel separator, walks ten header states, and reads each one. It counts
the line boxes the text paints, not the box that holds them, because the box keeps its 24px however
the text wraps. It hit-tests the middle of every button to prove the title does not cover it.

Ten states per run: the scene document with nothing picked, a plain scene object, an asset root, a
mesh inside a placed asset, an open object document, a mesh inside an open object document, a
material document, a texture document, a file picked in the Files panel, and the Instance branch.

right panel before, one line after, one line before, header scroll/client after
260px 4 of 10 10 of 10 54/30 on the asset case 30/30
152px 3 of 10 10 of 10 54/30 on the asset case 30/30
419px not run 10 of 10 30/30

Before, the painted text of the asset case started at y 57 while the header starts at y 81. That is
the cut off first line the report describes. After, it starts at y 88 and ends at y 103, inside the
header. Before, no state had a tooltip. After, all ten carry the full title.

The screenshots I looked at, all under
/private/tmp/claude-501/-Users-minjunes-blitz/278f5f97-7e16-4722-b1bc-c061014966db/scratchpad/evidence/inspector-header/:

  • shots/before-object-doc-child.png and shots/after-object-doc-child.png: the reported case. The
    before shot shows the title on five lines. The top ones run above the panel edge and are cut off.
    The Reload button sits over the text and the Save button is gone. The after shot shows one line,
    both buttons, and the Wall Segment Concrete row clear below it.
  • shots/before-sheet.png and shots/after-sheet.png: all ten states at 260px, stacked.
  • shots/before-narrow-sheet.png and shots/after-narrow-sheet.png: all ten at the 152px minimum.
  • shots/after-wide-sheet.png: all ten at 419px. assets/textures/roster/liquid-normal.png draws
    as one unbroken path, which is the check that the scrollbar gutter is gone.
  • zoom/after-texture-doc-head.png: the header at six times size, where I first saw the hole.
  • shots/variants.png, shots/folder-variants.png, shots/clip-variants.png: the rejected designs.
  • states-table.txt: every number above.

Edges I tested:

  • The 152px minimum panel with two buttons. Text room falls to about one character. The header stays
    one line, both buttons stay inside the panel, and the tooltip still carries the path.
  • The 419px wide panel. Nothing truncates and the path reads whole.
  • A title with no slash. It draws as one part with no dimmed half.
  • The Instance branch. No object in this project reaches it, because everything the asset manager
    loads carries _tpRootPath. I deleted that one field on a placed asset in memory to reach it, and
    saved nothing. It draws one line.
  • A file picked in the Files panel, which is the only state with a path and no buttons.

What fails without the fix: the six states marked in the before table, on the same harness, on the
baseline build of the same commit. I built the baseline, measured, restored the fix and measured
again, so the two runs differ only by this file.

Suites, all from the worktree: npm run typecheck exit 0, npm run lint exit 0,
npm test -w packages/kite3d 5 files and 8 tests passed, npm run test:scripts 2 tests passed.

Not tested: the environment map popup in objectApplyCommands.tsx draws the same header. Its title
is a library id or a texture name. Neither holds a slash. So it takes the one-part path I did shoot.
I could not drive its trigger headlessly. It needs an HDRI dragged onto the canvas. Please drop an
HDRI on the viewport once. Check that its popup header reads right.

Deploy

The editor bundle ships this. It reaches users through the next kite3d release on npm.

npm ci
npm run build
npm publish -w packages/kite3d

Rollback: install the previous version from npm, npm i -g kite3d@0.21.0-alpha.5. The change is one
file with no state, no storage and no schema, so a rollback needs nothing else.

The Inspector header put the title and its buttons in one row, and the title
could wrap. A picked mesh inside a placed asset writes a long title, for example
"Editing: assets/models/map/wall-12x3x1/wall-12x3x1.gltf > Wall_segment_concrete".
At a 260px panel that title took five lines. The row keeps its 30px height, so
the text spilled 24px above the panel's top edge and the first line was cut off,
it covered the Geometry row under it, and it pushed the Reload and Save buttons
out of the panel. The title's flex base was width 100% and its automatic minimum
size was min-content, so it never gave width back to the buttons.

The title is now one line at every panel width. It sets white-space nowrap,
min-width 0 and no width 100%, so it shrinks and the buttons, which Blueprint
already gives flex 0 0 auto, keep their place. The title splits at its last
slash: the folder part is dimmed and shrinks a hundred times faster, so the file
name and the picked child name are what survive. Both parts use overflow clip,
not hidden, because a hidden box is a scroll container and Chrome reserves 11px
of scrollbar width inside it, which opened a hole in the middle of the path. The
whole title is the tooltip, which is where a long path belongs.

Verification: headless Chrome 153, viewport 1512x982, the terminator-next
project, the right panel dragged to 260px, 152px and 419px. Ten header states
each time: the scene document, a plain scene object, an asset root, a mesh in a
placed asset, an open object document, a mesh in an open object document, a
material document, a texture document, a file picked in the Files panel, and the
Instance branch. Before, six of ten wrapped and the header read scrollHeight 54
against clientHeight 30; after, all ten read one line and 30 against 30, every
button hit-tests to itself and sits inside the panel, and the title attribute
carries the full path. Typecheck, lint, the kite3d suite (8 tests) and the
scripts tests (2 tests) all pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@pythonlearner1025
pythonlearner1025 deleted the fix/inspector-header branch September 17, 2026 00:41
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