Skip to content

🦄feat(web,desktop): check a material setup against its export - #850

Draft
polynaut wants to merge 2 commits into
mainfrom
feature/material-plan-from-export
Draft

🦄feat(web,desktop): check a material setup against its export#850
polynaut wants to merge 2 commits into
mainfrom
feature/material-plan-from-export

Conversation

@polynaut

@polynaut polynaut commented Aug 15, 2026

Copy link
Copy Markdown
Owner

A DazToHue material slot claims Daz surfaces by plain text, and so does every
texture baker layer. Change the scene — swap a graft out, drop an outfit — and
those claims keep naming surfaces that no longer exist: measured on DazToHue
2.5, a baker in that state finishes normally and bakes nothing, and Houdini
reports neither half. Nothing in the pipeline could see it.

Where the answer was

The .dth the HDA imports already carries a Materials list — one entry per
Daz surface, with the asset that owns it, the Daz content type and every
channel's texture path. Measured on a real export (LaraCroft_G81, DTH 2.0.2):
Material Name is verbatim the surface a slot claims — 26 of 26 exact matches
against that character's own scanned .hiplc. So the new Export check tab
needs no hython, opens no .hip and writes nothing; its two inputs are the
stored scan and a JSON file the studio itself wrote.

It reports claims the export does not back, baker layer groups it does not
back, and what a setup built from that export alone would look like — grouped
by the Daz content type, which is vendor-authored, so no heuristic is involved
(the eye stack is the one name match, and is marked as such).

  • Unclaimed surfaces are grouped by content type and never flagged: a "naked"
    variant node is supposed to leave its wardrobe unclaimed.
  • A project importing several scenes is refused rather than guessed at — the
    scan records imports per project, not per node.
  • A texture-derived proposal is partial by construction; a baker built from a
    constant cannot be read out of an export. Said in the tab, not implied away.

The scan now records baker layer groups (bakerGroups) — it already computed
them and threw them away. SCAN_ANSWER_VERSION → 7 so existing entries re-earn
their verdict instead of answering the new question with [].

Not verified

The tab has never rendered against real data — the 6 new smoke specs drive the
real SPA end-to-end but against the fake native layer. The Python change is
unexercised for the same reason the rest of material_utils is (no harness; it
only runs inside hython). bakerGroups stays empty until the first rescan.

The three most likely to be wrong, in the order I would bet on them: the
baker-groups row (the only unexercised path — if it reads none on a project
with 6 bakers after the rescan, that is the bug); the proposal's slot/baker
naming and where the eye stack lands (judgement calls made from two projects);
and the unclaimed list reading as alarming on a "naked" variant, where it is
correct and the fix would be presentational.

Generation — the write half — is #851, which carries the design and the one
measurement it is blocked on.

Test plan

  1. Open a character with a linked Houdini project → Utils → Export check.
    The first open re-runs the background scan (version bump), so give it a
    moment before the baker-groups row means anything.
  2. On LaraCroft_G81 it should name the five GP* claims left behind by the
    Golden Palace removal and the metal1 / metal_1 mismatch — and say
    whether the skin bakers' layers still carry the GP groups too.
  3. Toggle One clothing slot / One slot per garment and check the
    proposal against what you would have built by hand.
  4. A character that has never been exported should say to run a DTH Export
    once, not show an empty setup.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JHYR4PVb5KgaknwGSmL6wH

…ts export

Every DTH Export already writes a Materials list into the .dth the HDA imports
— one entry per Daz surface, with the asset that owns it, the Daz content type
and every channel's texture path. Nothing in the studio read it. Measured on a
real export (LaraCroft_G81, DTH 2.0.2): Material Name is verbatim the surface a
DazToHueMaterial slot claims, 26 of 26 exact matches against that character's
own scanned .hiplc.

The new Export check tab answers two questions nothing else in the pipeline
can. Does this setup still match the scene — slot claims and baker LAYER groups
both bind by plain text, so removing a graft leaves both pointing at surfaces
that no longer exist, and a baker in that state finishes normally and bakes
nothing. And what would a setup built from this export look like — the Daz
content type is vendor-authored, so the grouping needs no heuristic.

Read-only: no hython, no .hip opened, nothing written. The two inputs are the
stored scan and a JSON file the studio's own pipeline wrote.

The scan now records the geometry groups each baker layer names; it already
computed them and _node_info threw them away. SCAN_ANSWER_VERSION 7 retires
entries that would otherwise answer the new question with an empty list.

Two scoping rules the diff keeps rather than guessing: a project importing
several scenes is refused (the scan records imports per project, not per node,
so a node cannot be attributed), and unclaimed surfaces are grouped by content
type and never flagged — a "naked" variant is supposed to leave its wardrobe
unclaimed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JHYR4PVb5KgaknwGSmL6wH
The tab shipped in the previous commit with no guide page and two rough edges,
both found by writing the documentation and looking at the result.

- **The read-only tab was offering a Transfer button.** The drawer footer
  branched only on `tab === 'general'`, so Export check fell through to the
  TRANSFER footer: a Transfer button over "0 target nodes selected", which is
  the material tab's (empty) selection, on a tab that cannot transfer anything.
  It gets no footer now — it has no action of its own.

- **`material-plan.ts` was invisible to ripgrep.** The composite Map key joined
  slot and channel with a literal NUL BYTE, which makes the whole file `binary`
  to rg: every repo-wide grep silently skipped it, and the file read as absent
  rather than as a non-match. Same string, written as the escape, plus a comment
  saying why it must stay one.

The guide section covers what the tab answers and what it deliberately will not:
the four per-node verdict rows and why "Surfaces with no material" is never
flagged (a "naked" variant is supposed to leave its wardrobe unclaimed), the
proposed setup and its wardrobe toggle, that a proposal read from textures is
partial by construction, and the four ways it says it cannot answer rather than
showing a clean result. Plus its screenshot, driven by a new test in
guide.screenshots.ts.

That shot reuses the behaviour spec's fixture rather than copying it —
houdini-export-check.smoke.ts and the screenshot now share EXPORT_CHECK_* in
smoke/fixtures.ts, so the picture in the guide cannot drift away from the state
that is actually asserted.

Gates: build:guide, screenshots 46/46 incl. coverage, drawer smoke 10/10,
typecheck, lint within baseline.
Not verified: still not run against a real Houdini project — that is the
2026-08-17 test on LaraCroft_G81, and nothing here changes what it will show.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JHYR4PVb5KgaknwGSmL6wH
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Site preview deployed

Preview (this PR) https://pr-850.dth-character-studio.pages.dev
Guide https://pr-850.dth-character-studio.pages.dev/guide/
Exactly this commit https://fef5d8d9.dth-character-studio.pages.dev

Redeploys on every push to this PR. Production stays on GitHub Pages.

@polynaut
polynaut marked this pull request as draft August 18, 2026 06:15
@polynaut polynaut changed the title feat(web,desktop): check a material setup against its export 🦄feat(web,desktop): check a material setup against its export Aug 18, 2026
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