The Tauric save format

A .tauric file is a protobuf message. These are the schema files it is written against — the same ones the editor compiles, read straight from the repository rather than copied, so this page cannot drift from what the code does.

Protobuf was chosen to keep files compact. A map is mostly repetition — thousands of tile references, thousands of points — and protobuf writes those as packed numbers against integer tags instead of spelling out a key for every one of them. Measured on the map this editor opens with, the protobuf file is about a quarter the size of the same map as Tiled JSON with its tileset beside it.

Being straight about the limit of that: over a connection that compresses, the gap all but disappears — JSON's repetition is exactly what a compressor eats, and the same two files gzip to within a few percent of each other. The saving is real on disk, in memory, and in not parsing text; it is not a bandwidth argument.

What it costs is readability — this is the one format here you cannot open in a text editor, which is a large part of why this page exists.

Two pages of the specification cover most of what a reader needs: the proto3 language guide for what the schema below means, and the encoding reference for the bytes themselves — the second is the one to read if you are writing a parser rather than generating one.

The schema is MIT licensed. Compile it, vendor it, ship a reader or a writer — no permission needed, and the licence travels inside the file you download. That covers the schema text, not the editor.

What we can't promise is that a fork of it still interoperates. Add a field, renumber one, widen a type, and you have a dialect that shares a package name — and because protobuf skips tags it doesn't recognise instead of complaining, the divergence shows up as quietly missing data rather than an error. Unmodified, this schema round- trips. If you need something it doesn't carry, ask and it gets a field number everyone agrees on.

Field numbers are append-only. A number that has been used is never reused or renumbered: readers skip tags they don't know, which is what lets an old file open in a new build. Each message below lists the next free number.

package tauric.map.v1
common.proto2 messages

Copyright (c) 2026 Gnarled Helix LLC. All rights reserved. Shared primitives for the Tauric native format.

Vec2next free number 3
1doublex
2doubley
Propertynext free number 6

Strongly-typed simple property metadata (map-, layer-, and tile-level). Richer foreign values (Tiled class/list properties) are not representable and are dropped at save time with a warning.

1stringname
2PropertyTypetype
3boolboolean_value
4doublenumber_value
5stringstring_value

oneof value: boolean_value, number_value, string_value — at most one is set.

enum ImageFormat

0 IMAGE_FORMAT_UNSPECIFIED 1 IMAGE_FORMAT_PNG

enum PropertyType

0 PROPERTY_TYPE_UNSPECIFIED 1 PROPERTY_TYPE_BOOLEAN 2 PROPERTY_TYPE_NUMBER 3 PROPERTY_TYPE_STRING

map.proto18 messages21 internal fields not shown

Copyright (c) 2026 Gnarled Helix LLC. All rights reserved. The Tauric native map format: the lossless serialization of a map document. A .tauric file is one MapFile message, encoded binary. Tileset definitions and packed tile placements live in tiles.proto; shared primitives in common.proto. Tiled's own file formats are never embedded — the feature set this editor uses is replicated as typed messages. Field numbers are append-only. The schema still gains fields between releases, so a reader should skip tags it does not recognize rather than treat them as an error.

EdgePayloadnext free number 4

A line between two points, optionally bent. LEGACY: nothing writes this any more — a two-point polyline with an arc segment says the same thing — but it stays in the schema permanently and a reader must still handle it, because files written before the change keep opening.

1Vec2start
2Vec2end
3optional doublecurvature
StraightSegmentnext free number 1

A straight span. Present as an explicit case so one span can be straight in an array whose others bend; an ABSENT segment means the same thing.

ArcSegmentnext free number 2

A true circular arc: the subtended angle in degrees, positive bulging left of start→end in y-down pixel space. The same quantity DXF encodes as a per-vertex bulge, tan(θ/4).

1doublecurvature
BezierSegmentnext free number 3

A cubic Bézier. Handles are stored RELATIVE to their own span's endpoints — control1 from the span's start point, control2 from its end.

1Vec2control1
2Vec2control2
ShapeSegmentnext free number 4

How one span between consecutive shape points is drawn.

1StraightSegmentstraight
2ArcSegmentarc
3BezierSegmentbezier

oneof kind: straight, arc, bezier — at most one is set.

CommentPayloadnext free number 2
1stringtext
TextPayloadnext free number 7

A text label placed as map content. Distinct from a comment: comments are editor annotation and are stripped from every export, whereas a label is part of the map and travels with it.

