I've been writing a native interface design tool in Rust, and the part that taught me the most was the file format, so I wanted to share a few notes in case they help anyone parsing a binary format they don't control.
A .fig file is usually a ZIP holding canvas.fig, meta.json and an images/ folder. Some files skip the ZIP. canvas.fig starts with the bytes fig-kiwi and a little-endian u32 version (I write 106), followed by compressed chunks: first a Kiwi schema, then a message encoded with that schema. Chunks can be DEFLATE or Zstd, so the reader has to handle both. You can see the header yourself with unzip -p file.fig canvas.fig | head -c 12 | xxd.
Three things I'd do again:
-
Let the embedded schema drive the decoder. I don't hardcode the node layout. The decoder reads the schema from the file and produces a generic value tree, so new fields show up as data instead of breaking the parser.
-
Treat every file as hostile. My reader caps each inflated chunk at 2 GiB and a whole archive at 4 GiB, rejects compression ratios above 100:1 once output passes 16 MiB, and streams in 64 KiB pieces so a bad file never allocates gigabytes up front. It also caps decoded values per message. I sized that cap from a real 31-page file with about a million node records, which decoded to roughly 55 million values.
-
Keep a test that compares the writer's table of keys to the schema. If the schema gains a key my table doesn't name, or the table names a key the schema doesn't have, the test fails. That way a field can't quietly fall out of the writer.
The thing I haven't solved yet is issue #834. When writing, numbered-list formatting is dropped, and inherited or variable-bound paints on component instances are written as fixed values. If you've resolved inherited values while serializing back into a schema like this, I'd really like to hear how you approached it.
The project is DESIGN:OS Studio. It's FREE, source-available under PolyForm Shield, and has no affiliation with Figma. The parser lives in crates/designos-fig: GitHub - jangtrinh/design-os-studio: Native, GPU-accelerated interface design tool built in Rust. Opens and saves .fig files, runs your own coding agent on the open file, ships an MCP server. FREE + source-available (PolyForm Shield). · GitHub
1 post - 1 participant