Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/n64decomp/sm64/llms.txt

Use this file to discover all available pages before exploring further.

Every triangle in SM64’s collision mesh carries a surface type — a 16-bit constant that tells the engine how Mario should interact with it. Surface types control friction, whether a floor is lethal, whether it warps Mario to another area, which camera behaviour to activate, and much more. This page documents all constants defined in include/surface_terrains.h, the struct Surface layout, the terrain-sound system, and the macros used to build raw collision data in level geometry files.

struct Surface

Defined in include/types.h, this struct describes a single collision triangle at runtime.
struct Surface {
    /*0x00*/ TerrainData type;       // surface type constant (SURFACE_*)
    /*0x02*/ TerrainData force;      // parameter for some surface types
    /*0x04*/ s8         flags;       // SURFACE_FLAG_* bitmask
    /*0x05*/ RoomData   room;        // room index (-128..127)
    /*0x06*/ TerrainData lowerY;     // bounding box lower Y
    /*0x08*/ TerrainData upperY;     // bounding box upper Y
    /*0x0A*/ Vec3Terrain vertex1;    // first triangle vertex (s16[3])
    /*0x10*/ Vec3Terrain vertex2;
    /*0x16*/ Vec3Terrain vertex3;
    /*0x1C*/ struct { f32 x; f32 y; f32 z; } normal; // face normal (unit)
    /*0x28*/ f32        originOffset; // plane equation: dot(normal, P) + originOffset = 0
    /*0x2C*/ struct Object *object;   // non-null if this is a dynamic (moving) surface
};
type
TerrainData (s16)
The primary surface type. One of the SURFACE_* constants listed below. Determines floor/wall/ceiling behavior, friction class, special effects, and camera mode.
force
TerrainData (s16)
An auxiliary data word whose meaning depends on type. Used by flowing water, horizontal wind, instant-warp surfaces, and certain camera surfaces to carry directional or warp-target data.
flags
s8 — SURFACE_FLAG_* bitmask
ConstantValueMeaning
SURFACE_FLAG_DYNAMIC0x01Triangle belongs to a moving object
SURFACE_FLAG_NO_CAM_COLLISION0x02Camera passes through this surface
SURFACE_FLAG_X_PROJECTION0x08Use X-axis projection for wall normals
room
RoomData (s8)
The area room index. Objects and Mario are culled from rooms they are not in, enabling BBH and similar interiors to have separate object sets.
normal / originOffset
f32
The precomputed unit normal and the plane equation constant. These are filled in by load_area_terrain at level-load time and used by the collision queries (find_floor, find_ceil, find_wall_collisions).

Surface type constants

Standard floors and friction classes

SURFACE_DEFAULT
0x0000
The default floor. Uses the level’s ambient terrain sound type set by the terrain_type script command. Standard friction.
SURFACE_BURNING
0x0001
Lava (and frostbite in SSL/SL). Landing on this surface deals continuous damage and triggers the burning animation. The surface type is reused for both lava and freezing surfaces depending on level context.
SURFACE_HANGABLE
0x0005
Ceiling that Mario can grab onto and traverse using the hanging locomotion (used in HMC, CotMC, and similar cave ceilings).
SURFACE_SLOW
0x0009
Slows Mario’s movement. Defined but effectively unused in the final game.
SURFACE_DEATH_PLANE
0x000A
Instant kill floor. Mario dies immediately on contact. Used at the bottom of out-of-bounds pits.
SURFACE_VERY_SLIPPERY
0x0013
Equivalent to SURFACE_CLASS_VERY_SLIPPERY. Very high slide friction — Mario slides freely and cannot walk. Used for icy slides and some PSS sections.
SURFACE_SLIPPERY
0x0014
Equivalent to SURFACE_CLASS_SLIPPERY. Moderate sliding; Mario moves with reduced traction. Used on ice patches.
SURFACE_NOT_SLIPPERY
0x0015
Equivalent to SURFACE_CLASS_NOT_SLIPPERY. Maximum grip. Mario cannot slide at all — used on rough surfaces and climbable walls.
SURFACE_HARD
0x0030
Mario always takes fall damage when landing on this surface, regardless of fall distance. Used on metal/stone platforms.
SURFACE_HARD_SLIPPERY
0x0035
Hard + slippery. Always deals fall damage and provides reduced traction.
SURFACE_HARD_VERY_SLIPPERY
0x0036
Hard + very slippery. Always deals fall damage and provides minimal traction.
SURFACE_HARD_NOT_SLIPPERY
0x0037
Hard + maximum grip. Always deals fall damage but Mario cannot slide.
SURFACE_ICE
0x002E
Very slippery ice floor. Used in snow levels (CCM, SL) and THI’s underwater floor. Similar to SURFACE_VERY_SLIPPERY in effect.

