Files
2026-09-27 18:46:30 -04:00

183 lines
11 KiB
Markdown

# Original WoW spell visuals
The runtime packages every WoW 3.3.5 visual model referenced by the current
ability manifest, across all ten WoW classes. There is no class filter in
`package-wow-original.mjs`. Ascension and RuneWaker entries retain their existing
source mappings and sound behavior.
Current coverage: 483 packaged models; 5,066 of 5,066 source phase assets; 311
mesh models, 1,711 particle emitters, 249 ribbon emitters, and 479 unique source
textures. The generated
manifest includes per-class coverage. A spell rank without a source visual
phase (for example, a passive or totem-management action) is not counted as a
missing model. This does not invent original visuals for spells with no source
mapping; the runtime still supplies its generated school fallback.
## Generate and verify
```sh
npm run effects:wow
npm run effects:audit
npm run effects:test
```
`npm run effects:meteor` packages the Ascension Mage Meteor release and impact
models used by Falling Stars. It reads the additional Ascension models from the
extracted `patch-N` directory and attaches browser-ready graphs to spell
`ascension:500135`. The full `effects:generate` command runs this step after
the WoW package step so a regenerated manifest keeps the affix visuals.
`effects:generate` rebuilds the DBC/audio mappings before packaging all WoW
visuals. `effects:priest` remains a compatibility alias for `effects:wow` so it
cannot accidentally revert the main manifest to Priest-only coverage. The old
Priest decoder and fixtures remain for compatibility tests.
The manifest collector also reads effectful boss spell IDs from
`dungeonCampaignCatalog.json`. Regenerate the dungeon catalog first whenever
boss spell semantics change. Missing or undecodable source audio falls back to
the runtime's short spatial school cue; enabled combat audio is never silently
dropped merely because a source file is absent.
Source assets resolve from the extracted sibling `LadiksMPQEditor` base-client
directories, with the sibling `wow335a/Data` archive stack recovering missing
files. Locale archives supply shared interface textures used by spell models.
Recovered files go into `.tools/wow-effects-source`; source installations are
read-only. BLPConverter8 converts the original BLPs to PNG. Model and texture
paths are checked before resolution. An incomplete run reports failures and
does not replace the active manifest.
Graph filenames hash the complete runtime payload, including source model,
skin, textures and nested model dependencies. Changes therefore get new URLs
instead of reusing an incompatible cached graph. The normal content publisher
assigns the entire `assets/game/combat-effects` tree to `core:combat-media`.
Publishing a new app/content release remains the normal deployment step.
Development gameplay uses Vite's local source media directly; release builds
retain the verified media-pack download requirement.
## RuneWaker spell media mapping
`npm run effects:rom` refreshes only RuneWaker manifest entries and packages
their sound cues without rebuilding WoW effects. It reads spell-to-image links
from `romPlayerCatalog.generated.json` and `magiccollectobject.db`. It follows
each direct MagicCollect component through `magicobject.db` to ImageObject
`ExtendACT` target models, alongside the spell's own ImageObject paths. Exact
same-name cues under the client's parallel `sound/fx` tree and zero-offset
direct ROS audio events supply phase-tagged cues. Delayed and fade-out events
stay in the batch report until their timeline has a matching runtime event.
The combat audio player layers distinct RuneWaker cues on the same phase,
including separate ROS appear and idle sounds; WoW sources retain weighted
single-cue selection.
`npm run effects:rom:particles` packages a decoded ROS particle archive for the
five primary classes and their accepted elite pairs. Build the native exporter
with `scripts/runewaker-pipeline/native/build-exporter.ps1` first. The exporter
reads ACT motion controllers, where the texture names and particle keys live;
the static entity tree alone contains default values. Set `RUNEWAKER_RESOURCE_ROOT`,
`RUNEWAKER_EXPORTER`, or `TEXCONV_BIN` to override the default source and tool
locations. The archive index at
`public/assets/game/combat-effects/original/runewaker/manifest.json` records
decoded and unsupported controller families per model. Its graphs contain the
source shader identity, blend mode, billboard settings, particle tracks, and
PNG versions of referenced DDS textures. The archive also extracts the SMUNI
vertex and pixel HLSL from the Rune engine source with a source hash. Texture
tile sizes are pixels, not atlas row and column counts.
`npm run effects:rom:audit` writes the first-five class and accepted-pair map
to `docs/ROM_SPELL_MEDIA_MAPPING.md`. It distinguishes source ROS references,
packaged audio, and browser-playable original visual graphs. The packager
enables any graph whose sprite, emitter, texture, subtree alpha, and nonvisual
event callback data meet the browser renderer's validated schema. Event IDs that spawn an
effect or control projectile flight remain blocked. Urgent Heal's target rune
and decal are an explicit partial-original exception; `rom-particle-readiness.mjs`
holds hand-reviewed scale and fidelity overrides. Other ROS phases retain
generated visual fallbacks until their controller families are implemented.
Open `scripts/combat-effects/rom-preview.html`
with the Vite dev server to inspect the decoded sprite models. The emitter
integrates source rate keys over each rendered frame so short bursts survive
slower frames. Whirlwind Shield uses a 2.5 presentation scale after live
dungeon review.
`npm run effects:rom:plan` creates `docs/ROM_MEDIA_BATCH_PLAN.md` and its
machine-readable JSON companion from the current primary-five manifest and ROS
archive. It groups models by unsupported controller family, lists fully decoded
graphs awaiting visual review, and flags embedded one-shot audio paths absent
from the manifest as candidates for timeline support. Run it after the audio
and particle package steps. The generator attaches source direct audio events
at the matching phase boundary when their motion and zero-offset timing are
known; remaining candidates require a different timeline or phase mapping.
`npm run effects:rom:batch` runs the manifest/audio pass, particle package,
manifest attachment pass, media audit, and batch plan in that order. Build the
native exporter before running it when its C++ source changes.
The Priest's holy `act_casting_c_hand.ros` has three renderable sprite layers
and one `CRuController_EventTrigger` in its `appear` motion. The RuneWaker
source identifies event 43 as looping direct 3D audio for
`sound/fx/skill/holy/act_casting_c_hand.wav`, not another visual layer. The
packager marks the model renderer-ready after validating the event's
parameters. Its packaged WAV loops only during the matching Priest cast and
stops on release or cancellation. The same source event rule applies to the
five class cohort when IDs 1, 41, 43, 44, 50, or 61 carry valid data.
Urgent Heal's target effect is linked through MagicCollect spell `491147` to
MagicObject component `501543`, whose ImageObject `573048` supplies
`ExtendACT=model/fx/skill/holy/act_benedictory_heal_t_down.ros` at `p_down`.
The client creates the component's `ExtendACT` on the target after the heal
resolves. Its `explode` motion contains two original sprite layers (holy line
and gold stars), a nested `rune_cylinder.ros` particle entity with source rune
texture, a `kan_rune_circle.dds` ground decal, and a one-shot direct 3D audio
event for `sound/fx/skill/holy/act_benedictory_heal_t_down.mp3`. The browser
plays the two sprite layers and source rune mesh emission, and animates the
decal radius, rotation, color, and alpha. The decal lies on a level plane;
the RuneWaker client projects it onto collision triangles. The graph remains
`partial-original` for that terrain projection difference while replacing
the generated target filler.
Rising Tide spell `490256` uses ImageObject `572061` for
`act_icecone01_c_hand.ros` at cast start and `act_icecone01_f.ros` on release.
MagicObject component `620408` links ImageObject `572062`, whose target
`ExtendACT` is `act_riptide_t_freeze_hit.ros` at `freeze_hit`. The source
audio events name the projectile cue
`sound/fx/skill/ice/icenew/act_icecone01_f.ros.mp3` and target cue
`sound/fx/skill/ice/act_riptide_t_freeze_hit.mp3`; the cast hand has its
mirrored WAV. The verified models are attached to their respective combat
presentation phases after their controller support and source motion checks.
## Rendering
The `wow-m2-model` format composes source particles, animated/skinned geometry,
material alpha and colors, UV transforms, and bone-driven ribbon trails. The
renderer resolves full and upright billboards, texture layers, source-space
pivots, global animation sequences, and Stand/Hold/Decay timelines. Original
geometry particles use instance pools; secondary particle emitters are bounded
to prevent recursive effects multiplying the scene budget.
The live combat path uses the same cast, projectile, impact and aura events as
before. In original mode, an instant release also renders any source-side
`cast-start` layers without publishing another gameplay or audio event. Instant
terminal events prefer their exact phase, then use the source `impact` or
`aura-start` counterpart when that is the only mapping. The source phase stays
on the render event so attachment and aura lifetime rules remain correct. This
covers all 1,106 castable instant rank records that have a packaged source
visual, including all 287 latest-rank instant abilities with source visuals.
The source catalog also contains three passive instant records with visuals;
passives do not publish combat events. Abilities without a source mapping, or
with no usable asset load, retain generated fallback. Particle budgets,
placement anchors, and travel timing remain the game's presentation rules;
this is not a claim of pixel-identical client simulation or exhaustive
spell-by-spell gameplay QA.
Decoder reference for compressed bone quaternions, float UV quaternions, and
source record layouts: [wowlib M2 records](https://skarndev.github.io/wowlib/python/m2/records/).
## Local visual inspection
Run `npm run dev` and open `/scripts/combat-effects/preview.html`. The
development-only preview lists every directly referenced model and uses the
same mesh, ribbon and particle renderer as live combat. Drag to orbit, scroll
to zoom, replay an effect, or freeze its opening frame. The preview is not
included in the production app entry point.
Runtime tests parse all shipped graphs, sample bone transforms, and verify
geometry bounds, dependency textures and billboard behavior. Browser evidence
and observed limitations are recorded in `PLAYTEST_NOTES.md`.