Runtime Format
The Rive editor exports your project as a .riv file for consumption by the Rive runtimes. This is a binary representation of your Artboards, Shapes, Animations, State Machines, etc. This is the file that Rive’s runtimes read to display your content in an application, game, website, etc. The format was designed to provide a balance of quick load times, small file sizes, and flexibility with regards to future changes/addition of features.Binary Types
A binary reader for Rive runtime files needs to be able to read these data types from the stream.Byte order is little endian.
Header
The header is the first thing written into the file and provides basic information for the runtime to verify that it can read this file. A ToC (table of contents/field definition) is provided which allows the runtime to understand how it can skip over properties and objects it may not understand. This is part of what makes the format resilient to future changes/feature additions to the editor. An older runtime can at least attempt to load an older file and display it without the objects and properties it doesn’t understand.
Fingerprint
The file fingerprint just lets the importer quickly sanity check that it’s actually looking at a file exported by Rive. This is 4 bytes representing the utf8/ascii “RIVE”. In a hex editor this looks like.
0x52 0x49 0x56 0x45/“RIVE”
- if you update to runtimes that support a new major format, you must re-export files to that major format
- if you stay on older runtimes, you must export files in the older compatible major format
- runtimes that add support for a new file format major version will also ship a major runtime version update
11, and support for a new file format major is introduced, Android runtime support for that format will ship in a major 12 release.
To adopt it, you update to Android runtime 12 and re-export files to the new file format major.
If you need to verify a file’s format version programmatically, read the Major Version and Minor Version values from the file header. Rive runtimes also surface a descriptive import error when the file format is incompatible.
Major versions are not cross-compatible. For example, a runtime that supports format version 6 cannot read format version 7 files, and vice versa.
Whenever a new major file format version is introduced, a corresponding major release is issued for all supported runtimes.
When a file uses newer features that an older compatible runtime does not support, the file still loads and supported features continue to work. Unsupported features are treated as no-ops. Rive runtimes are designed to avoid crashes or undefined behavior for this compatibility scenario.
File ID
This is a unique identifier for the file that in the future will be able to be used to distinguish the file by our API. The API isn’t defined yet, but some of the planned features include re-exporting a newer version of the file on demand, getting details of the file, etc. For now this can be used to verify which file this export was generated from.ToC
The Table of Contents section of the header is a list of the properties in the file along with their backing type. This allows the runtime to read past properties it wishes to skip or doesn’t understand. It does this by providing the backing type for each property ID.Field Types
There are 5 fundamental backing types but they are serialized in 4 different ways. Knowing how the type is serialized allows the runtime to know how to read it in. Even if it reads the wrong value or interprets it incorrectly, the important aspect is being able to read past it so the rest of the file can be read in safely. For example, a boolean can be read as an unsigned integer as the backing type and serializer is compatible. Even though reading the boolean as an integer will not provide the valid value for the property, the runtime can still just read past it.ToC Data
The list of known properties is serialized as a sequence of variable unsigned integers with a 0 terminator. A valid property key is distinguished by a non-zero unsigned integer id/key. Following the properties is a bit array which is composed of the read property count / 4 bytes. Every property gets 2 bits to define which backing type deserializer can be used to read past it.The intention here is to provide the known property type keys and their backing type, such that if the property type is unknown, the reader can read the entirety of the value without under/over running the buffer.
As an example, if there were a file with three known property types (property 12 a uint value, property 16 a string value, and 6 a bool value) the exporter would serialize data as follows:
varuint: 12
varuint: 16
varuint: 6
varuint: 0
2 bits: 0
2 bits: 1
2 bits: 0