# Debug view: collision & invisible objects in game (`tools/debugviz.py`) As of: 2026-11-06. Shows, in **all 34 level WADs**, the collision geometry (including invisible walls/floors, death planes) and invisible logic objects (cameras, triggers, exits, checkpoints, force/box zones, environment zones …) directly in the game – as a coloured wireframe, invisible surfaces additionally filled semi-transparently. Game mechanics stay unchanged. ## Usage ``` lama-mod debug an # enable debug WADs (rebuilds the overlay, thereby also activating other mods) lama-mod debug aus # back to the original levels (the testlevel mod stays as it was) lama-mod debug # status ``` Takes effect the next time a level is loaded (best to restart the game). Do not toggle while a level is loading. Mod folder: `~/.wine-lama/mods/debug/wads/*.wad` (same names as on the CD, e.g. `t1l1m001.wad`); the file `~/.wine-lama/mods/debug/.aus` = disabled. Order in the overlay: alphabetical, later ones win → `testlevel` (T1L9*) always stays, debug WADs only replace the original levels. `lama-mod an|aus|status` work as before (`an` skips mod folders containing `.aus`). Backup of the old script: `deb-build/lama-mod.bak-vor-debug`. Rebuild (e.g. after changing colours): ``` python3 tools/debugviz.py --all ~/.wine-lama/mods/debug/wads --report /tmp/dv.json python3 tools/debugviz.py IN.wad OUT.wad [--no-fill] [--no-markers] [--no-coll] [--opaque] [--width 0.007] [--offset 0.012] ``` Run time ≈ 10–40 s per level. ## Colour legend All colours are RGB (0–255). **Lines** = wireframe (opaque), **fill** = semi-transparent (alpha 96/255, engine blend mode 1). ### Collision surfaces (frame around every collision polygon of the world tiles) Edge colour by orientation, as long as the material is 0 (normal): | Colour | RGB | Meaning | |---|---|---| | **Green** (lines) | 40,255,40 | walkable floor (normal pointing steeply up, ny ≥ 0.7) | | **Yellow-green** (lines) | 200,255,0 | slope (0.2 ≤ ny < 0.7) | | **Blue** (lines) | 0,150,255 | wall (−0.2 < ny < 0.2) | | **Orange** (lines) | 255,130,0 | ceiling / overhang (ny ≤ −0.2) | | **Red, filled semi-transparently** | 255,0,0 | **invisible collision**: no render surface within ±0.5 units along the normal (= invisible wall/floor/ceiling). The edge colour still shows orientation or material. | Collision with a special material (byte 1 of the collision polygon ≠ 0): edges in the material colour, for invisible polygons the fill is also in the material colour (instead of red): | Material | Colour | RGB | Meaning | |---|---|---|---| | 30 (0x1e) | **Magenta**, lines only (no fill) | 255,0,255 | **no floor / fall and death plane**: the player falls through (FUN_004036d0 sets floor = none). Usually model 0 at y ≈ −2.75 in every grid cell below the islands → magenta grid = fall/death zone. | | 16 | **Violet**, always filled | 190,60,255 | exit floor: LevelDoor only triggers when the player stands on material 16 in the door cell | | 17 (0x11) | **Yellow** | 255,255,0 | selective collision: only affects objects with runtime flag 0x8000000 (strat+0xe8) | | 18 (0x12) | **Light orange/peach** | 255,200,120 | selective collision: does NOT affect objects with flag 0x8000000 | | 1 | Turquoise | 0,200,200 | special material, meaning unknown (evaluated by strat scripts) | | 2 | White | 255,255,255 | ditto | | 3 | Pink (rose) | 255,120,170 | ditto (common in world 5, mountain) | | 5 | Mint | 120,255,200 | ditto (river, roller coaster) | | 6 | Lavender | 160,120,255 | ditto | | 7 | Light orange | 255,170,80 | ditto | | 8 | Dark green | 0,130,60 | ditto | | 9 | Light blue | 150,200,255 | ditto | | 10 | Olive | 150,150,0 | ditto | | 11 | Brown | 150,90,40 | ditto | | 13 | Salmon | 255,130,110 | ditto | | 15 | Light yellow | 255,255,150 | ditto | | 20 | Petrol | 0,120,140 | ditto | | 26 | Dark violet | 110,40,160 | ditto | | 27 | Silver | 190,190,190 | ditto (chase t1l2m003) | | 28 | Hot pink | 255,0,140 | ditto | | 33 | Dark red | 150,0,0 | ditto | | 255 | Almost black | 20,20,20 | ditto | | other | Light grey | 230,230,230 | (does not occur in the originals) | ### Object markers (invisible strats, MAP strat entries) Marker cube (10 cm) on a thin pole 0.35 above the object origin; short horizontal line = view direction (cameras, checkpoints). | Colour | RGB | Category | Types | |---|---|---|---| | **White**, arrow flat on the ground | 255,255,255 | player start (direction) | Llama, KuscoAndPachaTogetherOnATree (river), RollerCoaster, LlamaChase | | **Violet** + wire cube 1×1×1 around the grid cell | 190,60,255 | exit (trigger cell) | LevelDoor, VillageEndDoor, EndGameDoor, TeleportDoor | | **Green-turquoise** | 0,255,140 | checkpoint | CheckPointPost, CheckPointBox | | **Cyan** | 0,255,255 | camera | Camera* (CameraSide, CameraLift, CameraForceInsideBox …), CutSceneCamera*, RiverWaterfallCamera | | **Yellow** | 255,255,0 | trigger | CutSceneTrigger*, *Trigger*, Say* (voice lines), ChangeToBunny/Turtle, RiverStartSign | | **Orange** | 255,90,0 | force/special zones | Force*, FallOffNoHurt, ObjectDontDropInBox, RiverCurrentBox, RiverRebound, WaterReboundPoints*, SuckingWPs, ObjectSuckPoints, RiverTrackChange, TrackSwitch, RiverWhirlpool, BackgroundRotationChanger | | **Gold** | 255,200,0 | secret zone | Secret | | **Grey** | 170,170,170 | other invisible control objects | CheatTeleport, Wompy*, Spawner, Helper, coin lines/circles, Rain, DrippingWater, WaterfallMist, MusicBox, FlockOfBirds, Bats, Scorpions*, AppearingPlatforms* … | | **Dark grey**, small dot (6 cm) | 90,90,90 | all remaining objects (origin) | coins, enemies, doors … – so that really nothing is missing | | **Pink** wire cube per grid cell | 255,100,180 | environment/music/fog zone | MAP block 4 (90-byte entries, cell x/y/z) | **Zone boxes:** if a marker object has exactly 2 waypoints and the object lies in the rectangle between them, it is a box area (Secret, CameraSide/Lift, ObjectDontDropInBox, FallOffNoHurt, RiverCurrentBox …): wire cuboid in the category colour from min(y) to max(y)+1.2 (the height is estimated – the code probably only checks x/z), for areas ≤ 64 units² with a semi-transparent floor (alpha 70). **Waypoint chains** of other marker objects: small cubes (5 cm) in a darkened category colour (60 %), for force zones with connecting lines (e.g. WaterReboundPoints paths, CutSceneTrigger camera moves only as points). ## How it is built (decisions) * **Collision overlay appended to the TRAK models** (not as separate tiles): per collision polygon a frame of 2·n vertices (outer corners + corners offset inwards by the line width, computed from the edge planes), 2·n triangles; the fill reuses the inner corners. Everything offset by 0.012 along the surface normal (no z-fighting). This way tile transform, zones/visibility and tile swaps (alt models, WFPC 0x10000) are automatically correct. Collision is converted back from game space (geomlib.coll_decode/ coll_polygon, z mirrored). * Face flags of the overlay triangles: 0x800 | 0x400 (double-sided) | 0x4000 (ignore vertex colours) | 0x8 at every texture change and at the latest every 250 faces (render batch). * **Colours** = appended flat-colour textures (TEXT table, page −1): opaque flags 0x105, semi-transparent **0x1105** (bits 12–14 = 1 → table 0x573eb8: blend mode 1 = SRCALPHA/INVSRCALPHA, alpha from the 4th byte (v1) of the entry; checked in game). Semi-transparent triangles go through the sort buffer (FUN_0041ed90, 512 KB/frame ≈ 5000 triangles; when it is full they are simply dropped – no crash). That is why fills exist only for invisible collision, material 16 and small zone floors. * **Vertex colour block** in MAP: extended per tile (and per colour set/frame, also for alt models) by nV(overlay) entries 0x00808080 (byte 3 = 0, does not change the frame count). * **Invisibility detection**: render triangles of all tiles in world coordinates, bucketed by cell; for the centre + 4 points (70 % towards the corners) of every collision polygon a ray along the normal (±0.5) is tested against triangles with similar orientation (|cos| > 0.4); < 60 % hits = invisible. Majority vote per model over up to 6 instances. Strat models (STPC: doors, platforms, characters) do NOT count as render surfaces – collision behind moving objects may therefore appear red. (The first version with 0.06/0.15 distance marked entire house walls and cliff walls red, because the collision hull lies 0.2–0.4 in front of the visible wall – too much noise.) * **Markers** as new tiles without collision, one model per grid cell (lines split into pieces ≤ 1 and placed in the cell of their midpoint) → automatically get the zone of the cell. New tiles are appended at the end (indices of the original tiles stay). * **Game mechanics unchanged**: no collision polygons added/changed, strats, waypoints, parameter pool, zones and the rest of MAP byte-identical (checked after writing: strats/nodes/rest/original tiles identical). * Size: WADs grow by 0.1–4 MB (max. 8.9 MB, t1l6m003). Level memory (16 MB arena, FUN_0041ef00) holds TRAK+STPC+MAP – enough for all (load test). ## Limits / known issues * Collision of the **object models** (STPC: moving platforms, doors, crates …) is not shown – they move; only their origin as a dark grey dot. * Zone heights of the box areas are estimated; whether the engine checks y is open. * Meaning of most special materials unknown (only colour + count, see table below); material 30 = no floor, 16 = exit, 17/18 = selective are certain from the code. * Environment zones (MAP block 4): cell certain, meaning (fog/music/camera) only moderately certain; the default entry (position 1,1,1) is not drawn. * If the camera is close to a marker/line, the engine's near-plane clip sometimes cuts the triangles into large shreds (only briefly visible). * Performance: no noticeable drop under Wine/llvmpipe (Xvfb); uncritical on a real GPU (≤ 2000 extra vertices per tile model, on average ~1–2× as many triangles as the original). * Test level T1L9 (test world) has no debug version (the testlevel mod takes precedence). ## Allowance areas (LlamaMod option `debug-wireframe.allowance`, 2026-11-08) Choice `off` (default) / `tips` ("Floating spots") / `all` ("All edges"). Shows the floor test's edge allowance: the engine accepts a floor polygon up to `tol = −0x40 − ((0x1000 − ny·32) >> 6)` (≈0.016–0.023) outside each edge plane; at sharp corners this becomes a sliver up to tol / sin(θ/2) long (geometry.md "Floor test: inclusion rule …"). Colour **pink 255,60,200**. * Code: `mods/debug/FloorTest` = bit-exact port of FUN_004036d0's floor branch (same as `tools/floortest.py`; the sine table is `rint(sin(2πi/4096)·4096)`, identical to DAT_00574318), `mods/debug/AllowanceAreas`. All geometry uses the engine's plane scale (n·p = d/32 with |n| = 127), not `Collision.decode`'s d/4096, so the bands sit ~0.8 % further from the model origin than the green wireframe. * **tips**: for every placed tile and every up-facing collision polygon (not material 17 = skipped for the llama, not 30 = no floor) and every corner whose tolerance corner lies ≥ `MIN_REACH` (0.05) beyond the true corner, the area beyond the corner (tolerance region ∩ half-plane past the corner) is sampled in up to 40 rows × 7 points. A sample counts when the exact engine test, with the feet on that polygon's plane, picks this polygon, the point is outside the polygon without tolerance, and no other passing floor of the cell is less than `MIN_GAP` (0.05) below (material-30 floors count as none). Samples outside the tile's cell are dropped (the engine only tests the cell's tiles). Kept when the winning samples reach ≥ 0.05 outside the polygon: translucent strip (alpha 150) through the winning part of each row + an opaque centre line (4 mm), at the plane height + 0.012, in the tile's marker cell model (no collision). Strat object collision (crates as strats, platforms) is not considered. * **all**: per TRAK model, every up-facing floor polygon (same material filter) gets an opaque ring from its true corners to its tolerance corners (2n vertices, 2n triangles), appended to the model overlay like the wireframe (tile transform, alt models free). Tolerance corners further than 1.5 out are clamped. * Budget: if TEXT+TRAK+MAP+STPC+LGPC would exceed 12 MB (16 MB level arena) the level is rebuilt without allowance geometry and the apply log says "allowance areas left out: level too large". Not reached in any original level; a model whose overlay would pass 7900 vertices keeps its wireframe without bands. * Numbers (all 33 levels): tips 0–1454 slivers per level (river t1l3m00x most, t1l4m002 394), WAD +0–2.0 MB, ≤ 2 s per level; all: +0.02–2.9 MB, arena max 11.1 MB (t1l3m003). t1l4m002 crate (tile 443): poly 15 corner 2 (reach 0.18, contains Kuzco's spot 57.204/43.733), poly 11 corner 2 (0.175), polys 10/14 (0.11/0.13) on the other end, 12/13 barely (0.05). * Tests: `AllowanceAreasTest` (exact port vs. 44 floortest.py points, sine table vs. groove.exe, slivers of t1l4m002, no slivers on the flat start ground, band counts, process in each mode). ## Statistics per level (build of 2026-11-06) Marker categories are the internal keys of `debugviz.py`: ausgang = exit, geheimnis = secret, kamera = camera, kraft = force zone, objekt = other object, sonst = other control object, umgebung = environment zone. | Level | World | WAD old→new (KB) | Coll. polygons | of which invisible | Special materials (polygon count) | Markers | |---|---|---|---|---|---|---| | t1l1m001 | Village | 6158→8235 | 3474 | 215 | 2:138, 6:4, 8:35, 9:13, 16:8, 17:5, 18:84, 28:19, 30:1 | ausgang 1, checkpoint 6, geheimnis 2, kamera 6, kraft 6, objekt 95, sonst 4, start 1, trigger 1, umgebung 12 | | t1l1m002 | Village | 5471→7573 | 3909 | 130 | 6:4, 8:14, 16:9, 18:65, 28:23, 30:1 | ausgang 1, checkpoint 5, geheimnis 1, kamera 8, kraft 5, objekt 89, sonst 9, start 1, trigger 1, umgebung 15 | | t1l1m003 | Village | 5891→8348 | 3893 | 79 | 2:15, 6:4, 8:8, 16:5, 17:3, 18:458, 20:6, 28:23, 30:1 | ausgang 1, kamera 3, kraft 6, objekt 45, sonst 3, start 1, trigger 2, umgebung 4 | | t1l1m004 | Village | 5866→7006 | 2169 | 60 | 2:15, 8:8, 16:16, 17:3, 18:90, 30:1 | ausgang 2, geheimnis 1, kamera 2, kraft 1, objekt 31, sonst 2, start 1, trigger 1, umgebung 5 | | t1l2m001 | Jungle night | 5094→7491 | 3933 | 460 | 1:26, 2:111, 6:156, 9:34, 16:22, 17:24, 18:284, 20:80, 28:28, 30:138, 33:1 | ausgang 1, checkpoint 2, geheimnis 1, kamera 3, kraft 6, objekt 39, sonst 8, start 1, trigger 1, umgebung 8 | | t1l2m002 | Jungle night | 5329→7561 | 3715 | 389 | 1:216, 2:57, 6:154, 9:24, 16:34, 17:23, 18:319, 28:28, 30:50 | ausgang 1, checkpoint 4, geheimnis 1, kamera 3, kraft 7, objekt 105, sonst 2, start 1, trigger 1, umgebung 18 | | t1l2m003 | Jungle night (chase) | 2837→5142 | 4844 | 630 | 5:3, 9:6, 10:6, 11:37, 16:26, 27:206, 30:46 | kamera 2, kraft 1, objekt 33, sonst 4, start 1, trigger 1 | | t1l3m001 | River | 4099→8220 | 8371 | 1000 | 5:26, 16:8, 18:23 | ausgang 2, geheimnis 1, kamera 13, kraft 4, objekt 140, sonst 13, start 1, trigger 5 | | t1l3m002 | River | 3799→8249 | 8824 | 1097 | 5:40, 16:5, 18:23, 30:1 | ausgang 2, geheimnis 1, kamera 19, kraft 44, objekt 115, sonst 39, start 1, trigger 6 | | t1l3m003 | River | 4497→8537 | 8387 | 868 | 5:56, 16:5 | ausgang 4, geheimnis 1, kamera 15, kraft 7, objekt 52, sonst 15, start 1, trigger 3 | | t1l3m004 | River | 2674→3754 | 2201 | 228 | 5:18, 16:5 | ausgang 2, kamera 5, kraft 4, objekt 31, sonst 7, start 1, trigger 2 | | t1l4m001 | Jungle day | 5469→7380 | 3214 | 230 | 1:148, 6:105, 10:33, 16:18, 17:33, 18:158, 20:25, 28:24, 30:10 | ausgang 1, checkpoint 9, geheimnis 1, kamera 5, kraft 12, objekt 120, sonst 3, start 1, trigger 1, umgebung 10 | | t1l4m002 | Jungle day | 5807→8045 | 3820 | 157 | 1:186, 6:123, 10:80, 16:33, 17:55, 18:309, 20:6, 28:98, 30:22 | ausgang 1, checkpoint 7, geheimnis 2, kamera 1, kraft 14, objekt 135, sonst 3, start 1, trigger 1, umgebung 14 | | t1l4m003 | Jungle day | 6320→8886 | 4805 | 135 | 1:174, 2:52, 6:10, 10:33, 16:36, 17:110, 18:890, 20:186, 28:27, 30:33, 255:8 | ausgang 1, checkpoint 3, geheimnis 2, kamera 6, kraft 4, objekt 99, sonst 3, start 1, trigger 1, umgebung 16 | | t1l5m001 | Mountain | 6090→8613 | 4419 | 188 | 3:356, 8:96, 16:24, 17:35, 18:539, 20:66, 28:6, 30:87 | ausgang 1, checkpoint 3, geheimnis 2, kamera 5, kraft 2, objekt 83, sonst 7, start 1, trigger 1, umgebung 15 | | t1l5m002 | Mountain | 5949→8558 | 5242 | 220 | 2:20, 3:396, 8:23, 9:15, 16:19, 17:33, 18:342, 20:57, 30:120 | ausgang 1, checkpoint 3, geheimnis 4, kamera 10, kraft 3, objekt 67, sonst 6, start 1, trigger 1, umgebung 7 | | t1l5m003 | Mountain | 4989→6796 | 3399 | 98 | 3:232, 8:223, 16:17, 18:20, 20:6, 30:78 | ausgang 1, checkpoint 5, geheimnis 1, kamera 4, kraft 1, objekt 71, sonst 6, start 1, trigger 1, umgebung 2 | | t1l6m001 | City | 6210→8227 | 2857 | 169 | 6:29, 16:18, 17:140, 18:110, 30:38 | ausgang 1, checkpoint 4, geheimnis 1, kamera 5, kraft 3, objekt 83, sonst 3, start 1, trigger 5, umgebung 20 | | t1l6m002 | City | 5155→7060 | 1771 | 106 | 6:56, 16:9, 17:20, 18:39, 30:17 | ausgang 1, checkpoint 10, geheimnis 1, kamera 7, kraft 9, objekt 127, sonst 16, start 1, trigger 5, umgebung 46 | | t1l6m003 | City | 6693→8924 | 2462 | 148 | 1:39, 16:13, 17:80, 18:154, 28:3, 30:10 | ausgang 1, checkpoint 11, geheimnis 6, kamera 11, kraft 6, objekt 107, sonst 15, start 1, trigger 3, umgebung 59 | | t1l7m001 | Catacombs (roller coaster) | 3054→6705 | 4043 | 20 | 5:54, 11:18, 13:18, 16:9, 30:18 | kamera 1, objekt 2, sonst 36, start 1, trigger 1, umgebung 14 | | t1l7m002 | Catacombs | 5280→7722 | 1795 | 111 | 2:1, 11:3, 16:44, 30:93 | ausgang 3, checkpoint 12, geheimnis 5, kamera 6, kraft 4, objekt 186, sonst 12, start 1, trigger 1, umgebung 23 | | t1l7m003 | Catacombs (roller coaster) | 2496→5140 | 1999 | 11 | 5:54, 11:90, 13:36, 15:18, 16:9, 30:9 | kamera 1, objekt 11, sonst 41, start 1, trigger 1 | | t1l7m004 | Catacombs | 5299→6978 | 1892 | 61 | 2:7, 16:32, 30:70 | ausgang 1, checkpoint 3, geheimnis 3, kamera 4, kraft 7, objekt 93, sonst 10, start 1, trigger 2, umgebung 15 | | t1l7m005 | Catacombs (roller coaster) | 2390→4782 | 1885 | 9 | 5:54, 11:36, 13:36, 16:9, 30:9 | kamera 1, objekt 1, sonst 51, start 1, trigger 1, umgebung 9 | | t1l8m001 | Lab | 6632→8824 | 3396 | 185 | 1:40, 8:9, 16:16, 17:8, 18:181, 30:56 | ausgang 1, checkpoint 2, geheimnis 2, kamera 8, kraft 2, objekt 99, sonst 3, start 1, trigger 2, umgebung 19 | | t1l8m002 | Lab | 5427→7112 | 2204 | 76 | 16:1, 17:44, 18:496, 30:42 | ausgang 1, geheimnis 1, kamera 5, kraft 2, objekt 74, sonst 2, start 1, trigger 3, umgebung 1 | | t1l8m003 | Lab | 4656→5546 | 1398 | 34 | 16:9, 17:10, 18:196, 30:21 | ausgang 1, checkpoint 2, geheimnis 1, kamera 2, kraft 2, objekt 36, sonst 2, start 1, trigger 3, umgebung 6 | | t1l8m004 | Lab | 5817→8407 | 2993 | 124 | 9:10, 16:66, 17:1, 30:57 | ausgang 1, checkpoint 7, geheimnis 3, kamera 12, kraft 6, objekt 164, sonst 3, start 1, trigger 7, umgebung 46 | | t1l8m005 | Lab | 5375→8660 | 4041 | 179 | 7:10, 16:78, 17:1, 30:82 | checkpoint 7, geheimnis 1, kamera 14, kraft 5, objekt 113, sonst 15, start 1, trigger 2, umgebung 47 | | t1l8m006 | Lab | 5423→5948 | 738 | 44 | 2:13, 8:24, 16:3, 17:5, 18:27, 26:4 | ausgang 1, objekt 15, start 1, trigger 17 | | t6l6m001 | Special (options/map) | 1331→1482 | 333 | 0 | | kamera 1, objekt 3 | | t6l6m002 | Special (options/map) | 3605→3640 | 64 | 0 | | kamera 1, objekt 2 | (Collision polygons counted per TRAK model, not per tile instance.) ## Tests (2026-11-06) **Offline (all 33 debug WADs, `$JOB/tmp/dv/offcheck.py`):** TRAK parses and rebuilds byte-identically; ≤ 8000 vertices per model (max. 2012, t1l4m003); render batches ≤ 256 faces; all texture indices < table size; vertex colour block per tile = nV(model) (all frames); MAP fully parsed with `mapchunk` (0 bytes left over) and rebuilt byte-identically; strats, waypoints, parameter pool, environment zones, zone table/grid, alt block and original tiles unchanged; original models (vertices, faces, **collision**) unchanged byte for byte; new marker models without collision; all other chunks (STPC, sound, LGPC …) identical; tiles within the grid. TRAK+STPC+MAP+LGPC ≤ 7.6 MB (16 MB level arena). **Loaded in game** (lamatest, via slot world 9 as T1L9M001.wad, ~40–90 s played/rotated, no crash, no hang, no errors in the Wine log): t1l1m001 (several times, visual check), t1l1m003, t1l1m004, t1l2m001, t1l2m002, t1l3m001–004 (the river also works normally in slot 9: the boat moves), t1l4m001–003, t1l5m001–003, t1l6m001–003 = 19 levels. The build tested was the one right before the final one: identical geometry, only the colour values of the special materials were switched afterwards to fixed colours per material (+8–16 bytes of texture table). The preview images also come from that build – special material colours in them (e.g. turquoise fill in the mountain image) do not yet fully match the legend above. **Only checked offline:** t1l1m002 and t1l2m003 (the load attempt previously failed at lamatest's menu detection, not at the level), t1l7m001–005 (catacombs/roller coaster), t1l8m001–006 (lab), t6l6m001/002. A test via the real save game slot was not done. lamatest change on the side: save game selection with more attempts and 0.3 s long key presses (under CPU load short presses got lost). Images: `notes/img/debug/00_montage.jpg` (6 worlds), `01_…06_*.jpg` (1280×720).