1stringtext
2optional doublefont_sizePer-label overrides of the type's text graphic. Unset means the type decides.
3optional stringfont_family
4optional stringcolor
5optional stringoutline_color
6optional doubleoutline_width
PointListnext free number 2
1repeated Vec2points
EntityPlacementnext free number 20
1stringid
2stringtype_id
3doubletile_xTile coords, Y-down; fractional after fine drags
4doubletile_y
5optional doublewidthPixel overrides; absent = type defaultSize
6optional doubleheight
7optional doubleangleDegrees, clockwise
8optional google.protobuf.Structproperties
9EdgePayloadedge
10CommentPayloadcomment
18TextPayloadtext
11PointListpolyline
12PointListpolygon
19repeated ShapeSegmentsegmentsOne per span between consecutive shape points, parallel to whichever shape case is set (a polygon's last span wraps back to its first point). Empty, short, or all-straight all mean the same thing: straight spans.

oneof payload: edge, comment, text — at most one is set.

oneof shape: polyline, polygon — at most one is set.

TileLayernext free number 14
1stringid
2stringname
3boolvisible
4doubleopacity
5optional doubleparallax_x
6optional doubleparallax_y
7optional stringtint_color
8optional doubleoffset_x
9optional doubleoffset_y
10repeated Propertyproperties
11TileLayerTilestiles
12optional stringparent_id
13optional boollockedDrawn, but not touchable in the viewport. Absent means unlocked.
EntityLayernext free number 9
1stringid
2stringname
3boolvisible
4optional doubleopacity
5repeated Propertyproperties
6repeated EntityPlacemententities
7optional stringparent_id
8optional boollocked
ImageLayernext free number 17
1stringid
2stringname
3boolvisible
4stringimage_path
5stringimage_name
6optional stringimage_url
7doubleoffset_x
8doubleoffset_y
9doubleopacity
10optional doubleparallax_x
11optional doubleparallax_y
12optional boolrepeat_x
13optional boolrepeat_y
14repeated Propertyproperties
15optional stringparent_id
16optional boollocked
GroupLayernext free number 11

A folder of other layers. Holds no content; its visibility, opacity and offset apply to everything inside it. Membership is by the CHILD's parent_id rather than a list of children here.

1stringid
2stringname
3boolvisible
4optional doubleopacity
5optional doubleoffset_x
6optional doubleoffset_y
7optional boolcollapsed
8repeated Propertyproperties
9optional stringparent_id
10optional boollocked
Layernext free number 6
1TileLayertile
2EntityLayerentity
3ImageLayerimage
5GroupLayergroup

oneof kind: tile, entity, image, group — at most one is set.

TilesetEntrynext free number 3

One entry per tileset the map references. Order matters: packed tile cells index into this list. `definition` is absent for tilesets the session had no definition for (their source paths ride in unknown_tileset_sources).

1stringname
2optional TilesetDefinitiondefinition
EmbeddedAssetnext free number 4

One image asset the map's entity types draw from, as stored (a PNG, or a .prs sheet with its sprite layout inside it).

1stringid
2stringname
3bytesdata
EmbeddedProjectnext free number 3

A copy of the project state this map needs, so the file can be opened somewhere that has never seen the project it came from. Without it a .tauric is only meaningful next to its project: placements carry a type_id, and the definition behind that id — its graphic, its category kind, the image it draws — lives in the project.

1google.protobuf.StructconfigProjectConfig verbatim: categories, entity types, tile size, real-world scale. A Struct rather than a typed mirror, so a reader does not drop whatever the writing version knew and it did not.
2repeated EmbeddedAssetassetsOnly the assets the map's types actually reference, not the whole project's art library.
MapFilenext free number 13
1uint32format_version1
2stringmap_name
3stringbackground_color
4optional stringmap_uuid
5repeated Layerlayers
6repeated TilesetEntrytilesets
7repeated Propertymap_properties
11optional EmbeddedProjectprojectAbsent in files written before self-contained saves, and in exports that deliberately omit it.
12optional booltiled_infiniteFalse for a fixed-size (finite) Tiled map. Absent means infinite.
tiles.proto7 messages

Copyright (c) 2026 Gnarled Helix LLC. All rights reserved. Tile-related messages for the Tauric native format: typed tileset definitions replicating the subset of Tiled's .tsj feature set Tauric uses (no raw Tiled JSON embeds), and a compact chunked encoding for tile placements (no per-cell tileset names).

ImageRefnext free number 7
1stringsourceOriginal image filename/path, kept so exports reference the same file.
2uint32width
3uint32height
4bytesimage_bytesEmbedded image (self-contained save)
5stringimage_refURL/path reference (session-scoped)
6ImageFormatformatEncoding of image_bytes; always set (PNG) when bytes are embedded. UNSPECIFIED for references, whose format is the referenced resource's.

oneof data: image_bytes, image_ref — at most one is set.

AnimationFramenext free number 3
1uint32tile_idLocal tile id within the same tileset
2uint32duration_ms
CollisionShapenext free number 8

One collision shape from a tile's Tiled objectgroup: a rect unless `polygon` is set (polygon points are relative to x/y, in pixels).

1doublex
2doubley
3doublewidth
4doubleheight
5repeated Vec2polygon
6optional doublerotation
7optional stringshape_classTiled object `class`/`type`
TileDefinitionnext free number 8

Per-tile data. Entries are sparse — only tiles that carry any of this are stored, keyed by their sheet position (never a dense array with empty items). The linear tile id is derived: row * columns + column.

2optional stringtile_classTiled `class`/`type` (e.g. "ground")
3repeated AnimationFrameanimation
4repeated CollisionShapecollision
5repeated Propertyproperties
6uint32row
7uint32column
TilesetDefinitionnext free number 10
1stringname
2uint32tile_width
3uint32tile_height
4uint32columns
5uint32tile_count
6uint32margin
7uint32spacing
8ImageRefimage
9repeated TileDefinitiontiles
TileChunknext free number 4
1sint32xChunk origin in tile coords (multiple of chunk_size)
2sint32y
3repeated uint32cellsRow-major, chunk_size² entries
TileLayerTilesnext free number 3
1uint32chunk_size16
2repeated TileChunkchunks

The collaboration protocol — how peers and the relay talk to each other — is a separate schema and is not published here.