Skip to content

Commit b60c867

Browse files
LinuxJessiclaude
andcommitted
Docs: plain-spoken front page with what's new, Blender guide, consolidated update notes
README rewritten to read top-down: what you get, what's new this month (models in Blender, the character and casino texture fixes, the rendered soundtrack), how to run it, modding, how the disc is laid out, the docs map. Today's five update entries merged into one readable entry. BLENDER.md and the BROWSING tour reworded; MODDING intro softened. New docs/images/blender-models.png: KOS-MOS, Cherenkov and Albedo rendered by Blender from the kit's .glb files. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 801ce9c commit b60c867

6 files changed

Lines changed: 297 additions & 578 deletions

File tree

‎README.md‎

Lines changed: 142 additions & 313 deletions
Large diffs are not rendered by default.

‎docs/BLENDER.md‎

Lines changed: 80 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,98 @@
1-
# Models in Blender
1+
# The models in Blender
22

3-
`browse --kinds models` turns every `.lex` on the disc into a glTF 2.0
4-
binary (`.glb`) under `browse/models/`, mirroring the `dump/` tree:
3+
Run `browse` with the **Models** box ticked (or `--kinds models` on the
4+
command line) and every `.lex` model on the disc becomes a `.glb` file
5+
under `browse/models/`, in the same folders the game uses:
56

67
```
7-
browse/models/chain0/char/pc/kosmos.glb body + face merged (4,568 tris)
8-
browse/models/chain0/char/pc/kosmos_face.glb the face on its own (1,278 tris)
9-
browse/models/chain0/char/pc/kosmos_h.glb alternate outfit
10-
browse/models/chain0/enemy/… obj/… map/… weapon/… robo/…
8+
browse/models/chain0/char/pc/kosmos.glb KOS-MOS, face included
9+
browse/models/chain0/char/pc/kosmos_face.glb just her face
10+
browse/models/chain0/char/pc/kosmos_h.glb her alternate outfit
11+
browse/models/chain0/char/npc/andrew.glb Cherenkov
12+
browse/models/chain0/enemy/… robo/… weapon/… obj/… map/…
1113
```
1214