Water and quicksand

SURFACE_WATER
0x000D
Marks a water volume surface. Used on some waterboxes but has no associated movement action; the waterbox system handles swimming separately.
SURFACE_FLOWING_WATER
0x000E
Water with a directional current. The force field encodes the flow direction and speed.
SURFACE_SHALLOW_QUICKSAND
0x0021
Quicksand with a depth of 10 units. Mario slowly sinks but can escape.
SURFACE_DEEP_QUICKSAND
0x0022
Lethal quicksand 160 units deep. Mario sinks slowly but dies if fully submerged.
SURFACE_INSTANT_QUICKSAND
0x0023
Instantly lethal quicksand. Mario dies on first contact.
SURFACE_DEEP_MOVING_QUICKSAND
0x0024
Flowing quicksand, 160 units deep. The force field provides the current direction.
SURFACE_SHALLOW_MOVING_QUICKSAND
0x0025
Flowing quicksand, 25 units deep.
SURFACE_QUICKSAND
0x0026
Moving quicksand, 60 units deep.
SURFACE_MOVING_QUICKSAND
0x0027
Flowing quicksand, 60 units deep (primary SSL desert variant).
SURFACE_INSTANT_MOVING_QUICKSAND
0x002D
Instantly lethal flowing quicksand. Not included in the SURFACE_IS_QUICKSAND range check.
The helper macro SURFACE_IS_QUICKSAND(cmd) returns true for types 0x210x27 (excludes SURFACE_INSTANT_MOVING_QUICKSAND).

Wind

SURFACE_HORIZONTAL_WIND
0x002C
Applies a horizontal push force to Mario. The force field encodes the wind direction (yaw angle). Used on SL’s snow plains and the wind corridors in SSL.
SURFACE_VERTICAL_WIND
0x0038
Upward wind combined with a death plane at the bottom. Used in the spiral staircase area to push Mario up. Mario dies if he falls below the associated death boundary.

Warp surfaces

SURFACE_INSTANT_WARP_1B / _1C / _1D / _1E
0x001B–0x001E
Stepping on one of these triggers an immediate area warp. The force field identifies the warp destination. Used in WDW (between the two water level areas), DDD, SSL, TTM, and the endless stairs (to warp back when Mario lacks enough stars).
SURFACE_WARP
0x0032
Generic warp surface.
SURFACE_LOOK_UP_WARP
0x002F
Warps Mario when he looks up while standing on it. Used for the Wing Cap entrance (the castle’s central room).
SURFACE_WOBBLING_WARP
0x00FD
Pool warp used in HMC and DDD.

Timer surfaces

SURFACE_TIMER_START
0x0033
Starts the in-game slide timer. Used at the beginning of Peach’s Secret Slide.
SURFACE_TIMER_END
0x0034
Stops the timer and awards the star if the time is good enough.

Camera-control surfaces

