[PR #192] [MERGED] kb: Limbo: atlas mips confirmed, boy is atlas-only, header fields, published limbo-tools (follow-up to #146) #195

Closed
opened 2026-10-15 20:54:14 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/rehan-remade/universal-modder/pull/192
Author: @hukultan
Created: 10/10/2026
Status: ✅ Merged
Merged: 10/11/2026
Merged by: @rehan-remade

Base: main ← Head: kb/limbo-followup


📝 Commits (8)

  • 6329240 kb: Limbo - confirm atlas mips, resolve tail u16s, boy has no standalone sprites (follow-up #146)
  • 9780825 kb: Limbo - link published limbo-tools, record build ID/date, refresh index
  • 00166ac kb: Limbo - verified mip filter (floor L/A), extract/pack identity, edit loop
  • 25260a9 kb: Limbo - live-verified multi-asset human-edit loop (howtoplay_pc + atlas rects)
  • 5fa208c kb(limbo): characterize header unk6 (blur-only) and prove alpha is used by shaders
  • 669d9dd kb: Limbo follow-up: review fixes
  • d3444fe Merge remote-tracking branch 'origin/main' into land/pr-192
  • 023219c kb: regenerate the index

📊 Changes

3 files changed (+208 additions, -92 deletions)

View changed files

📝 knowledge/INDEX.md (+1 -1)
📝 knowledge/games/limbo/pngatlas-a8l8-format.md (+204 -89)
📝 knowledge/index.json (+3 -2)

📄 Description

Follow-up to the merged #146. This resolves every open item from the #146 review with verified data, retracts one draft claim, and adds the decompiled-atlas-loader RE from this repo's own runtime work.

Answers to the reviewer's follow-up items:

  1. Atlases ARE 6-level mip chains (confirmed by decoding level 1) - atlas_blur texel data = 4096^2+2048^2+...+128^2 exactly, and the bytes after the first 4096^2 region decode to a 2048x2048 image that is a half-size copy of level 0 (corr 0.999999 vs a 2x2 box downsample). atlas_norm's own header W/H = 4096x1024 (resolved; not a tall 4096x1365 sheet). Level 1 of atlas_norm (2048x512) corr 0.999998. The stale-mips gotcha is now grounded in confirmed structure.
  2. 16-byte prefix + trailing u16s resolved. Third u32 is the file-type/atlas-variant flag (1 = sprite, 9 = .png_a/.pngblur, 17 = .pngatlas) - the 'id-like byte and a byte that reads 1' from the first draft are this same flag, misread. The fourth u32 is NOT a path CRC (brute-forced seeds/xors over path, derived/pc/path, .d, lower/upper all mismatch): across 135 files it's 0, 0x12345678, 0x00FF00FF, or a 4-byte slice of an authoring-era absolute path (c:/derived/pc/...), i.e. stale debug cruft the loader never validates. First trailing header u16: high byte = mip count (title 0x0C=12 for W=2048, chapters/1 0x0B=11, 512-wide metal_heavy 0x0A=10, atlases 0x06=6); second = 0x0A01 sprites / 0x0A11 atlases (low nibble repeats the flag).
  3. Boy has NO standalone sprite files (confirmed by CRC32). All data/sprites/characters/boy/** CRC32 combos (11 manifest members x 6 ext incl. the exact head_cutoff.png.d path) match no entry in either pkg hash table, and no pkg blob's internal wrapper path starts with data/sprites/characters/boy/ (84 blobs merely mention 'boy' in cutscene scripts/ragdoll volumes). The boy exists only as 337 atlas manifest rects.
  4. Manifest cols 5-6 = offset/pivot (X/Y), NOT used W/H - proven via the 11 atlas members that also exist standalone (manifest cols 3-4 equal standalone usedW/usedH on all 11, leaving cols 5-6 as the anchor). Steam build ID recorded: 18220724.
  5. DONE - scripts published: unpack_limbo.py, limbo_tex.py, make_titlezero.py, repack_limbo.py, shot_diff.py are now at https://github.com/hukultan/limbo-tools (MIT, README + AI disclosure, no game files), and the note's links + Build steps point at it.

Additions beyond the review list:

  • Decompiled atlas loader chain (Ghidra over a memory-dumped unpacked exe): FUN_004e7dd0 -> FUN_004e7c60(atlases.txt) -> FUN_004e5550 parsing each manifest row as 6 ints + path (ints at rect+0x1c..0x30) -> FUN_004e40c0(name,'ATLAS') -> FUN_004e3160 setting flag 0x11/bit3, suffix picker FUN_005ea9b0 (_A/_BLUR_A/''), and the generic loader's 'XXXX' (0x58585858) invalid sentinel that explains why near-black boy edits showed nothing.
  • Retraction of a draft claim: the first-draft 'swap moved the darkness pass (58.97 vs 45.45)' was measured against a botched comparison - a second Steam launch captured mid title-fade. A clean single-instance re-run of the same swap reaches the menu fine, no crash, pixel diffs are animation noise only (mean 26.92 vs ~26.6 with cutscene skip). The manifest is still the live rect source (decompile-confirmed + the atlases.txt near-white live test).
  • Boot pkg entry-count correction: build 18220724's boot pkg holds 1,600 entries (1,091 named), not the 1,088/1,410 the filelist head claims.

Checks: um kb check --index PASS (157 notes), um publish check . PASS (2 pre-existing unrelated warnings), pytest 87 passed / 1 skipped.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/rehan-remade/universal-modder/pull/192 **Author:** [@hukultan](https://github.com/hukultan) **Created:** 10/10/2026 **Status:** ✅ Merged **Merged:** 10/11/2026 **Merged by:** [@rehan-remade](https://github.com/rehan-remade) **Base:** `main` ← **Head:** `kb/limbo-followup` --- ### 📝 Commits (8) - [`6329240`](https://github.com/rehan-remade/universal-modder/commit/6329240eab723719291b4cb6154598900b6d494c) kb: Limbo - confirm atlas mips, resolve tail u16s, boy has no standalone sprites (follow-up #146) - [`9780825`](https://github.com/rehan-remade/universal-modder/commit/978082521a4ab549f1aca42df0b31f1037deb6dd) kb: Limbo - link published limbo-tools, record build ID/date, refresh index - [`00166ac`](https://github.com/rehan-remade/universal-modder/commit/00166acff012d007b93c31af510011e3d714533b) kb: Limbo - verified mip filter (floor L/A), extract/pack identity, edit loop - [`25260a9`](https://github.com/rehan-remade/universal-modder/commit/25260a961a5d6f169248961232b8ddea3450f4a2) kb: Limbo - live-verified multi-asset human-edit loop (howtoplay_pc + atlas rects) - [`5fa208c`](https://github.com/rehan-remade/universal-modder/commit/5fa208cda6f1c657a71f0d39594eafd1e7752c64) kb(limbo): characterize header unk6 (blur-only) and prove alpha is used by shaders - [`669d9dd`](https://github.com/rehan-remade/universal-modder/commit/669d9dd712f9b85f6101c5add80b0676fafb34ba) kb: Limbo follow-up: review fixes - [`d3444fe`](https://github.com/rehan-remade/universal-modder/commit/d3444fec68fb27c7249604935239409170e52210) Merge remote-tracking branch 'origin/main' into land/pr-192 - [`023219c`](https://github.com/rehan-remade/universal-modder/commit/023219c9b8ac80479bc973c439a542b817280f5f) kb: regenerate the index ### 📊 Changes **3 files changed** (+208 additions, -92 deletions) <details> <summary>View changed files</summary> 📝 `knowledge/INDEX.md` (+1 -1) 📝 `knowledge/games/limbo/pngatlas-a8l8-format.md` (+204 -89) 📝 `knowledge/index.json` (+3 -2) </details> ### 📄 Description Follow-up to the merged #146. This resolves every open item from the #146 review with verified data, retracts one draft claim, and adds the decompiled-atlas-loader RE from this repo's own runtime work. **Answers to the reviewer's follow-up items:** 1. **Atlases ARE 6-level mip chains (confirmed by decoding level 1)** - atlas_blur texel data = 4096^2+2048^2+...+128^2 exactly, and the bytes after the first 4096^2 region decode to a 2048x2048 image that is a half-size copy of level 0 (corr 0.999999 vs a 2x2 box downsample). atlas_norm's **own header W/H = 4096x1024** (resolved; not a tall 4096x1365 sheet). Level 1 of atlas_norm (2048x512) corr 0.999998. The stale-mips gotcha is now grounded in confirmed structure. 2. **16-byte prefix + trailing u16s resolved.** Third u32 is the file-type/atlas-variant flag (1 = sprite, 9 = .png_a/.pngblur, 17 = .pngatlas) - the 'id-like byte and a byte that reads 1' from the first draft are this same flag, misread. The fourth u32 is NOT a path CRC (brute-forced seeds/xors over path, derived/pc/path, .d, lower/upper all mismatch): across 135 files it's 0, 0x12345678, 0x00FF00FF, or a 4-byte slice of an authoring-era absolute path (c:/derived/pc/...), i.e. stale debug cruft the loader never validates. First trailing header u16: high byte = mip count (title 0x0C=12 for W=2048, chapters/1 0x0B=11, 512-wide metal_heavy 0x0A=10, atlases 0x06=6); second = 0x0A01 sprites / 0x0A11 atlases (low nibble repeats the flag). 3. **Boy has NO standalone sprite files (confirmed by CRC32).** All data/sprites/characters/boy/** CRC32 combos (11 manifest members x 6 ext incl. the exact head_cutoff.png.d path) match no entry in either pkg hash table, and no pkg blob's internal wrapper path starts with data/sprites/characters/boy/ (84 blobs merely mention 'boy' in cutscene scripts/ragdoll volumes). The boy exists only as 337 atlas manifest rects. 4. **Manifest cols 5-6 = offset/pivot (X/Y), NOT used W/H** - proven via the 11 atlas members that also exist standalone (manifest cols 3-4 equal standalone usedW/usedH on all 11, leaving cols 5-6 as the anchor). Steam build ID recorded: 18220724. 5. **DONE - scripts published:** unpack_limbo.py, limbo_tex.py, make_titlezero.py, repack_limbo.py, shot_diff.py are now at https://github.com/hukultan/limbo-tools (MIT, README + AI disclosure, no game files), and the note's links + Build steps point at it. **Additions beyond the review list:** - Decompiled atlas loader chain (Ghidra over a memory-dumped unpacked exe): FUN_004e7dd0 -> FUN_004e7c60(atlases.txt) -> FUN_004e5550 parsing each manifest row as 6 ints + path (ints at rect+0x1c..0x30) -> FUN_004e40c0(name,'ATLAS') -> FUN_004e3160 setting flag 0x11/bit3, suffix picker FUN_005ea9b0 (_A/_BLUR_A/''), and the generic loader's 'XXXX' (0x58585858) invalid sentinel that explains why near-black boy edits showed nothing. - **Retraction of a draft claim:** the first-draft 'swap moved the darkness pass (58.97 vs 45.45)' was measured against a botched comparison - a second Steam launch captured mid title-fade. A clean single-instance re-run of the same swap reaches the menu fine, no crash, pixel diffs are animation noise only (mean 26.92 vs ~26.6 with cutscene skip). The manifest is still the live rect source (decompile-confirmed + the atlases.txt near-white live test). - Boot pkg entry-count correction: build 18220724's boot pkg holds 1,600 entries (1,091 named), not the 1,088/1,410 the filelist head claims. Checks: um kb check --index PASS (157 notes), um publish check . PASS (2 pre-existing unrelated warnings), pytest 87 passed / 1 skipped. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-15 20:54:14 +00:00
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
rehan-remade/universal-modder#195
No description provided.