13-
Each file carries the decoded texture atlas inside it, so a `.glb` is
14-
self-contained: no texture paths to fix up.
15-
16-
## Import
17-
18-
Blender 2.8 or later, no add-on needed:
19-
20-
1. **File ▸ Import ▸ glTF 2.0 (.glb/.gltf)** and pick the file.
21-
2. Leave the importer defaults. "Shading: Normals" uses the game's own
22-
vertex normals; "Pack images" keeps the atlas inside the `.blend`.
23-
3. Switch the viewport to **Material Preview** (the sphere icon, or `Z`
24-
▸ Material Preview) to see the textures.
25-
26-
What you get:
27-
28-
* **One object per game mesh**, named `NN/group/bone`
29-
(`01/kosmos_mune/kosmos_body`): the mesh index, the artist's group
30-
name and the bone it is parented to. Face parts merged in from a
31-
companion file are prefixed with that file's name
32-
(`37/kosmos_face/kosmos_face/kosmos_face`).
33-
* **Materials** named `matN_u<min>-<max>_v<min>-<max>`, the region of the
34-
atlas the material draws from (in atlas pixels, 1024×256 for
35-
character sheets). `_rgba` marks a true-colour material (hair). All
36-
share one image texture; alpha is a cutout (`MASK`) except hair, which
37-
blends.
38-
* **Vertex colours** as the `Col` colour attribute (the game's
39-
per-vertex lighting tint). The importer wires them into the material;
40-
if a model looks too dark or too tinted, disconnect the Color
41-
Attribute node from Base Color.
42-
* **Vertex groups** named `j<id>` on every skinned object, with an
43-
**Armature** called `skeleton` whose bones all sit at the origin. The
44-
weights are the game's; the bone *positions* are not decoded yet (they
45-
live in `.jnt`, see below), so the armature is a flat list of named
46-
joints. You can weight-paint, retarget or build a rig on top of the
47-
groups; you cannot pose the import as-is.
48-
49-
Scale and axes: the game is Y-up in metres (KOS-MOS stands 1.73 units
50-
tall), the same as glTF, so the importer's default "Y up → Z up"
51-
conversion puts her upright on Blender's floor. No scaling needed.
15+
Each file carries its texture inside it, so there are no paths to fix
16+
up. Drop one into Blender and it just works.
17+
18+
## Importing
19+
20+
1. **File ▸ Import ▸ glTF 2.0** and pick the `.glb`.
21+
2. Leave the importer settings alone.
22+
3. Press `Z` and choose **Material Preview** so you see the textures.
23+
24+
Blender 2.8 or newer, no add-ons needed.
25+
26+
## What you will see
27+
28+
**Objects.** One per game mesh, named `number/group/bone`, for example
29+
`01/kosmos_mune/kosmos_body`. The group is the artist's name for the
30+
part; the bone is what it hangs off. Parts that came from a separate
31+
face file are prefixed with that file's name.
32+
33+
**Materials.** Named after the region of the texture they use, like
34+
`mat3_u256-320_v128-256`. They all share one image. Hair materials end
35+
in `_rgba` and blend; everything else uses a cut-out alpha.
36+
37+
**Vertex colours** in the `Col` attribute. That is the game's baked-in
38+
shading tint. If a model looks too dark, unplug the Color Attribute node
39+
from Base Color in the material.
40+
41+
**Vertex groups** named `j<number>` on every skinned part, with an
42+
armature called `skeleton`. The weights are the game's own. The bone
43+
positions are not decoded yet, so the armature is a flat list of named
44+
joints at the origin: you can weight-paint or build a rig on top of it,
45+
but you cannot pose the model as imported.
46+
47+
**Scale.** The game works in metres, Y up, same as glTF. KOS-MOS stands
48+
1.73 m tall and lands upright on Blender's floor with no scaling.
5249

5350
## Which files to open
5451

