3DS File Documentation


Summary

A .3ds file is a 3D Studio Mesh: Autodesk's old binary 3D model format storing mesh geometry, materials, cameras, lights, and keyframe animation. Introduced in 1990 for DOS-based 3D Studio, it survives as a widely readable interchange format (MIME image/x-3ds). Open one free in Blender, MeshLab, or the browser viewer 3DViewer.net; convert to .stl to 3D print it or to OBJ/FBX for modern pipelines.

Technical details

FeatureValue
Full name3D Studio Mesh
File extension.3ds
MIME typeimage/x-3ds
Format typeBinary, chunk-based 3D mesh/scene format
DeveloperAutodesk (originally The Yost Group / 3D Studio for DOS)
Introduced1990 (3D Studio for DOS); native until 3D Studio MAX 1.0, 1996
Open standardNo — proprietary, but widely reverse-engineered
Byte orderLittle-endian
Chunk header2-byte chunk ID + 4-byte length (6 bytes)
Magic number4D 4D (0x4D4D, MAIN3DS primary chunk) at offset 0
Vertex precision32-bit floats
StoresMeshes, UVs, materials, cameras, lights, keyframe animation
Name limitObject/material names capped at 10 characters (DOS legacy)
LimitationsNo sub-objects, PBR materials, or modern shaders
Native successor.max (full 3ds Max scene)
Related extensions.max, .obj, .fbx, .dae, .stl, .prj
Free toolsBlender, MeshLab, FBX Review, 3DViewer.net
NoteNintendo 3DS game ROMs also use .3ds — an unrelated file type
File signature (magic bytes)
4D 4D

Offset 0, 2 bytes. This is the ID of the primary chunk MAIN3DS (0x4D4D), read as a little-endian 16-bit value. It is immediately followed by a 4-byte little-endian length giving the size of the whole file. The rest of the file is a tree of nested chunks, each a 2-byte ID plus 4-byte length. Note that little-endian TIFF also begins with the ASCII MM bytes, so confirm a 3DS by checking that a valid chunk length and known sub-chunks follow, not the first two bytes alone.

What is a 3DS file?

The .3ds extension is the native file format of Autodesk 3D Studio, the DOS-based 3D modelling and animation program first released in 1990. When 3D Studio was replaced by 3D Studio MAX in 1996 (whose native scene format is .max), .3ds did not disappear. It survived as a lightweight, almost universally readable interchange format for 3D meshes, which is why it still turns up in asset libraries, game tools, and old model archives decades later.

Technically a 3DS file is binary and chunk-based: a tree of nested records, each tagged with an ID and a length, storing mesh geometry (vertices, faces, UV coordinates), materials, cameras, lights, and keyframe animation. Because the format dates to the DOS era it has hard limits: vertex coordinates are 32-bit floats, object and material names are capped at ten characters, and there is no concept of sub-objects, modern shaders, or physically based materials. Those constraints are why newer pipelines prefer FBX, OBJ, or glTF, and why .3ds is now mostly a legacy import/export option that remains useful precisely because nearly every 3D application can read it.

The chunk: a 2-byte ID and a 4-byte length

Everything in a 3DS file is a chunk. A chunk is a 6-byte header followed by its data and any child chunks. The first two bytes are the chunk ID; the next four are a little-endian 32-bit length giving the size of the entire chunk, header included.

struct Chunk {
    uint16  id;      // bytes 0-1: chunk identifier, e.g. 0x4D4D
    uint32  length;  // bytes 2-5: total bytes of this chunk incl. children
    byte    data[];  // payload, which may itself contain nested chunks
};

Because the length covers the chunk and all of its descendants, a reader that meets an unknown ID simply adds length to the current offset and continues — unknown chunks are skipped cleanly. That single rule is what lets a modern importer read a 3DS written by 1990s software, and it is why the format forms a tree rather than a flat record list. All multi-byte values are little-endian.

The chunk hierarchy: MAIN3DS, EDIT3DS and KEYF3DS

