SKP File Format Reference¶
This document describes the modern ZIP/VFF .skp format emitted by SketchUp
2021 and later in the observed save-version matrix. For the earlier CArchive format, see
Old Binary Format.
The authoritative machine-readable tag map is in ../skp_tags.yaml.
Container Layout¶
An .skp file is a ZIP archive preceded by a text header:
+-------+
| Text Header (UTF-16-like bytes) |
| - "SketchUp Model" |
| - Version string "{major.minor.build}" |
+-------+
| ZIP Archive |
| +- model.dat (required) |
| +- meta/meta.dat (optional) |
| +- styles/*/style.xml |
| \- materials/*/ |
| +- material.xml |
| \- <texture files> |
\-------+
Text Header¶
Begins with a UTF-16LE-prefixed product string (
"SketchUp Model").Followed by a version string like
"{21.0.0}".The ZIP payload starts at the first
PK\x03\x04signature.
ZIP Entries¶
Entry |
Required |
Description |
|---|---|---|
|
Yes |
Binary TLV stream containing the model graph |
|
No |
Model metadata |
|
No |
Visual style definitions |
|
No |
Material definitions (XML) |
|
No |
Texture image files |
model.dat is typically stored with deflate compression (method = 8).
model.dat - TLV Encoding¶
model.dat is a binary Tag-Length-Value (TLV) stream. Records are nested
recursively.
Record Layout¶
+--+--+----+
| tag | length | payload |
| u16 LE | u32 LE | length bytes |
\--+--+----+
tag (
u16little-endian): Identifies the record type.length (
u32little-endian): Byte count of the payload.payload: Either raw data or nested TLV children.
Top-Level Structure¶
The file always begins with a single root record:
Tag |
Name |
Description |
|---|---|---|
|
|
Root container for the entire model |
Primitive Payload Conventions¶
Payload Size |
Typical Type |
Examples |
|---|---|---|
1 byte |
Boolean / byte flag |
|
4 bytes |
|
IDs, enums, bitmasks |
8 bytes |
|
Distances, angles, scales |
16 bytes |
2 x |
UV coordinates |
24 bytes |
3 x |
Points, vectors, axes (xyz) |
32 bytes |
4 x |
Plane equation (abcd) |
48 bytes |
6 x |
Bounding box (min/max triplets) |
72 bytes |
9 x |
3x3 projection matrix |
104 bytes |
13 x |
Transform (see below) |
Variable-Length Integers¶
Many IDs, counters, and references are stored as compact little-endian
integers (1-4 bytes depending on value range). A value like 6 may occupy
a single byte, while larger values use 2, 3, or 4 bytes.
ID Encoding¶
IDs are commonly wrapped in a two-level structure:
0x05DC (id_wrapper)
\- 0x05DE (id_value) -> compact little-endian integer
Some records use an extended payload form:
0x05DC (id_wrapper)
+- 0x05DD (id_extended_payload) -> nested TLV blob
\- 0x05DE (id_value) -> compact little-endian integer
Root Tag Map (0x01F4 Children)¶
The root record contains these top-level blocks:
Tag |
Name |
Description |
|---|---|---|
|
|
Legacy version marker (u32, observed 0) |
|
|
ID counter seed |
|
|
Root-level entities (vertices, edges, faces, instances, etc.) |
|
|
Material definitions |
|
|
Layers and layer folders |
|
|
Component definitions |
|
|
Model camera snapshot |
|
|
Rendering/display options |
|
|
Sketch axes / coordinate system |
|
|
Font definitions |
|
|
Text style defaults |
|
|
Dimension style defaults |
|
|
Named options providers |
|
|
Watermark definitions |
|
|
Shadow/geo-reference settings |
|
|
Active schema zip-file references |
|
|
Visual styles registry |
|
|
Saved scenes/pages |
|
|
Custom line styles |
|
|
Attribute dictionaries |
|
|
Path to |
|
|
Mipmap usage flag |
|
|
Section plane naming counter |
|
|
Default component behaviors |
|
|
Default image reference |
|
|
Environment/lighting data |
|
|
Sun data |
|
|
Migration flag |
Entities (0x01F6)¶
The entities block (0x1388) contains all geometric and non-geometric objects
in the model.
Entity Sub-Blocks¶
Tag |
Name |
Description |
|---|---|---|
|
|
Vertex positions |
|
|
Edge connectivity |
|
|
Face geometry with loops |
|
|
Component instance placements |
|
|
Group instances |
|
|
Drawing element references |
|
|
Image entities |
|
|
Construction guide lines |
|
|
Construction guide points |
|
|
Section plane entities |
|
|
Active section plane reference |
|
|
Polyline curves |
|
|
Arc curves |
|
|
Dimension entities |
|
|
Entity metadata |
|
|
Opening entities |
|
|
Sentinel marker |
|
|
Component state bitfield |
|
|
Bounding box for definition entities |
Vertices¶
Each vertex record (0x09C4) contains:
Tag |
Payload |
Description |
|---|---|---|
|
compact int |
Vertex ID |
|
3 x f64 |
Position (x, y, z) in inches |
Edges¶
Each edge record (0x0BB8) contains:
Tag |
Payload |
Description |
|---|---|---|
|
nested |
Entity base (IDs, flags) |
|
compact int |
Start vertex ID |
|
compact int |
End vertex ID |
|
compact int |
Optional curve ID |
The entity base can include 0x07D1 for a material reference, 0x07D2 for
the owning layer/tag, and 0x07D3 for the compact integer edge flag bitfield.
Raw modern bits are 0x01 hidden, 0x02 casts shadows, 0x04 receives
shadows, 0x08 soft, and 0x10 smooth. Public Edge.flags normalizes the
three edge properties to 0x01, 0x02, and 0x04 respectively.
See Edge Shading Flags for how these flags map to importer
normal smoothing.
Faces¶
Each face record (0x0DAC) contains:
Tag |
Payload |
Description |
|---|---|---|
|
nested |
Entity base (ID, front material, layer/tag, flags) |
|
4 x f64 |
Plane equation (a, b, c, d) |
|
nested |
Loop container |
|
compact int |
Back-material ID |
Loops (0x0DAE) contain repeated loop records (0x1194), each with edge-use
entries (0x1195 -> 0x0FA0):
Tag |
Payload |
Description |
|---|---|---|
|
compact int |
Edge ID |
|
bool |
Reversed flag |
Hole faces are represented as multiple loop records within the same face.
Component Instances, Groups, and Images¶
All three share a common 0x1964 instance record structure:
Tag |
Payload |
Description |
|---|---|---|
|
nested |
Entity base |
|
UTF-8 string |
Name (optional) |
|
13 x f64 |
Transform matrix |
|
compact int |
Definition ID |
|
16 bytes |
GUID-like blob |
Transform encoding (0x1966): 13 doubles in SketchUp SUTransformation
storage order:
[m00, m01, m02, m10, m11, m12, m20, m21, m22, tx, ty, tz, w]
To reconstruct a row-major 4x4 matrix:
matrix = [
[m00, m01, m02, tx],
[m10, m11, m12, ty],
[m20, m21, m22, tz],
[0.0, 0.0, 0.0, w],
]
Component instance:
0x138C->0x1964Group:
0x138D->0x1D4C-> nested0x1964Image:
0x1390->0x1F40-> nested0x1964
Curves¶
Tag |
Name |
Description |
|---|---|---|
|
|
Container -> |
|
|
Number of edges in curve |
|
|
Polygon flag |
|
|
First edge ID |
|
|
Last edge ID |
Arc Curves¶
0x1397 -> 0x4C2C contains a nested 0x4A38 curve record plus arc-specific
payload 0x4C2D. The payload is 16 little-endian float64 values: center (3),
unit normal (3), plane distance (1), radius-scaled X axis (3), radius-scaled Y
axis (3), radius (1), start angle (1), and end angle (1). Curve and arc-curve
sections precede EDGES; the public SDK rejects an edge-to-curve reference when
the owning curve section is serialized afterward.
Section Planes¶
0x1393 -> 0x445C with plane (0x445D), name (0x445E), and symbol
(0x445F).
Construction Guides¶
Guide lines use 0x1391 -> 0x4269. Their 0x4268 field contains a nested
entity base, 0x426A stores a point, a unit direction, and two parameter
bounds as eight doubles, and 0x426B stores a u16 stipple pattern. Infinite
lines use bounds -1e30 and +1e30.
Guide points use 0x1392 -> 0x426C, with the same nested construction/entity
base, position 0x426D, optional reference position 0x426E, and its enable
flag 0x426F. Construction and section entities carry layer ownership in the
entity-base 0x07D2 field.
Dimensions¶
Linear dimensions use 0x1399 -> 0x5BCC with base data (0x59D8) and
anchor records (0x5BCD, 0x5BCE). Each anchor contains a 0x5208 point
reference: kind 0x5209, position 0x520A, and primary/secondary association
wrappers 0x520B/0x520C. An association wrapper 0x53FC contains an
optional leaf entity ID 0x53FD and a width-prefixed outer-to-inner instance
path in 0x53FE.
These records map to the same public LinearDimension and PointReference
classes used for legacy files. The parser retains text, font reference, 3-D
text and arrow settings, anchors, direction vectors, mode, offset, alignment,
and dimension-line position.
Radial dimensions use 0x139A -> 0x5DC0, with the same common dimension
base, associated target ID 0x5DC1, curve parameter 0x5DC3, radius ratio
0x5DC4, and diameter boolean 0x5DC5. Modern writer conformance covers the
associated form. The parser also retains historical inline arc payloads in
0x5DC2; no accepted modern writer representation for orphaned arcs has been
confirmed.
Openings¶
0x139D -> repeated 0x7530 records with origin, axes, and flags.
Materials (0x01F7)¶
Binary structure:
0x01F7 -> 0x30D4 -> 0x30D5 -> repeated 0x32C8 (material records)
Each material record (0x32C8) contains:
Tag |
Payload |
Description |
|---|---|---|
|
bool |
Record context: global ( |
|
blob |
Texture payload |
|
UTF-8 string |
Material name |
|
compact int |
Optional auxiliary value; semantics unconfirmed |
0x30D6 holds the current/active material reference.
Texture, opacity, color, and PBR appearance come from the optional material XML. When that resource is absent or invalid, the parser retains TLV identity/name and uses neutral appearance defaults.
Material XML¶
Rich material data is stored in materials/<name>/material.xml inside the ZIP:
<mat:material name="Brick" type="..." workflow="..."
colorRed="180" colorGreen="80" colorBlue="60"
trans="0" useTrans="0" hasTexture="1">
<mat:texture textureFilename="brick.jpg" xScale="100" yScale="100">
<mat:image path="..." file_name="brick.jpg"/>
</mat:texture>
<mat:pbrMR enable_metalness="0" enable_roughness="1"
roughnessFactor="0.5" .../>
</mat:material>
Layers (0x01F8)¶
0x01F8 -> 0x3A98
+- 0x3A99: layer list -> repeated 0x3C8C
+- 0x3A9A: active layer ID
\- 0x3A9B: folder tree -> anonymous 0x3E80 root -> public 0x3E80 nodes
Layer record (0x3C8C):
Tag |
Payload |
Description |
|---|---|---|
|
nested |
ID wrapper |
|
UTF-8 string |
Layer name |
|
bool |
Visible flag |
|
nested |
Inline |
|
bitmask |
Scene behavior flags |
|
compact int |
Custom line style reference |
Folder nodes (0x3E80) can nest through 0x3E83. Their 0x3E84 membership
payload is a packed sequence: each layer ID is preceded by a one-byte width
(1-4), followed by the little-endian ID bytes.
Component Definitions (0x01F9)¶
0x01F9 -> 0x1770 -> 0x1771 -> repeated 0x157C
Definition record (0x157C):
Tag |
Payload |
Description |
|---|---|---|
|
nested |
Definition base (contains ID) |
|
nested |
Definition-local entities |
|
16 bytes |
GUID blob |
|
UTF-8 string |
Name |
|
UTF-8 string |
Description |
|
UTF-8 string |
Loaded-from path |
|
compact int |
Timestamp |
|
bool |
Modified flag |
|
compact int |
Definition type |
|
nested |
Packed payload (thumbnail, etc.) |
|
nested |
Component behavior defaults |
The instance-to-definition join uses 0x1967 (instance) matching the
definition ID inside 0x157C -> 0x07D0 -> 0x05DC -> 0x05DE.
Camera (0x01FA)¶
0x01FA -> 0x34BC
Tag |
Payload |
Description |
|---|---|---|
|
3 x f64 |
Eye position |
|
3 x f64 |
Target position |
|
3 x f64 |
Up vector |
|
f64 |
Near clipping distance |
|
f64 |
Far clipping distance |
|
bool |
Perspective flag |
|
f64 |
Orthographic height |
|
f64 |
Perspective FOV |
|
f64 |
Aspect ratio |
|
bool |
FOV-is-height flag |
|
bool |
Legacy camera flag |
|
UTF-8 string |
Description |
|
f64 |
Image width |
|
bool |
2D camera flag |
|
f64 |
2D scale |
|
f64 |
2D center X |
|
f64 |
2D center Y |
|
bool |
Allow clipping in parallel projection |
Rendering Options (0x01FB)¶
0x01FB -> 0x733C
Contains ~50+ fields controlling display: render mode, transparency, edge display, colors (background, foreground, highlight, face front/back, fog, sky, ground, section cuts), fog settings, ambient occlusion, photomatch, and legacy compatibility flags.
Section display record 0x7375 is a bitmask shared with legacy rendering
options. Bit 0x1 controls section-plane visibility and bit 0x2 controls
section-cut visibility. The public model exposes these as
display_section_planes and display_section_cuts while preserving the raw
section_display_mode value.
Scenes (0x0207)¶
0x0207 -> 0x6D60 -> 0x6D61 -> repeated 0x7148
Each scene record contains:
Tag |
Description |
|---|---|
|
Base scene (ID, name, description) |
|
Flags |
|
Camera snapshot |
|
Hidden entity IDs |
|
Style reference |
|
Rendering options snapshot |
|
Shadow info snapshot |
|
Axes snapshot |
|
Hidden layer IDs |
|
Active section plane IDs |
|
Show in slideshow |
|
Transition/delay overrides |
|
Background image reference |
|
Thumbnail image |
|
Hidden layer folder IDs |
|
Environment reference/settings |
|
Foreground image IDs |
The ID stored in the base scene is preserved. Camera snapshots are decoded to
the same public Camera class used by model-level cameras. Collections such as
hidden entities, hidden layers, and active section planes use repeated scalar
TLV records; each repeated record contributes one public reference ID.
Shadow Info / Geo-Reference (0x0204)¶
0x0204 -> 0x6590
Tag |
Payload |
Description |
|---|---|---|
|
compact int |
Time |
|
bool |
Daylight savings |
|
raw |
City name |
|
compact int |
Country |
|
f64 |
Longitude (degrees) |
|
f64 |
Latitude (degrees) |
|
f64 |
Timezone offset |
|
3 x f64 |
North direction |
|
various |
Display flags, light/dark settings |
Attribute Dictionaries (0x0209)¶
0x0209 -> 0x36B1 -> 0x36B2 (dictionary records)
Each dictionary contains:
Tag |
Description |
|---|---|
|
Dictionary name |
|
Entries -> |
Typed values (0x38A4) carry a type code (0x38A7) and one of:
0x38A8: int32 payload0x38A9: f64 payload0x38AA: bool payload0x38AD: string payload0x38AE: nested blob
The same dictionary root can appear inside an entity’s 0x05DD extended ID
payload. Named records are exposed through
Entities.attribute_dictionaries_by_entity_id; definition, material, and layer
records use Model.attribute_dictionaries_by_object_id. Technical records in
that root, including texture projections, are handled separately and do not
become empty named dictionaries.
Texture projection data is also stored in attribute dictionaries; see UV Projection.
Physical Units¶
Geometric lengths: stored in SketchUp internal units (inches).
Lat/long: degrees (f64).
Camera FOV/legacy scalar: radians.
Colors: 4-byte packed ARGB (u32, little-endian).
Timestamps: compact integer (epoch-like semantics).
Parser Gotchas¶
Not all payloads are nested TLV. Fixed-size numeric blobs (24, 32, 104 bytes) can accidentally look like valid tags if decoded heuristically.
Pseudo-tags like
0x0000and some0x40xxvalues may appear from raw f64 geometry payload bytes - always parse based on known tag semantics.Variable-length IDs must be supported (not fixed u32 only).
Legacy (non-ZIP) SKP files cannot be read through the
model.datZIP extraction path.
Tag Coverage¶
The tag map in ../skp_tags.yaml covers:
422 mapped tags
298 leaf tags with explicit payload/type annotations
124 container-only tags (no payload type)
Inference basis: analysis of observed .skp files with cross-check against
record lengths and value distributions.