re(ui): scale 0 means collapsed, not "unset" -- stop drawing it full size
blit() and fill_quad() both opened with
let sx_pct = if kf.scale_x == 0 { 100 } else { kf.scale_x };
so an element whose pose is collapsed to nothing rendered at FULL SIZE.
I first described this as "a 1-pixel sliver", reading the .max(1) in the
size arithmetic two lines below -- the guard above it meant .max(1) never
saw a zero. Read the whole function, not the lines you went looking for.
Control run before the change: if 0 meant "unset", something on the disc
would use it throughout. Nothing does.
elements with a keyframe group 15 493
at least one keyframe at scale 0 2 166
EVERY keyframe at scale 0 0
zero is a transient the element grows out of 1 762
ptlogo_eff3.t32 runs 0% -> 200%. An "unset" marker no element ever uses
throughout is not a marker.
Both functions now return without drawing when either scale is 0.
Reach: 24 of 24 renders byte-identical across GP_TITLE (all 16 builds),
GP_PAUSE_MENU and GP_OPTIONS -- additive on every screen the port needs.
195 elements have a guessed rest pose at scale 0 and 126 of those have a
non-zero alpha, so the old code painted them; all 126 are in
GP_READY_ROOM.pak, which S1 already declared a no-go. They are
tactical-map sprites at sx=0/sy=100, mid-horizontal-wipe, that the
coercion drew full-width.
So: a real correctness fix with no visible effect on the menu port.
Suite green, 122 passed / 0 failed across 3 suites at commit time.
This commit is contained in:
@@ -291,6 +291,15 @@ authored version can be deleted.
|
||||
the defensible one there — see below. Still worth flagging plateau-less
|
||||
elements in an export rather than silently inheriting our guess; it is one pass
|
||||
over the keyframes.
|
||||
✅ **One concrete part of it is fixed (2026-08-28): `scale = 0` no longer
|
||||
renders at full size.** `blit`/`fill_quad` coerced `scale == 0` to 100 %, so an
|
||||
element collapsed to nothing was drawn full-size. The disc settles the reading:
|
||||
2 166 elements have a zero-scale keyframe, **not one is zero throughout**, and
|
||||
1 762 grow back out of zero — so 0 means collapsed, not "unset". **Renders are
|
||||
24/24 byte-identical** on `GP_TITLE` (all 16 builds), `GP_PAUSE_MENU` and
|
||||
`GP_OPTIONS`, so nothing you rely on moves; the 126 elements the old
|
||||
code actually painted are **all in `GP_READY_ROOM.pak`**, already a no-go.
|
||||
[`structures/ui-rat-layout.md`](../re/structures/ui-rat-layout.md)
|
||||
🔴 **"rest = last keyframe" is refuted** as the fix. The splash has three
|
||||
sibling glows with identical structure and times, differing in one byte
|
||||
(`a=212` vs `a=255` at `t=45`); that rule would make `anima_eff` alone
|
||||
|
||||
@@ -408,3 +408,14 @@ agent's loop prompt, i.e. nowhere durable. See [`README.md`](README.md) for the
|
||||
a heredoc two lines later wrote nowhere — while the `echo` after it still
|
||||
printed "written". A success message after a failed redirect is not a success.
|
||||
Use `(setsid nohup … &)` and keep the file-writing in its own call.
|
||||
* **Read the whole function before describing what it does.** I wrote "a
|
||||
zero-scale pose paints a 1-pixel sliver" into a tool's docstring, from the
|
||||
`.max(1)` in the size arithmetic. Two lines above it, a guard coerced
|
||||
`scale == 0` to **100 %**, so the `.max(1)` never saw a zero and the element
|
||||
rendered at *full size* — a much larger bug than the one I described. I had
|
||||
read the lines I went looking for and stopped.
|
||||
* **Never diff a file a background job might still be writing.** A comparison
|
||||
loop over an output directory reported `GP_TITLE` build 6 as changed; the pixel
|
||||
diff was then all zeros, because `cmp` had read a half-written PNG. Compare
|
||||
only after the job signals done, or skip the newest file. A "difference" that
|
||||
vanishes on re-examination is usually a race, not a flake.
|
||||
|
||||
@@ -408,3 +408,8 @@ neighbourhood, not just the line.
|
||||
makes `palogo_anima_eff` alone invisible while `gamearts_eff` and `seta_eff`
|
||||
stay lit. Capture box-mean ratios (0.717 / 0.723 / **0.772**) go the other way
|
||||
too. [`structures/ui-resting-pose.md`](structures/ui-resting-pose.md)
|
||||
* "a keyframe `scale` of 0 means *unset*, so render at 100 %" → **refuted by a
|
||||
disc-wide control.** 2 166 elements have a zero-scale keyframe and **not one is
|
||||
zero on every keyframe**, while 1 762 grow back out of zero (`ptlogo_eff3.t32`
|
||||
runs 0 % → 200 %). Zero means collapsed; the renderer now draws nothing.
|
||||
[`structures/ui-rat-layout.md`](structures/ui-rat-layout.md)
|
||||
|
||||
24
docs/re/data/zero-scale-census.txt
Normal file
24
docs/re/data/zero-scale-census.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
# tools/re-capture/zero_scale_census.py -- 2026-08-28
|
||||
|
||||
elements with a keyframe group: 15493
|
||||
at least one keyframe at scale 0: 2166
|
||||
EVERY keyframe at scale 0 (would vanish): 0
|
||||
zero is a transient the element grows out of: 1762
|
||||
rest poses with scale 0%%: 195
|
||||
... of which alpha > 0, so blit paints a 1-pixel sliver: 126
|
||||
... alpha == 0, harmless: 69
|
||||
|
||||
by archive:
|
||||
126 GP_READY_ROOM.pak
|
||||
|
||||
examples (pak, entry, element idx, name, sx, sy, alpha):
|
||||
('GP_READY_ROOM.pak', 0, 2, 'pbacropolis.t32', 0, 100, 255)
|
||||
('GP_READY_ROOM.pak', 0, 6, 'pbFriendly.t32', 0, 100, 255)
|
||||
('GP_READY_ROOM.pak', 0, 10, 'pbFriendly.t32', 0, 100, 255)
|
||||
('GP_READY_ROOM.pak', 0, 14, 'pbFriendly.t32', 0, 100, 255)
|
||||
('GP_READY_ROOM.pak', 7, 2, 'pbacropolis.t32', 0, 100, 255)
|
||||
('GP_READY_ROOM.pak', 7, 6, 'pbFriendly.t32', 0, 100, 255)
|
||||
('GP_READY_ROOM.pak', 7, 10, 'pbFriendly.t32', 0, 100, 255)
|
||||
('GP_READY_ROOM.pak', 7, 14, 'pbFriendly.t32', 0, 100, 255)
|
||||
('GP_READY_ROOM.pak', 74, 2, 'pbr_enemy.t32', 0, 100, 255)
|
||||
('GP_READY_ROOM.pak', 76, 2, 'pbr_enemy.t32', 0, 100, 255)
|
||||
@@ -711,3 +711,48 @@ full cycle length has to come from measurement.
|
||||
|
||||
❔ The word at `+0x004` is **not** the keyframe count: `0x003c0000` (60) with 8
|
||||
keyframes here, `0x001e0000` (30) with 3 in `ptloop01.rat`/`ptloop02.rat`.
|
||||
|
||||
## ✅ `scale = 0` means COLLAPSED, not "unset" (2026-08-28)
|
||||
|
||||
`ui_layout::blit` and `fill_quad` both used to open with
|
||||
|
||||
```rust
|
||||
let sx_pct = if kf.scale_x == 0 { 100 } else { kf.scale_x };
|
||||
```
|
||||
|
||||
so an element whose pose is *collapsed to nothing* was drawn at **full size**.
|
||||
(The `.max(1)` two lines below never saw a zero — see [METHOD.md](../METHOD.md).)
|
||||
|
||||
### The control, run before the change
|
||||
|
||||
If `0` meant "unset", some element would use it throughout. Over the disc
|
||||
([`data/zero-scale-census.txt`](../data/zero-scale-census.txt)):
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| elements with a keyframe group | 15 493 |
|
||||
| at least one keyframe at scale 0 | 2 166 |
|
||||
| **every** keyframe at scale 0 | **0** |
|
||||
| zero is a transient the element grows back out of | **1 762** |
|
||||
|
||||
Not one element on the disc is zero-scale throughout, and 1 762 grow out of zero
|
||||
— `ptlogo_eff3.t32` runs `0 % → 200 %`. **An "unset" marker that nothing ever
|
||||
uses throughout is not a marker.** Zero means zero.
|
||||
|
||||
### The fix, and its reach
|
||||
|
||||
Both functions now return without drawing when either scale is 0.
|
||||
|
||||
* **Renders: 24 of 24 byte-identical** across `GP_TITLE` (all 16 builds),
|
||||
`GP_PAUSE_MENU` and `GP_OPTIONS`. The change is additive
|
||||
on every screen the port needs.
|
||||
* 195 elements have a guessed rest pose at scale 0; **126 of those had a non-zero
|
||||
alpha**, so the old code painted them at full size.
|
||||
* ⚠️ **All 126 are in `GP_READY_ROOM.pak`** — the archive
|
||||
[S1](../ready-room-probe.md) already declared a no-go. They are tactical-map
|
||||
sprites (`pbacropolis`, `pbFriendly`, `pbr_enemy`) at `sx=0, sy=100`, i.e.
|
||||
mid-horizontal-wipe, which the old coercion drew full-width.
|
||||
|
||||
🟡 So this is a **real correctness fix with no visible effect on the menu port**.
|
||||
It matters for anything that later reads `GP_READY_ROOM`, and it removes a case
|
||||
where the renderer contradicted the format.
|
||||
|
||||
Reference in New Issue
Block a user