55-
| Directory under `browse/models/chain0/` | What it is |
52+
| Folder under `browse/models/chain0/` | What is in it |
5653
|---|---|
57-
| `char/pc/` | playable characters: `kosmos`, `shion`, `jr`, `momo`, `chaos`, `ziggy`, variants `*1`, `*2`, `*_h` (alternate outfits), `*_face` (face parts, already merged into the body file) |
58-
| `char/npc/` | every NPC |
54+
| `char/pc/` | the party: `kosmos`, `shion`, `jr`, `momo`, `chaos`, `ziggy`; `*1`, `*2`, `*_h` are alternate outfits; `*_face` are the face parts (already merged into the body files) |
55+
| `char/npc/` | every NPC; Cherenkov is `andrew`, Albedo is `albelt` |
5956
| `enemy/`, `enemy/boss/` | enemies and bosses |
60-
| `robo/` | A.G.W.S. mechs |
61-
| `weapon/pc/` | weapons (KOS-MOS's blades are `kos_hw*`) |
62-
| `obj/` | field props |
63-
| `map/` | field and battle maps (`MC_BTL*` are battle arenas; large) |
64-
65-
A body `.glb` already includes its companion files (anything in the same
66-
folder whose name starts with the body's stem and has no atlas of its
67-
own: `kosmos_face.lex`, `kosmos_h_face.lex` …). The companions are also
68-
written on their own, so `kosmos_face.glb` exists if you only want the
69-
head.
70-
71-
## What is and isn't decoded
72-
73-
Done: geometry, normals, UVs (scaled by the model's declared texture
74-
size and wrapped into each material's atlas region the way the GS
75-
region-repeat did), vertex colours, three skin-weight
76-
encodings, in-stream material changes, true-colour hair sheets, the
77-
atlas itself. Verified against Lakuwu's xenotool: identical triangle and
78-
weight-group counts on the retail disc.
79-
80-
Not yet:
81-
82-
* **Skeleton pose and hierarchy** (`.jnt`). Joints exist as named vertex
83-
groups, bones have no positions. Solving this is the next piece of
84-
work; the `.jnt` holds 0x40-byte blocks with a parent index each.
85-
* **Animation** — not located on the disc yet (the cutscene motion packs
86-
in chain 1 are FL00 containers; battle/field motion is an open thread).
87-
* Two map meshes use vertex formats `0x30`/`0xA0` and are skipped; the
88-
`.glb`'s `extras.warnings` lists them.
89-
* **Eyelashes.** Every character has a `*_matu` lash mesh (UV type
90-
`0x7F`, a 32×32 sheet). Its vertex colours are flat white, so the dark
91-
lash look is entirely the texture — and that sheet is 4-bit (PSMT4),
92-
which the texture decoder does not read yet (the same open thread as
93-
KOS-MOS's visor HUD). The lashes export with the right UVs onto the
94-
atlas but show whatever the PNG has in that spot; the material is
95-
named `…_lash-4bpp-undecoded` so it is easy to hide or recolour.
96-
* Blend shapes (weight format 1024 — the face files carry some) are
97-
ignored.
98-
99-
## Re-exporting a single model from Python
57+
| `robo/` | the A.G.W.S. mechs |
58+
| `weapon/pc/` | weapons |
59+
| `obj/` | props |
60+
| `map/` | field and battle maps (`MC_BTL*` are the battle arenas; large) |
61+
62+
A body file already includes its companions: anything in the same
63+
folder whose name starts with the body's name and has no texture of its
64+
own (`kosmos_face.lex`, `kosmos_h_face.lex`). The companions are also
65+
written on their own, so `kosmos_face.glb` is there if you only want
66+
the head.
67+
68+
## Known gaps
69+
70+
* **No skeleton pose yet.** The joints come through as named vertex
71+
groups; their positions and hierarchy live in the `.jnt` files, which
72+
are the next thing to decode.
73+
* **No eyelashes.** Every character has a lash mesh whose texture is a
74+
tiny 4-bit sheet the texture decoder cannot read yet. The lashes are
75+
in the file with correct UVs; their material is named
76+
`…_lash-4bpp-undecoded` so it is easy to hide.
77+
* **No animation.** Not located on the disc yet.
78+
* Two map meshes use vertex formats the parser skips, and blend shapes
79+
are ignored. Anything skipped is listed in the `.glb`'s `extras`.
80+
81+
## From Python
10082

10183
```python
10284
import arx, lex
10385
from browse import decode_xtx, png_bytes
10486

105-
raw = open("out/dump/chain0/char/pc/kosmos.lex", "rb").read()
106-
model = lex.parse_lex(arx.decompress(raw)) # dump files are ARX-packed
107-
face = lex.parse_lex(arx.decompress(open(".../kosmos_face.lex", "rb").read()))
108-
lex.merge_companion(model, face, "kosmos_face/")
87+
body_lex = arx.decompress(open("out/dump/chain0/char/pc/kosmos.lex", "rb").read())
88+
face_lex = arx.decompress(open("out/dump/chain0/char/pc/kosmos_face.lex", "rb").read())
89+
body = lex.parse_lex(body_lex)
90+
lex.merge_companion(body, lex.parse_lex(face_lex), "kosmos_face/")
10991

110-
xtx = arx.decompress(open(".../kosmos.xtx", "rb").read())
111-
w, h, rgba, _ = decode_xtx(xtx, [lex_bytes_for_kosmos, lex_bytes_for_face])
112-
open("kosmos.glb", "wb").write(lex.to_glb(model, png_bytes(w, h, rgba), (w, h)))
92+
xtx = arx.decompress(open("out/dump/chain0/char/pc/kosmos.xtx", "rb").read())
93+
w, h, rgba, _ = decode_xtx(xtx, [body_lex, face_lex])
94+
open("kosmos.glb", "wb").write(lex.to_glb(body, png_bytes(w, h, rgba), (w, h)))
11395
```
11496

115-
The format itself is written up in [FORMATS.md](FORMATS.md) § LEX models.
97+
The file format itself is written up in [FORMATS.md](FORMATS.md) under
98+
"LEX models".

‎docs/BROWSING.md‎

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# Browsing the extraction — a guided tour
1+
# A tour of the output
22

3-
What you have after running `extract` + `classes` + `browse` against the USA
4-
disc, and how to poke around in it. Numbers below are from a full extraction
5-
of SLUS-20469; yours will match.
3+
This is what you have after running `extract`, `classes` and `browse`,
4+
and where to look first. The counts are from a full extraction of the
5+
USA disc; yours will match.
66

77
```
88
out/
@@ -12,9 +12,9 @@ out/
1212
browse/classes_manifest.csv one row per lifted Java class
1313
```
1414

15-
Rule of thumb: **`dump/` is for tools, `browse/` is for humans.** Everything
16-
in `browse/` is derived from `dump/` (or straight from the ISO) by decoders
17-
described in [FORMATS.md](FORMATS.md).
15+
Rule of thumb: **`dump/` is for tools, `browse/` is for people.** Everything
16+
in `browse/` is made from `dump/` by the decoders described in
17+
[FORMATS.md](FORMATS.md).
1818

1919
## The three areas of `dump/`
2020

@@ -79,9 +79,9 @@ can be recovered later from the playback code. Sizes run from 2.5 MB
7979
audio**; they play in VLC/ffplay as-is (video) and convert to proper MP4s
8080
with `browse --kinds movies`.
8181

82-
## `browse/` — the human-readable mirror
82+
## `browse/` — the folder you actually open
8383

84-
Each `browse` kind writes one subtree, preserving `dump/` paths:
84+
Each kind of conversion writes one subtree, keeping the `dump/` paths:
8585

8686
| Directory | Count | From | Open with |
8787
|---|---|---|---|
@@ -96,11 +96,13 @@ Each `browse` kind writes one subtree, preserving `dump/` paths:
9696
| `classes/` | ~2,200 `.class` | `.evt` FL00 containers | `javap -c -p`, CFR, Krakatau |
9797
| `code/` | 19 binaries | ISO filesystem (`--code`) | Ghidra / readelf |
9898

99-
Highlights per subtree:
99+
Worth opening first:
100100

101+
* **`models/chain0/char/pc/`** — the party in Blender-ready `.glb` files;
102+
see [BLENDER.md](BLENDER.md).
101103
* **`textures_png/chain0/tanaka/`** — 109 casino graphics: slot reels, poker
102-
tables, card faces. The single best "wait, this shipped in a folder named
103-
after a guy?" browse.
104+
tables, card faces. The best "wait, this shipped in a folder named
105+
after a guy?" moment on the disc.
104106
* **`textures_png/chain0/carddata/`** — all 117 card-game faces.
105107
* **`textures_png/_embedded/`** — the second texture trove: battle-effect
106108
sheets from the `.esd`/`.esp` effect libraries, scene-archive art from

‎docs/MODDING.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Modding Xenosaga Episode I — how the repack layer actually works
22

3-
This is the mechanics document: everything you need to modify the tools —
4-
or write your own — **without re-deriving anything**. Byte-level format
5-
reference lives in [FORMATS.md](FORMATS.md); this file explains how the
6-
pieces fit and why they are built the way they are. Everything below was
7-
established and verified on the USA disc (SLUS-20469) in July 2026.
3+
This is the mechanics document. If you want to change the tools, or
4+
write your own, it tells you how the pieces fit and why they are built
5+
the way they are, so you never have to re-derive anything. The
6+
byte-level format reference is [FORMATS.md](FORMATS.md). Everything here
7+
was worked out and verified on the USA disc in July 2026.
88

99
The worked example throughout is the KOS-MOS hair recolor (`pinkhair.py`),
1010
because it hit every layer: palettes, true-colour pixels, compression,

0 commit comments

Comments
 (0)