Camera surfaces are intangible to Mario but change the camera behaviour when he enters their volume.
ConstantValueEffect
SURFACE_CLOSE_CAMERA0x000BPulls the camera close to Mario
SURFACE_BOSS_FIGHT_CAMERA0x0065Wide fixed camera for BoB and WF boss fights
SURFACE_CAMERA_FREE_ROAM0x0066Free-roam camera (THI, TTC)
SURFACE_CAMERA_8_DIR0x0069Far camera for platforms (THI)
SURFACE_CAMERA_MIDDLE0x006EReturns camera to the middle (SSL pillars)
SURFACE_CAMERA_ROTATE_RIGHT0x006FCamera rotates right (Bowser 1, THI)
SURFACE_CAMERA_ROTATE_LEFT0x0070Camera rotates left (BoB, TTM)
SURFACE_CAMERA_BOUNDARY0x0072Invisible camera movement limiter
SURFACE_NO_CAM_COLLISION0x0076No camera collision

Misc special surfaces

SURFACE_INTANGIBLE
0x0012
An invisible separation barrier. Used in BBH to isolate the mansion interior from the merry-go-round exterior for room purposes. Mario passes through it.
SURFACE_MGR_MUSIC
0x001A
Triggers the Merry-Go-Round music to play when Mario is standing on it. Handled by handle_merry_go_round_music in bbh_merry_go_round.inc.c.
SURFACE_WALL_MISC
0x0028
Generic wall used for some interactive walls (Warp Pipe, Cannon barrel). Also adjusts camera framing.
SURFACE_SWITCH
0x007A
Non-slippery surface with no camera collision, used by floor switches and Dorrie.
SURFACE_VANISH_CAP_WALLS
0x007B
Walls that can be passed through while wearing the Vanish Cap.
SURFACE_TTM_VINES
0x0016
TTM vine surface — currently has no action defined.
SURFACE_TRAPDOOR
0x00FF
Bowser arena left trapdoor. Has no action defined.

Painting surfaces

Surfaces in the range 0x00A60x00D2 cause the corresponding painting in the castle lobby to wobble when Mario touches them. Surfaces in 0x00D30x00FC warp Mario into the corresponding level painting.
#define SURFACE_IS_PAINTING_WARP(cmd) (cmd >= 0xD3 && cmd < 0xFD)
Selected examples:
ConstantValueLevel
SURFACE_PAINTING_WOBBLE_A60x00A6BoB painting (left zone)
SURFACE_PAINTING_WARP_D30x00D3BoB painting warp (left)
SURFACE_PAINTING_WARP_D90x00D9WF painting warp (left)
SURFACE_PAINTING_WARP_DF0x00DFLLL painting warp (left)
SURFACE_TTC_PAINTING_10x00F4TTC painting warp (left)

Surface class constants

The engine reduces any surface type to one of four friction classes for movement calculations:
ConstantValueMeaning
SURFACE_CLASS_DEFAULT0x0000Standard traction
SURFACE_CLASS_VERY_SLIPPERY0x0013Near-zero traction (slides)
SURFACE_CLASS_SLIPPERY0x0014Reduced traction
SURFACE_CLASS_NOT_SLIPPERY0x0015Maximum traction
The check SURFACE_IS_NOT_HARD(cmd) returns true for all surfaces that do not always cause fall damage (i.e., excludes SURFACE_HARD and 0x350x37).

Terrain sound types

The level script command terrain_type sets the ambient terrain for an area. This controls the footstep sound effects Mario produces. The constant is stored in the level’s area data and accessed via MarioState.terrainSoundAddend.
ConstantValueSound effect theme
TERRAIN_GRASS0x0000Grass / dirt
TERRAIN_STONE0x0001Stone / concrete
TERRAIN_SNOW0x0002Snow
TERRAIN_SAND0x0003Sand
TERRAIN_SPOOKY0x0004Haunted house (quieter, creaky)
TERRAIN_WATER0x0005Splashing
TERRAIN_SLIDE0x0006Slide surface
TERRAIN_MASK = 0x0007 masks out the 3-bit terrain index from the combined sound addend.