The chunks nest into a fixed hierarchy. The whole file is wrapped in the primary chunk MAIN3DS (ID 0x4D4D), which is why every 3DS file begins with the bytes 4D 4D. Inside it sit a version chunk, the 3D editor chunk that holds all the scene data, and optionally the keyframer chunk that holds animation.

0x4D4D  MAIN3DS            primary chunk (whole file)
 ├─ 0x0002  M3D_VERSION    file version integer
 ├─ 0x3D3D  EDIT3DS        the 3D editor: all meshes, materials, lights
 │   ├─ 0xAFFF  MAT_ENTRY  a material definition
 │   └─ 0x4000  EDIT_OBJECT  a named object
 │       ├─ 0x4100  OBJ_TRIMESH   triangle mesh
 │       │   ├─ 0x4110  POINT_ARRAY   vertex list
 │       │   ├─ 0x4120  FACE_ARRAY    face (triangle) list
 │       │   ├─ 0x4140  TEX_VERTS     UV coordinates
 │       │   └─ 0x4160  MESH_MATRIX   local transform
 │       ├─ 0x4600  N_DIRECT_LIGHT  a light
 │       └─ 0x4700  N_CAMERA        a camera
 └─ 0xB000  KEYF3DS        keyframe animation data

The EDIT3DS chunk (0x3D3D) is the heart of the file: it contains one EDIT_OBJECT (0x4000) per named object, plus the material definitions. The KEYF3DS chunk (0xB000) is separate and holds the animation track, so a static mesh file simply omits it. This separation is why a 3DS with no animation is smaller and why a viewer that ignores 0xB000 still shows the geometry correctly.

Inside a mesh: vertices, faces and UVs

A single mesh lives in an OBJ_TRIMESH chunk (0x4100) built from parallel arrays. POINT_ARRAY (0x4110) starts with a 16-bit vertex count, then that many triples of 32-bit floats giving the X, Y, Z of each vertex. FACE_ARRAY (0x4120) starts with a 16-bit face count, then that many faces, each four 16-bit values: three vertex indices plus a face-info flag holding edge-visibility bits.

TEX_VERTS (0x4140) supplies one UV coordinate pair per vertex for texture mapping, and MESH_MATRIX (0x4160) stores the object's local-to-world transform as a 4×3 matrix. A crucial detail: the 3DS format does not store per-vertex or per-face normals. A reader must compute them from the face winding, which is exactly why old 3DS models so often display with black or inside-out faces — the normals are reconstructed, and any inconsistency in the original winding shows up as flipped shading.

Material definitions and texture maps

Materials are defined once in MAT_ENTRY chunks (0xAFFF) under the editor chunk and referenced by name from each mesh. A material entry holds a name string (the ten-character limit applies here), ambient, diffuse, and specular colour chunks, a shininess value, and optional texture-map chunks (0xA200 for the diffuse map) that name an external image file. Because the texture is referenced by filename rather than embedded, a 3DS shared without its accompanying image files loads with the geometry and colours but missing textures — a frequent surprise when opening a downloaded asset.

3DS versus MAX: why you cannot recover a scene

It is tempting to treat .3ds and .max as two spellings of the same thing, but they are fundamentally different. A .3ds is a flat, baked mesh: the geometry as triangles, with basic materials. A .max is the full 3ds Max scene, storing modifier stacks, construction history, parametric objects, scene settings, and editor state that a mesh never contained. 3ds Max can import a .3ds and then Save As a .max, but that only wraps the imported triangles in a new scene; the original authoring history cannot be reconstructed from a format that never held it. For modern engines, exporting to FBX (which carries meshes, materials, rigs, and animation) or OBJ (a simple universal mesh) is the usual path.

Is your .3ds a model or a Nintendo 3DS game?

The same extension is used, coincidentally, for dumped Nintendo 3DS game cartridges. The two are entirely unrelated. A 3D-model .3ds from an asset library is usually a few hundred kilobytes and begins with the bytes 4D 4D; it opens in Blender or MeshLab. A game ROM is typically hundreds of megabytes and runs only in a Nintendo 3DS emulator, not in any 3D modeller. The file size and origin tell them apart immediately, and nothing in this page's mesh tooling applies to the game file.

References