docs(link): one direction, not five — and it is index 0

Only the viewer-facing direction is wanted for players and monsters, so
direction leaves the key entirely (§5.1) rather than being a segment nobody
varies. Every depth count in §11 falls by exactly 5x.

Which index that is was rendered, not looked up: all five directions for a
human, a wolf and a dragon. Index 0 is head-on — face, chest and front legs —
and index 4 is directly away, with a quadruped's tail toward the camera. The
small-thumbnail version of the same test suggested the opposite, which is why
the finding is in the doc rather than in someone's head.

Measured consequence: body 400 drops 1,050 -> 210 frames, and a complete
one-direction set for all 1,144 bodies is ~173,000 frames (~170 MB) rather than
~865,000. That moves a bulk-fill-everything switch from "never" to something
phase 5 should leave room for.

One caveat kept as an open question: index 0 is the least legible view for
four-legged creatures — a head-on wolf is a dark blob, a side-on wolf is a wolf
— so the extractor takes the index as configuration defaulting to 0, and §17
asks whether the catalogue should default to 1 or 2 instead.

No client-derived image is committed; the render was inspected and discarded.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
This commit is contained in:
2026-09-10 00:47:14 -05:00
parent 556141341f
commit 0c3f0d65cc

View File

@@ -54,7 +54,7 @@ Two of those rows are load-bearing and are dealt with in §4 and §9. The rest s
referenced by the plugin's own build.** referenced by the plugin's own build.**
Depth, for §11's sizing: body 400 (human male) has **35 actions × 5 directions = 1,050 frames**. Depth, for §11's sizing: body 400 (human male) has **35 actions × 5 directions = 1,050 frames**.
One body. One body. §5.1 cuts that by exactly 5×.
--- ---
@@ -189,8 +189,8 @@ the hash key, the filename stem and the manifest row id:
static/3922 one item graphic static/3922 one item graphic
static/3922/h33 the same graphic, hue 33 applied static/3922/h33 the same graphic, hue 33 applied
land/3 one land tile land/3 one land tile
body/34/a0/d1 creature body 34, action 0, direction 1, first frame body/34/a0 creature body 34, action 0, first frame
body/400/a0/d1/f0..f9 human male, action 0, direction 1, all ten frames body/400/a0/f0..f9 human male, action 0, all ten frames
cliloc/enu the whole converted string table (not an image) cliloc/enu the whole converted string table (not an image)
tree/Spawns/Trammel.xml a ServUO tree file (§10) tree/Spawns/Trammel.xml a ServUO tree file (§10)
``` ```
@@ -201,12 +201,38 @@ Three properties this shape buys:
(`BridgeMarket.cs:582`, `BridgeProfile.cs:314`), so a marketplace listing already knows the exact (`BridgeMarket.cs:582`, `BridgeProfile.cs:314`), so a marketplace listing already knows the exact
key for its own picture. Applying hues website-side would mean shipping `Hues.mul` semantics into key for its own picture. Applying hues website-side would mean shipping `Hues.mul` semantics into
Node for no gain. Node for no gain.
- **Depth is expressible without being mandatory.** `body/400/a0/d1` and `body/400/a0/d1/f0..f9` - **Depth is expressible without being mandatory.** `body/400/a0` and `body/400/a0/f0..f9` are the
are the same addressing scheme at two depths, which is what lets §11 bulk-import thumbnails and same addressing scheme at two depths, which is what lets §11 bulk-import thumbnails and fetch full
fetch full animations on demand without a second protocol. animations on demand without a second protocol.
- **Nothing in the key is client-version-specific**, so a client patch changes an asset's *bytes*, - **Nothing in the key is client-version-specific**, so a client patch changes an asset's *bytes*,
not its name — which is what makes §7's delta work. not its name — which is what makes §7's delta work.
### 5.1 There is no direction segment, because only one direction is wanted
Bodies are stored in **five** directions and the client mirrors three of them to reach eight. Only
one is needed here — the one facing the viewer — so **direction is fixed by the extractor and is
not part of the key**. Leaving it in would advertise a choice nobody is going to make and would
five-fold every count in §11 for nothing.
**The front-facing index is 0.** This was determined by rendering all five for a human, a wolf and
a dragon rather than from a table, because the answer is not obvious and the small-thumbnail version
of the same test suggested the opposite:
| Index | View |
|---|---|
| **0** | **Head-on, facing the viewer** — face, chest and front legs visible |
| 1 | Front three-quarter |
| 2 | Full side profile |
| 3 | Rear three-quarter |
| 4 | Directly away — back of the head, and a quadruped's tail toward the camera |
One caveat the render made obvious, and it is the reason this is written down rather than assumed:
**index 0 is the least legible view for four-legged and long-bodied creatures.** A wolf seen head-on
is a dark blob; the same wolf at index 2 is unmistakably a wolf, and at index 1 is the view
UOFiddler's own thumbnail list picks. For a bestiary tile that matters. The extractor therefore
takes the index as a **configuration value defaulting to 0**, so changing the catalogue's mind later
is a setting and a re-import, not a protocol change.
--- ---
## 6. The manifest, and what the two buttons actually do ## 6. The manifest, and what the two buttons actually do
@@ -347,8 +373,9 @@ project. §1.1's measurements make the sizing question concrete:
| Item statics | **~49,150** | No — on demand, cached, keyed by `itemId` (+ hue) | | Item statics | **~49,150** | No — on demand, cached, keyed by `itemId` (+ hue) |
| Land tiles | **16,384** | No — on demand | | Land tiles | **16,384** | No — on demand |
| Creature/player bodies, first frame | **1,144** | **Yes** — this is the catalogue | | Creature/player bodies, first frame | **1,144** | **Yes** — this is the catalogue |
| One body, all actions × directions | **1,050 frames** (body 400) | No — on demand, per body | | One body, every action, one direction | **210 frames** (body 400); 96210 measured across six bodies | No — on demand, per body |
| All bodies, full animation | ~10⁶ frames | Never | | All bodies, every action, one direction | **~173,000 frames**, ~170 MB | No — but no longer unthinkable |
| The same at five directions | ~865,000 frames | Not built (§5.1) |
| Cliloc table | 123,490 entries → 67,496 rows | **Yes** — whole-table replace | | Cliloc table | 123,490 entries → 67,496 rows | **Yes** — whole-table replace |
| ServUO tree files (§10) | ~21 files, ~10.6 MB | **Yes** | | ServUO tree files (§10) | ~21 files, ~10.6 MB | **Yes** |
@@ -358,8 +385,14 @@ that makes a bestiary, a marketplace listing and a character sheet render.
Everything deeper is the *same protocol at a deeper key* (§5), fetched on demand and cached. That Everything deeper is the *same protocol at a deeper key* (§5), fetched on demand and cached. That
is what serves the future project without exporting 3.5 GB of someone else's copyrighted client is what serves the future project without exporting 3.5 GB of someone else's copyrighted client
into a database: a viewer that wants body 400's full walk cycle asks for into a database: a viewer that wants body 400's full walk cycle asks for `body/400/a2/f0..f9` and
`body/400/a2/d1/f0..f9` and gets it, once, and it is cached from then on. gets it, once, and it is cached from then on.
Because §5.1 dropped four of the five directions, a **complete** one-direction animation set for
every body is now ~173,000 frames rather than ~865,000 — around 170 MB. That is still not the
default and still not something to import before anything asks for it, but it has moved from
"never" to "a thing an operator could reasonably choose", and phase 5 should leave room for a
bulk-fill-everything switch rather than assuming on-demand is the only mode.
**Hued variants are on demand, always.** `static/3922/h33` is generated when something on the wire **Hued variants are on demand, always.** `static/3922/h33` is generated when something on the wire
actually carries hue 33. The cross product of 49,150 statics and ~3,000 hues is not a set anyone actually carries hue 33. The cross product of 49,150 statics and ~3,000 hues is not a set anyone
@@ -455,7 +488,7 @@ disagree, so a split bump means the next bundle silently fails to compose.
| 2 | Clilocs end to end; retire the converter and `UOFIDDLER.md` §Part 1 | all | | 2 | Clilocs end to end; retire the converter and `UOFIDDLER.md` §Part 1 | all |
| 3 | Body resolution (§8) + the 1,144-body catalogue; `shard_spawn_creatures.art` filled | servuo-plugins, module-uo | | 3 | Body resolution (§8) + the 1,144-body catalogue; `shard_spawn_creatures.art` filled | servuo-plugins, module-uo |
| 4 | Item statics and land on demand, hued keys, the cache | servuo-plugins, module-uo | | 4 | Item statics and land on demand, hued keys, the cache | servuo-plugins, module-uo |
| 5 | Deep animation keys (`body/<id>/a<n>/d<n>/f<n>`) for the future project | servuo-plugins, module-uo | | 5 | Deep animation keys (`body/<id>/a<n>/f<n>`) for the future project, plus the bulk-fill switch | servuo-plugins, module-uo |
| 6 | The atlas over the sidecar (§10); shared-filesystem requirement retired | module-uo | | 6 | The atlas over the sidecar (§10); shared-filesystem requirement retired | module-uo |
| 7 | Admin surface, Import/Update, approve/reject, activity log | module-uo | | 7 | Admin surface, Import/Update, approve/reject, activity log | module-uo |
| 8 | Docs pass across five repos; live walk on the real rig | docs | | 8 | Docs pass across five repos; live walk on the real rig | docs |
@@ -472,7 +505,8 @@ prove byte-identical output *before* building six phases on top of it.
libgdiplus dependency, the UOP gap and the vendor-drift risk all going away at once. libgdiplus dependency, the UOP gap and the vendor-drift risk all going away at once.
2. **§11: gump art deferred.** Confirm that paperdoll and equipment gump art is genuinely 2. **§11: gump art deferred.** Confirm that paperdoll and equipment gump art is genuinely
out of scope for 8, given it is the one kind whose existing decoder crashes. out of scope for 8, given it is the one kind whose existing decoder crashes.
3. **§11: the bulk working set is one frame per body (1,144).** Confirm that "player models and 3. **§5.1: direction is fixed at index 0** (head-on) and is not in the key — settled 2026-09-10.
everything" is served by on-demand depth rather than a bulk animation export. What is *not* settled is whether the catalogue should default to index 1 or 2 instead, since a
head-on wolf is a dark blob and a side-on wolf is a wolf. It is a setting either way.
4. **§13: the default audience** for asset serving — inheriting the using page's audience is 4. **§13: the default audience** for asset serving — inheriting the using page's audience is
proposed; the operator sets the policy either way. proposed; the operator sets the policy either way.