Collision data format and macros

Raw collision data for level geometry is stored as Collision (s16) arrays. include/surface_terrains.h defines convenience macros that make these arrays readable:
// Begin a collision data block
COL_INIT()

// Declare N vertices
COL_VERTEX_INIT(vtxNum)

// Individual vertex
COL_VERTEX(x, y, z)

// Begin a group of triangles with a given surface type
COL_TRI_INIT(surfType, triNum)

// A triangle referencing three vertex indices
COL_TRI(v1, v2, v3)

// A triangle with an extra force parameter (flowing water, wind, etc.)
COL_TRI_SPECIAL(v1, v2, v3, param)

// Stop reading triangles for this group (continue to next group)
COL_TRI_STOP()

// End the entire collision block
COL_END()
A minimal example from a level geometry file:
static const Collision my_platform_collision[] = {
    COL_INIT(),
    COL_VERTEX_INIT(4),
        COL_VERTEX(-200,   0, -200),
        COL_VERTEX( 200,   0, -200),
        COL_VERTEX( 200,   0,  200),
        COL_VERTEX(-200,   0,  200),
    COL_TRI_INIT(SURFACE_DEFAULT, 2),
        COL_TRI(0, 1, 2),
        COL_TRI(0, 2, 3),
    COL_TRI_STOP(),
    COL_END(),
};
All vertex coordinates are s16 — they are limited to −32768 … 32767 world units. If your geometry requires larger coordinates, scale the model down or consider splitting collision into multiple pieces.

Water box macros

Water bodies are declared at the end of a collision block using the environment loader:
COL_WATER_BOX_INIT(num)      // declare num water boxes follow
COL_WATER_BOX(id, x1, z1, x2, z2, y)  // axis-aligned water box

TERRAIN_LOAD_* commands

These commands are embedded in the collision data stream itself and are processed by the collision loader, not the physics engine:
ConstantValueRole
TERRAIN_LOAD_VERTICES0x0040Begin vertex list
TERRAIN_LOAD_CONTINUE0x0041End triangle group, continue stream
TERRAIN_LOAD_END0x0042End the entire collision block
TERRAIN_LOAD_OBJECTS0x0043Load macro objects placed in this area
TERRAIN_LOAD_ENVIRONMENT0x0044Load water/gas environment boxes
TERRAIN_LOAD_IS_SURFACE_TYPE_LOW(cmd) is true for commands < 0x40 (real surface types), and TERRAIN_LOAD_IS_SURFACE_TYPE_HIGH(cmd) is true for >= 0x65 (camera surfaces and painting types).

How surface type affects Mario’s movement

The engine maps every type to a surface class (SURFACE_CLASS_*). If the class is VERY_SLIPPERY or SLIPPERY, Mario’s action is set to a sliding action rather than walking. The magnitude of slide deceleration is controlled by the class: very slippery surfaces decelerate very slowly, allowing long slides.
SURFACE_HARD and 0x350x37 always trigger the fall-damage animation and sound regardless of fall height. On all other surfaces, fall damage only occurs when Mario’s fall speed exceeds the threshold.
SURFACE_BURNING is detected by mario_floor_is_lava(). Mario takes periodic damage and is launched upward. The burning-feet animation plays and a timer gates how frequently damage is applied.
Any type for which SURFACE_IS_QUICKSAND(type) is true initiates a sinking sub-action. The depth variant determines how far Mario sinks and whether it is instantly lethal.
SURFACE_HORIZONTAL_WIND, SURFACE_FLOWING_WATER, and the moving quicksand types all use the force field of struct Surface to supply a direction. The physics engine reads this after resolving the floor triangle.
The area-wide TERRAIN_* constant is blended with certain surface-specific overrides. For example, SURFACE_NOISE_DEFAULT and SURFACE_NOISE_SLIPPERY add noise to the default footstep sample.

Build docs developers (and LLMs) love