mkds.nkm module¶
- class mkds.nkm.Section(data, size)[source]¶
Bases:
object
Base class for sections in an NKM file.
Overview¶
- Most NKM sections (all except STAG) begin with an 8-byte section header:
0x00 (4 bytes): Section magic (ASCII, e.g., “OBJI”).
0x04 (4 bytes): Number of entries in the section (UInt32).
Immediately after the header the section contains entry_count entries, each with a fixed stride (size) which is specified by the concrete Section subclass.
- This base class encapsulates:
raw data for the whole section (header + entries)
stride (size in bytes of a single entry)
entry_count parsed from the header
an iterator over each fixed-size entry slice
Notes / Caveats¶
This class assumes the data passed includes the section header.
If a section contains variable-length entries (rare in NKM), a custom parser should be used instead of relying on a fixed stride.
Many sections have fields where 0xFFFF or 0xFF indicates “unused” or “none” — callers should treat those sentinel values accordingly.
- class mkds.nkm.OBJI(data)[source]¶
Bases:
Section
OBJI — Object Instances section.
Stride: 0x3C bytes per entry.
Purpose¶
Describes every object placed in the track: visual decorations, interactive objects, obstacle instances, item boxes, etc. These objects are instantiated by the game engine and can be linked to PATH routes.
OBJI Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos
3D position vector (FX32).
0x0C
VecFx32
rot
3D rotation vector.
0x18
VecFx32
scale
3D scale vector.
0x24
u16
object_id
Object ID (model/behavior).
0x26
u16
route_id
Route ID (0xFFFF = none).
0x28
u32
setting0
Object-specific setting 0.
0x2C
u32
setting1
Object-specific setting 1.
0x30
u32
setting2
Object-specific setting 2.
0x34
u32
setting3
Object-specific setting 3.
0x38
u32
show_tt
Visible in Time Trials (1=yes,0=no).
Gameplay Context¶
The object ID decides both model and in some cases runtime logic (collision, activatable behaviors).
The route_id links the object to a PATH. If present, the object will be moved/animated by the PATH’s POIT points at runtime (e.g., moving platforms, cameras).
The object settings are used by many object types to control behavior: rotation speed, spawn flags, timers, random seeds, or other per-object parameters. Different object IDs require different decoding logic.
Reverse-Engineering Notes / Tips¶
The four 32-bit settings differ radically between object types — community wikis often contain per-object decode rules (use object ID to branch).
The presence of a non-0 or non-0xFFFFFFFF route_id often means the object will be animated along that route; route indices are bytes in PATH entries but stored here as a 16-bit value (keep an eye on sign/width).
Show-in-time-trials: historically some editors used 0/1 inverse; verify against known tracks when in doubt.
Parsing Caveat¶
We read object_id as read_u16 and route_id as read_u16. Consumers of this class should treat 0xFFFF in route_id as “no route”.
- class mkds.nkm.PATH(data)[source]¶
Bases:
Section
PATH — Path metadata.
Stride: 0x04 bytes per entry.
Purpose¶
Describes metadata for routes used by objects and cameras. Each PATH entry points to a sequence of POIT entries (control points) that define the route.
PATH Entry Structure¶
Offset
Type
Name
Description
0x00
u8
route_id
Route identifier.
0x01
u8
loop
1 if route loops, else 0.
0x02
u16
point_ct
Number of POIT points.
Gameplay Context¶
Objects or cameras that reference a route will move along the POIT points in order; if the loop flag is set, the route repeats.
Route ID is commonly a small integer; the PATH list enumerates all routes in use on the track.
Reverse-Engineering Notes / Caveats¶
The canonical spec states: 0x01 == 1 if the route loops, 0 otherwise. In the code you originally used read_u8(d, 0x01) != 1 (which inverts the meaning). I have NOT altered your logic — but be aware of the discrepancy: callers should expect True when the route loops. Consider changing to read_u8(… ) == 1 for clarity.
point_count enumerates POIT entries but the mapping from global POIT index to route is (index offset + length) — consumers should reconstruct the actual POIT index ranges using CPAT/EPAT/IPAT/MEPA grouping sections when applicable (these groupings partition points).
- class mkds.nkm.POIT(data)[source]¶
Bases:
Section
POIT — Path points (control points).
Stride: 0x14 bytes per entry.
Purpose¶
Stores the actual 3D points used by PATH routes. Points are grouped by route using the counts stored in PATH plus the various *PAT grouping sections.
POIT Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos
3D position vector.
0x0C
u8
index
Point index in route.
0x0D
u8
unknown1
Unknown/padding.
0x0E
s16
duration
Point duration (optional).
0x10
u32
unknown2
Reserved/unknown.
Gameplay Context¶
Moving objects and cameras read these points sequentially to interpolate positions. The “point_index” normally indicates position in the route’s ordering (0,1,2,…).
Some cameras or scripted objects use point_duration to wait between points, enabling non-linear motion.
POIT order in the file is important: group membership is often determined by successive ranges; use PAT sections to map ranges to specific routes.
Reverse-Engineering Notes¶
The unknown fields often show consistent patterns per track editor — check community resources to decode them for special behaviors.
Some older track versions or beta files encode rotation differently; when in doubt, cross-check with KTPJ notes for version-dependent behavior.
- class mkds.nkm.STAG(data)[source]¶
Bases:
object
STAG — Stage (track) information.
Fixed-size: The STAG section is unique in NKM: it does NOT have a section header and is a single 0x2C-byte structure placed directly in the file (after POIT in the canonical header ordering).
Purpose¶
Contains global track settings: track ID, default lap count, fog settings, colors used by KCL (collision visual palettes), and other miscellaneous bytes.
STAG Entry Structure¶
Offset
Type
Name
Description
0x00
char[4]
magic
Always “STAG”.
0x04
u16
track_id
Track ID.
0x06
u16
laps
Lap count.
0x08
u8
unknown1
Unknown small integer.
0x09
u8
fog_enabled
1 = fog on, 0 = off.
0x0A
u8
fog_mode
Fog generation mode.
0x0B
u8
fog_slope
Fog slope.
0x0C
u8
u0
Unknown.
0x0D
u8
u1
Unknown.
0x0E
u8
u2
Unknown.
0x0F
u8
u3
Unknown.
0x10
u8
u4
Unknown.
0x11
u8
u5
Unknown.
0x12
u8
u6
Unknown.
0x13
u8
u7
Unknown.
0x14
Fx32
fog_dist
Fog distance.
0x18
GXRgb
fog_color
Fog color.
0x1A
u16
fog_alpha
Fog alpha (0–15).
0x1C
GXRgb
kcl_color1
Default KCL color 1.
0x1E
GXRgb
kcl_color2
Default KCL color 2.
0x20
GXRgb
kcl_color3
Default KCL color 3.
0x22
GXRgb
kcl_color4
Default KCL color 4.
0x24
u8
v0
Unknown.
0x25
u8
v1
Unknown.
0x26
u8
v2
Unknown.
0x27
u8
v3
Unknown.
0x28
u8
v4
Unknown.
0x29
u8
v5
Unknown.
0x2A
u8
v6
Unknown.
0x2B
u8
v7
Unknown.
Gameplay Context¶
Amount of laps controls how many laps the race uses by default for the stage; some tracks use lap_count = 0 for special cases (verify per track).
Fog parameters influence rendering: enabling fog can hide distant objects and alter perceived depth; fog color & distance control atmosphere.
KCL colors are the default palette for collision visualization (useful for editors and collision debugging).
Implementation Notes¶
This class sets placeholders for color fields (GXRgb) — you can implement GXRgb decoding (usually 2 bytes per color or platform-specific) and populate these fields for richer output.
The unknown arrays are repeated in code (unknown2 and unknown3) — that mirrors the spec layout but may be redundant; keep one copy or rename for clarity if desired.
- class mkds.nkm.KTPS(data)[source]¶
Bases:
Section
KTPS — Kart/Start Positions (Start points for racers).
Stride: 0x1C bytes per entry.
Purpose¶
Defines start positions (spawn/starting grid) for players/racers. Typically used for the main race starts; can also be used in battle or mission modes.
KTPS Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos
3D position vector (spawn).
0x0C
VecFx32
rot
3D rotation vector.
0x18
u16
padding
Padding (0xFFFF).
0x1A
u16
index
Start index (battle/mission).
Gameplay Context¶
On race start, the game picks starting positions from this section.
start_position_index is relevant for battle stages or mission mode where start ordering differs from main racing.
The rotation vector might be stored differently in beta versions — the canonical community notes indicate the Y-rotation sometimes needs to be computed via Atan2 on rotation vector components for older versions.
Notes / Community Tips¶
Typically the number of KTPS entries equals the number of players or more (some tracks list more possible starts than vehicles).
If you want to reposition start locations, modify positions and write the file back in FX32 format.
- class mkds.nkm.KTPJ(data)[source]¶
Bases:
Section
KTPJ — Respawn positions (kart respawn).
Stride: 0x20 bytes per entry.
Purpose¶
Positions to which a kart (player) can respawn after falling off or during certain scripted events. Contains references to enemy/item points (EPOI/IPOI) to determine nearby behavior or AI context.
KTPJ Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos
3D position vector.
0x0C
VecFx32
rot
3D rotation vector.
0x18
u16
enemy_id
Enemy position ID (EPOI).
0x1A
u16
item_id
Item position ID (IPOI).
0x1C
u32
respawn_id
Respawn identifier.
Gameplay Context¶
When a kart falls off the track or hits a severe collision, the engine picks a KTPJ respawn that matches the current lap and nearby conditions.
The enemy/item IDs let respawn logic pick nearby AI/item spawn points for smoother reintroduction.
Version Notes¶
For version 0x1E (older beta), the final Respawn ID (0x1C) may not exist.
The rotation encoding changed for early beta versions; if reading older tracks, compute Y-rotation via atan2(Rx, Rz) to convert to degrees.
Remarks for Parser¶
We read respawn_id as a 32-bit value; if parsing older tracks that omit it, ensure you guard read beyond section length.
- class mkds.nkm.KTP2(data)[source]¶
Bases:
Section
KTP2 — Lap checkpoints (points to pass to count lap progress).
Stride: 0x1C bytes per entry.
Purpose¶
Defines the “lap gate” points that the engine checks to determine whether a player completed a lap. Usually combined with timing/ordering checks.
KTP2 Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos
3D position vector.
0x0C
VecFx32
rot
3D rotation vector.
0x18
u16
padding
Padding (0xFFFF).
0x1A
u16
index
Index (0xFFFF typical).
Gameplay Context¶
The race logic queries these points as canonical lap markers.
Often unused fields are set to 0xFFFF; do not treat them as valid indices.
Notes
The “Index” is usually unused (set to 0xFFFF); if present, it may participate in specialized lap logic or developer tools.
- class mkds.nkm.KTPC(data)[source]¶
Bases:
Section
KTPC — Cannon / Pipe destination points.
Stride: 0x1C bytes per entry.
Purpose¶
Describes destinations for cannons/pipes used in certain stages (mostly in battle stages). Cannon indices are used by specialized collision types.
KTPC Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos
3D position (destination).
0x0C
VecFx32
rot
3D rotation vector.
0x18
u16
unknown
Unknown.
0x1A
u16
cannon_idx
Cannon index (links activator/destination).
Gameplay Context¶
Cannon/pipe logic teleports an object/player to the KTPC destination.
The cannon_index can be used as a link between activator and destination.
Notes
In many tracks this section is small or absent; treat missing sections gracefully when writing tools that modify KTPC entries.
- class mkds.nkm.KTPM(data)[source]¶
Bases:
Section
KTPM — Mission points.
Stride: 0x1C bytes per entry.
Purpose¶
Points used by mission objectives (mission mode). They often resemble KTPS/KTP2 entries but have mission-specific indexing.
KTPM Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos
3D position vector.
0x0C
VecFx32
rot
3D rotation vector.
0x18
u16
padding
Padding (0xFFFF).
0x1A
u16
index
Mission index.
Gameplay Context¶
Missions may use these points to define target positions or spawns.
index can be used in mission scripts to select a specific point out of the KTPM array.
Notes
If the track is not a mission type, these often default to 0xFFFF.
- class mkds.nkm.CPOI(data)[source]¶
Bases:
Section
CPOI — Checkpoints (2D oriented).
Stride: 0x24 bytes per entry.
Purpose¶
Defines checkpoint segments used for lap counting, key handling, and respawn logic. CPOI includes two 2D positions and precomputed trig/distance values used by the engine to determine crossing and checkpoint ordering.
CPOI Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32 (2D)
pos1
2D position 1.
0x08
VecFx32 (2D)
pos2
2D position 2 (other edge).
0x10
Fx32
sin
Precomputed sine.
0x14
Fx32
cos
Precomputed cosine.
0x18
Fx32
distance
Distance between pos1/pos2.
0x1C
s16
section1
Section data 1 (unknown).
0x1E
s16
section2
Section data 2 (unknown).
0x20
u16
key_id
0x0000=lap, 0xFFFF=none.
0x22
u8
respawn_id
Respawn ID.
0x23
u8
unknown
Unknown/padding.
Gameplay Context¶
CPOIs are the canonical gate the engine checks for lap progress.
The Key ID allows some checkpoints to behave as keys (for gates, or race logic). If Key ID == 0x0000 the point counts as the lap marker.
The precomputed sinus/cosinus/distance allow the engine to quickly test whether a player crossed the checkpoint along the correct orientation.
Reverse-Engineering Notes¶
Community docs note the section_data fields are partially decoded for special track logic. If you need precise behavior, compare original tracks and observe in-engine behavior.
- class mkds.nkm.CPAT(data)[source]¶
Bases:
Section
CPAT — CPOI grouping (checkpoint groups).
Stride: 0x0C bytes per entry.
Purpose¶
Groups CPOI entries into logical sequences (routes/sections). Each CPAT entry points to a contiguous block of CPOI points and describes adjacency (previous/next groups) and section order.
CPAT Entry Structure¶
Offset
Type
Name
Description
0x00
u16
point_start
Start index into CPOI array.
0x02
u16
point_len
Number of points.
0x04
u8
next0
Next group index 0.
0x05
u8
next1
Next group index 1.
0x06
u8
next2
Next group index 2.
0x07
u8
prev0
Previous group index 0.
0x08
u8
prev1
Previous group index 1.
0x09
u8
prev2
Previous group index 2.
0x0A
s16
section_order
Section ordering index.
Gameplay Context¶
CPAT allows complex checkpoint graphs (non-linear courses) by connecting multiple CPOI groups.
Useful when a single lap uses multiple discontiguous checkpoint regions.
Implementation Notes¶
The next_group and prev_group arrays use 0xFF as “unused”; treat sentinel values accordingly.
- class mkds.nkm.IPOI(data)[source]¶
Bases:
Section
IPOI — Item spawn points.
Stride: 0x14 bytes per entry.
Purpose¶
Describes where items (like red shells, bananas) may spawn or where items follow a path along a route. IPOI entries are often referenced by KTPJ (respawn) or object logic.
IPOI Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos
3D position vector.
0x0C
Fx32
scale
Point scale (size/weight).
0x10
u32
unknown
Reserved field.
Gameplay Context¶
Items may spawn at IPOI locations or be used for scripted item routes.
point_scale may modify spawn probability or area radius.
Notes
The unknown 32-bit value is often zero; it may contain bitflags in certain custom tracks.
- class mkds.nkm.IPAT(data)[source]¶
Bases:
Section
IPAT — IPOI grouping.
Stride: 0x0C bytes per entry.
Purpose¶
Group IPOI entries into contiguous point ranges and define adjacency, much like CPAT but for item points.
IPAT Entry Structure¶
Offset
Type
Name
Description
0x00
u16
point_start
Start index into IPOI array.
0x02
u16
point_len
Number of points.
0x04
u8
next0
Next group index 0.
0x05
u8
next1
Next group index 1.
0x06
u8
next2
Next group index 2.
0x07
u8
prev0
Previous group index 0.
0x08
u8
prev1
Previous group index 1.
0x09
u8
prev2
Previous group index 2.
0x0A
s16
section_order
Section ordering index.
Gameplay Context¶
Used by item routing and by respawn selection to find nearby item points.
- class mkds.nkm.EPOI(data)[source]¶
Bases:
Section
EPOI — Enemy/CPU path points.
Stride: 0x18 bytes per entry.
Purpose¶
Defines points that the CPU opponents use for their routing (AI paths). These influence how CPUs drive the course (lines, drifting behavior, etc).
EPOI Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos
3D position vector.
0x0C
Fx32
scale
Point scale (radius/weight).
0x10
s16
drift
Drifting parameter.
0x12
u16
unknown1
Unknown flag.
0x14
u32
unknown2
Engine metadata.
Gameplay Context¶
CPU behavior heavily depends on EPOI positions and the drifting parameter — altering these can change how tight/loose CPUs corner.
EPOI groups are linked via EPAT entries (below).
Notes
The meaning of the 0x14 32-bit word is partially unknown in community docs; experiments suggest it can contain flags for AI behavior.
- class mkds.nkm.EPAT(data)[source]¶
Bases:
Section
EPAT — EPOI grouping.
Stride: 0x0C bytes per entry.
Purpose¶
Groups EPOI points into contiguous blocks and defines adjacency (next/prev groups) and section ordering. Used by CPU pathing code to navigate routes.
EPAT Entry Structure¶
Offset
Type
Name
Description
0x00
u16
point_start
Start index into EPOI array.
0x02
u16
point_len
Number of points.
0x04
u8
next0
Next group index 0.
0x05
u8
next1
Next group index 1.
0x06
u8
next2
Next group index 2.
0x07
u8
prev0
Previous group index 0.
0x08
u8
prev1
Previous group index 1.
0x09
u8
prev2
Previous group index 2.
0x0A
s16
section_order
Section ordering index.
Gameplay Context¶
EPAT partitions EPOI arrays into logical AI routes; enabling multiple CPU strategies per segment.
- class mkds.nkm.MEPO(data)[source]¶
Bases:
Section
MEPO — Mini-game enemy points.
Stride: 0x18 bytes per entry.
Purpose¶
Similar to EPOI but used by specific mini-games; describes where minigame entities spawn/move.
MEPO Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos
3D position vector.
0x0C
Fx32
scale
Point scale.
0x10
s32
drifting
Drifting parameter (32-bit).
0x14
u32
unknown
Unknown/reserved.
Gameplay Context¶
MEPO entries are used only in special mini-game contexts and may allow more variety (hence Int32 for drifting).
- class mkds.nkm.MEPA(data)[source]¶
Bases:
Section
MEPA — MEPO grouping (for mini-games).
Stride: 0x14 bytes per entry.
Purpose¶
Groups MEPO points into sequences. MEPA entries support up to 8 next and 8 previous groups (Byte[8]) because mini-games may have richer topology.
Gameplay Context¶
Use MEPA to create complex mini-game movement graphs (multiple branching).
- class mkds.nkm.AREA(data)[source]¶
Bases:
Section
AREA — Camera/zone areas.
Stride: 0x48 bytes per entry.
Purpose¶
Defines 3D regions used by the engine for camera selection and environmental triggers (sounds like waterfalls). Each area contains a center position, axes/length vectors (defining an oriented bounding box), and metadata such as area type and camera ID.
AREA Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos
Center position vector.
0x0C
VecFx32
length_vec
Length vector.
0x18
VecFx32
x_vec
X-axis vector.
0x24
VecFx32
y_vec
Y-axis vector.
0x30
VecFx32
z_vec
Z-axis vector.
0x3C
s16
u0
Unknown.
0x3E
s16
u1
Unknown.
0x40
s16
u2
Unknown.
0x42
u8
u3
Unknown.
0x43
u8
camera_id
Camera index (CAME ref).
0x44
u8
area_type
Area type (0x01=camera, etc.).
0x45
s16
u4
Unknown.
0x47
u8
u5
Unknown.
Gameplay Context¶
AREA sections usually determine which camera the engine should switch to when the player is inside the region.
Camera ID links to CAME entries; Area type allows special behavior (e.g., waterfall sound triggers).
Good for editors to preview camera transitions.
Notes
Several fields are still undocumented; their meaning varies by track.
- class mkds.nkm.CAME(data)[source]¶
Bases:
Section
CAME — Camera definitions.
Stride: 0x4C bytes per entry.
Purpose¶
Defines camera motions and static camera positions used in cutscenes, intros, and dynamic in-game camera triggers. Camera entries are often linked by AREA zones or object routes.
CAME Entry Structure¶
Offset
Type
Name
Description
0x00
VecFx32
pos1
Primary position vector.
0x0C
VecFx32
rot
Rotation vector.
0x18
VecFx32
pos2
Secondary position vector.
0x24
VecFx32
pos3
Tertiary position vector.
0x30
s16
fov_begin
Field-of-view start.
0x32
Fx16
fov_beg_sin
Precomputed sine for FOV start.
0x34
Fx16
fov_beg_cos
Precomputed cosine for FOV start.
0x36
s16
fov_end
Field-of-view end.
0x38
Fx16
fov_end_sin
Precomputed sine for FOV end.
0x3A
Fx16
fov_end_cos
Precomputed cosine for FOV end.
0x3C
u16
zoom
Camera zoom factor.
0x3E
u16
type
Camera type.
0x40
u16
linked_route
Linked PATH route index (0xFFFF = none).
0x42
u16
route_speed
Speed along linked route.
0x44
u16
point_speed
Speed between points.
0x46
u16
duration
Duration (1/60s units).
0x48
u16
next_cam
Next camera index (0xFFFF = none).
0x4A
u8
intro_pan
Intro pan indicator (0=none,1=top,2=bot).
0x4B
u8
unknown
Unknown (1 if type==5).
Camera Type (common)¶
Bit Offset
Description
0x00
After race camera
0x01
Unknown (with route)
0x02
Unknown
0x03
Intro camera (top screen)
0x04
Intro camera (bottom screen)
0x05
Unknown
0x06
Unknown
0x07
Battle mode camera
0x08
Mission finish camera
Gameplay Context¶
CAME entries drive cinematic camera movement during intros, cutscenes, and special camera modes.
Linked route + point speed define how the camera follows a PATH.
Camera duration uses 1/60th-second units — helpful for exact timing.
Notes & Community Tips¶
Many of these fields are precomputed (sine/cosine) for faster in-engine interpolation. Editors can either preserve or recompute them.
The “next camera” field allows building camera chains for sequences.
When building camera editors, expose both positions and FOV values to enable previewing transitions correctly.
- class mkds.nkm.NKM(data)[source]¶
Bases:
object
NKM — Mario Kart DS Course Map parser.
Purpose¶
Top-level container that parses the NKM file header and initializes objects representing each section (OBJI, PATH, POIT, STAG, KTPS, … , CAME).
Usage Example¶
>>> nkm = NKM.from_file("my_course.nkm") >>> print(len(nkm._OBJI)) # number of object instances >>> print(nkm._STAG.amt_of_laps) # global lap count for the stage
Implementation Details¶
The typical header length is 0x4C and contains offsets (UInt32) to 17 canonical sections in standard order. Offsets are relative to the end of the header (H), so they are added to _header_offset to compute absolute positions inside the file.
This parser assumes the “typical” header layout. If an NKM contains additional special sections (like NKMI) or a different header length, additional handling will be required.
Parsing is defensive but assumes the file is well-formed; for robust tools consider adding bounds checks when slicing self._data[…].
Known Limitations¶
Some fields (GXRgb, camera_type, some unknown bytes) are left as None or unknown placeholders. Implementing GXRgb and Fx16/Fx32 conversions will enable richer output.
The code currently uses PATH.has_loop = read_u8(…) != 1 which inverts the canonical meaning (spec: 1 means loop). Consider normalizing this if you rely on literal interpretation elsewhere.
See also
The
,and