Files
healer-man/scripts/runewaker-pipeline/POSE_AUDIT.md
T
2026-08-14 15:56:39 -04:00

247 lines
11 KiB
Markdown

# RuneWaker evaluated-pose audit
`audit-animated-poses.mjs` checks the actual evaluated, skinned vertices of the
RuneWaker actors shipped by HealerMan. It is intentionally separate from the
clip-name/readiness audit: an animation can have the right name and duration
while applying bone rotations in the wrong coordinate basis.
## What is audited
The batch runner can discover packaged GLBs under `public/assets/creatures`, but
the authoritative full-game input is the 322 runtime-referenced shipping paths
in `artifacts/animation-audit/runtime-clip-coverage.json`. Discovery can include
unused or non-combat assets and must not be substituted for that exact list in a
release verdict. Each Meshopt shipping GLB is copied through glTF Transform to a
temporary, uncompressed GLB because Blender does not import
`EXT_meshopt_compression`. Blender then evaluates:
- the armature rest/bind pose;
- the first, middle, and final frame of every action by default;
- finite and non-finite skinned vertices;
- posed AABB, axis extents, diagonal, centroid, maximum radius, and RMS radius;
- bind-relative size, radius, and centroid-shift ratios;
- connected-topology component movement, resizing, and separation from the
bind envelope.
The temporary decompressed file is removed after each actor. The report hashes
and identifies the original packaged GLB, not the temporary copy.
## Commands
Run from `D:\Projects\HealerMan`. First regenerate the inventory and runtime
selector plan from the same shipping build that will be pose-audited:
```powershell
npm run runewaker:audit:animation-inventory
npm run runewaker:audit:runtime-clips
```
The package aliases pass additional CLI arguments through to the batch runner
and regenerate the deterministic all-dungeon report:
```powershell
npm run runewaker:audit:pose-batch -- --input-list <inputs.json> --jobs 2
npm run runewaker:audit:pose-master
```
The expected mapping is 436 entity templates to 268 base actor configurations
to 322 runtime-referenced shipping variants. Do not continue if the inventory
contract fails. Create the exact input list from the runtime plan, assert its
size, and run the complete numeric audit plus semantic-family render pass:
```powershell
$projectRoot = (Resolve-Path '.').Path
$coverageFile = 'artifacts/animation-audit/runtime-clip-coverage.json'
$coverage = Get-Content -Raw -LiteralPath $coverageFile | ConvertFrom-Json
$inputs = @(
foreach ($dungeon in $coverage.samplePlanByDungeonAndAsset.PSObject.Properties) {
foreach ($asset in $dungeon.Value.PSObject.Properties) {
(Join-Path $projectRoot $asset.Value.glb).Replace('\', '/')
}
}
) | Sort-Object -Unique
if ($inputs.Count -ne 322) {
throw "Expected 322 runtime shipping variants; found $($inputs.Count)."
}
$inputList = Join-Path $projectRoot 'artifacts/animation-audit/v5-pose-inputs.json'
$inputJson = @{ inputs = @($inputs) } | ConvertTo-Json -Depth 3
[System.IO.File]::WriteAllText(
$inputList,
$inputJson + [Environment]::NewLine,
[System.Text.UTF8Encoding]::new($false)
)
node scripts/runewaker-pipeline/audit-animated-poses.mjs `
--root public/assets/creatures `
--input-list $inputList `
--output-dir artifacts/animation-audit/batches/v5-full `
--summary artifacts/animation-audit/batches/v5-full/summary.json `
--jobs 2 `
--sample-mode all `
--render-mode families `
--render-limit 24 `
--contact-sheets
node scripts/runewaker-pipeline/make-pose-audit-review-pages.mjs `
artifacts/animation-audit/batches/v5-full
```
`--sample-mode all` numerically evaluates first, middle, and final samples from
every action. `--render-mode families` renders a bounded representative
semantic-family set for every shipping variant; it does not reduce the numeric
action plan. Preserve the runtime coverage JSON, input list, pose reports,
contact sheets, and review pages together. Their hashes identify the exact
shipping build under review.
Running discovery without an input list remains useful as a broader diagnostic,
but its count is not the runtime contract:
```powershell
node scripts/runewaker-pipeline/audit-animated-poses.mjs --jobs 2
```
Audit one dungeon and keep a deterministic report for each packaged variant:
```powershell
node scripts/runewaker-pipeline/audit-animated-poses.mjs `
--include '^paspers-shrine/' `
--jobs 2 `
--output-dir runewaker-export-work/pose-audit-paspers
```
Render one representative middle frame per detected semantic family and make a
contact sheet:
```powershell
node scripts/runewaker-pipeline/audit-animated-poses.mjs `
--input public/assets/creatures/paspers-shrine/fog-ferocity-03.glb `
--render-mode families `
--contact-sheets
```
Use `--render-mode flagged` to render only numeric outliers, or
`--render-mode all` for every sampled frame. `--render-limit` bounds disk and
rendering cost. Reports can be reused only when the shipping SHA-256 still
matches by adding `--resume`.
An inventory job can supply the exact runtime-used variant set as a JSON array
or an object containing an `inputs` array:
```json
{
"inputs": [
"D:/Projects/HealerMan/public/assets/creatures/paspers-shrine/fog-ferocity-03.glb",
{ "file": "D:/Projects/HealerMan/public/assets/creatures/paspers-shrine/fog-loster-03.glb" }
]
}
```
Pass it with `--input-list inventory.json`. Relative paths are resolved from
the inventory file's directory. Input and Blender paths are converted to
absolute paths before subprocesses start, so Blender changing its working
directory cannot redirect a source or report.
## Required human visual review
Numeric status is triage, not acceptance. A wrong quaternion basis can keep all
values finite and leave the GLB Khronos-clean. A reviewer must inspect the
contact sheet for every one of the 322 variant paths, including numeric passes,
and compare warnings with their per-sample metrics. Any folded or inverted
limb, exploded skin, detached equipment, discontinuity, or ambiguous extreme
pose must be rerun with `--render-mode all` and, when necessary, compared with
the original-client animation.
After actual inspection, create a review input using
`batch-a-visual-review-input.json` as the schema reference. Its
`reviewedVariants` must exactly match `summary.json`; include both
`demon-stronghold-125` and `zurhidon-stronghold-124` in
`explicitEmptyDungeons`, and record a reason for each. The compiler verifies
inventory equality but cannot perform or infer the visual review:
```powershell
node scripts/runewaker-pipeline/compile-pose-audit-review.mjs `
artifacts/animation-audit/batches/v5-full `
artifacts/animation-audit/batches/v5-full/v5-visual-review-input.json `
artifacts/animation-audit/batches/v5-full/v5-review.json `
artifacts/animation-audit/batches/v5-full/v5-review.md
```
## Completed v5 disposition
`artifacts/animation-audit/post-v5/summary.json` contains all 322 runtime paths
and 44,305 evaluated poses: 282 actors passed numerically, 40 are
accepted-warning candidates, and there were zero errors and zero
Blender/decompression/report failures. The 634 flagged samples exactly match
the totals from the visually reviewed v4 batches; no new numeric deformation
signature appeared after the v5 cast-semantics rebuild. Mantarick accounts for
the expected static-pose warning, and Sardo's red Rune Warning Device retains
its intentional native no-locomotion exception.
The rebuilt inventory is green at 30/436/268/322 with zero blockers, and the
runtime selector reports zero semantic near misses. The packaged/offline browser
showed all 30 dungeons Ready and loaded both Pasper's Shrine and Hall of
Survivors with no animation or WebGL errors. Only an unrelated library
deprecation warning appeared. These results complete the v5 pose disposition;
the sampling and original-client comparison limits below still apply.
All 19 focused RuneWaker animation tests pass. The unfinished RoM class catalog
and missing Manastorm fixtures remain unrelated repo-wide build/test blockers.
## Report contract
Every `<actor>.pose-audit.json` is timestamp-free and deterministically ordered.
`variantId` is the stable packaged path below the selected discovery root, so
actors with the same basename in different dungeons remain distinct.
Its `sampling.actionPlan` is the machine-readable audit plan: action index,
exact action name, semantic family, action frame range, and every frame label
and value selected for evaluation. `samples` records the resulting metrics,
bind comparisons, and issue codes. `summary.status` is one of `pass`, `warning`,
or `error`.
The batch `summary.json` records one row per packaged input path. Numeric
warnings do not fail the command because unusual animations can intentionally
detach weapons or body parts. A Blender/decompression/report failure does fail
the command.
The documented Mantarick exception (Hall of Survivors template `102452`, asset
`judgement-light-pose`) contains static posed meshes without an armature. It is
still checked for finite geometry and bounds, and is reported as
`static-pose-only` with a `pose-only-no-armature` warning rather than failing the
batch. It is the only approved pose-only runtime variant.
Sardo Castle template `105758` (`rune-device-red`, Rune Warning Device) is a
native stationary device, not pose-only. Its source animation set intentionally
has no locomotion. A missing-moving warning is acceptable only for this asset;
its idle, configured combat, wound, and death actions still require numeric and
visual review.
## Regression proof for the Pasper goatmen
The preserved pre-fix v3 cache files and the shipping v4 files captured for the
quaternion repair were audited with all actions:
| Actor | Source | Poses | Flagged samples |
| --- | --- | ---: | ---: |
| Giant Assassin | pre-fix cache `2dd9e271a1296f39cb35864b.glb` | 61 | 51 |
| Blackhorn Silencer | pre-fix cache `921ccbe5f2225bf2f02a3136.glb` | 61 | 51 |
| Giant Assassin | v4 `paspers-shrine/fog-ferocity-03.glb` capture | 61 | 0 |
| Blackhorn Silencer | v4 `paspers-shrine/fog-loster-03.glb` capture | 61 | 0 |
The old poses were caught by connected-component movement even though their
whole-character AABB diagonal stayed near the bind size. This is why global
bounds alone are not sufficient for this regression. The v4 comparison proves
the quaternion repair, while the completed 322-variant post-v5 audit proves the
cast-semantics rebuild did not change the aggregate evaluated-pose result.
## Limits
- Numeric shape checks cannot prove semantic correctness, timing quality,
attack impact alignment, or that a clip is the intended RuneWaker clip.
- Start/middle/end sampling can miss a defect isolated between those frames.
- Family contact sheets render representative frames, not every frame of every
action. Use `--render-mode all` for suspicious actors, then test timing and
transitions in the browser.
- Deliberately detached parts, projectiles, trails, and extreme attacks may
require visual review rather than automatic rejection.
- Component metrics require the evaluated modifier stack to preserve vertex
count and ordering.
- Contact sheets are evidence aids, not replacements for an in-game playtest.