11 KiB
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:
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:
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:
$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:
node scripts/runewaker-pipeline/audit-animated-poses.mjs --jobs 2
Audit one dungeon and keep a deterministic report for each packaged variant:
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:
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:
{
"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:
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 allfor 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.