@majesticfudgie/col-reader
v1.0.0
Published
A TypeScript library for parsing GTA collision (`.col`) files - COLL (v1, GTA III/VC), COL2 (SA PS2), and COL3/COL4 (SA PC/XBOX). Works in both **Node.js** and the **browser** (uses `Uint8Array` input).
Downloads
224
Readme
col-reader
A TypeScript library for parsing GTA collision (.col) files - COLL (v1, GTA III/VC), COL2 (SA PS2), and COL3/COL4
(SA PC/XBOX). Works in both Node.js and the browser (uses Uint8Array input).
Installation
npm install @majesticfudgie/col-readerUsage
A single .col file commonly bundles many named collision models back to back - e.g. a game install's
barriers.col holds one entry per barrier prop (~30 models), not just one.
Node.js
import fs from 'fs';
import COLReader from '@majesticfudgie/col-reader';
const data = new Uint8Array(fs.readFileSync('barriers.col'));
const col = new COLReader(data);
console.log(col.models.length); // e.g. 33
const model = col.getModel('barrierturn');
console.log(model?.boxes, model?.boundingBox);Browser (via fetch)
import COLReader from '@majesticfudgie/col-reader';
const response = await fetch('/models/coll/barriers.col');
const buffer = await response.arrayBuffer();
const col = new COLReader(new Uint8Array(buffer));API
new COLReader(data: Uint8Array)
Creates a new reader and immediately parses every model in the file. A model whose body doesn't match this
parser's understanding of the format is logged (console.error) and replaced with an empty-geometry stand-in
rather than throwing - one malformed entry doesn't take the rest of the file down with it.
| Parameter | Type | Description |
|---|---|---|
| data | Uint8Array | Raw bytes of the .col file |
col.models: COLModel[]
Every model parsed from the file, in file order.
interface COLModel {
version: 1 | 2 | 3 | 4,
name: string,
modelId: number,
boundingSphere: { center: { x, y, z }, radius: number },
boundingBox: { min: { x, y, z }, max: { x, y, z } },
spheres: CollisionSphere[],
boxes: CollisionBox[],
vertices: { x, y, z }[], // empty for box/sphere-only models
faces: CollisionFace[],
flags: number, // V2/3/4 only (0 for V1) - see below
}interface CollisionSphere {
center: { x, y, z },
radius: number,
surface: { material: number, flags: number, brightness: number, light: number },
}
interface CollisionBox {
min: { x, y, z },
max: { x, y, z },
surface: { material: number, flags: number, brightness: number, light: number },
}
interface CollisionFace {
a: number, b: number, c: number, // indices into this model's own `vertices`
material: number,
light: number,
}flags bits (V2/3/4): 0x1 uses lines/cones, 0x2 non-empty, 0x8 has face groups, 0x10 has a shadow mesh
(V3+). Face groups (a spatial acceleration structure over faces), triangle planes, lines/cones, and the shadow
mesh itself aren't parsed yet - not needed for visualization, and derivable from vertices/faces later if
actual physics needs them.
col.getModel(name: string): COLModel | undefined
Case-insensitive lookup by model name.
const model = col.getModel('CasinoBlock2');Format notes
Verified against gtamods.com/wiki/Collision_File, cross-checked
against the reversed engine structs (plugin-sdk's CCollisionData/CColSphere/CColBox/CColTriangle/
CSphere) and OpenRW's loader, then verified a third time against real files extracted from a GTA:SA install -
every .col archive in gta3.img/gta_int.img plus the loose models/coll/{peds,vehicles,weapons}.col
(10,000+ models total, spanning V1/V2/V3).
A couple of things worth knowing if you're extending this:
- V2/3/4 vertex count isn't stored in the header, and can't safely be derived from
offsetToFaces - offsetToVerticeseither - a variable amount of padding/face-group data can sit between the two. This reads all faces first and derives vertex count from the highest vertex index actually referenced. - V1's "unused, always 0" field (per gtamods.com) sits after the box array, not between spheres and boxes - confirmed by decoding real ped ragdoll sphere data (bilaterally symmetric skeletons) at each candidate position and checking which one made every other field size out correctly.
- Real game data isn't always internally consistent - e.g. one stock
peds.colmodel has a handful of triangles whose vertex index is out of range despite everything else about it (sizes, other indices, bounds) checking out. Don't assume every face index is valid; clip/skip rather than trust blindly.
Supported Games
Primarily tested against GTA San Andreas assets (COL2/COL3, and the COLL-format peds.col/vehicles.col/
weapons.col). COLL is shared verbatim with GTA III and Vice City.
