File & Export Formats
How nittygrid saves your work in the browser today, how to back up projects (.ngproj) and recipes (.ngrecipe), and how rendered exports (.ngrender.zip, .ngrender.json, MP4) work.
Before the file types, one important thing: where does your work live while you create?
How Project Persistence Works Today (Browser-Only)
nittygrid has no accounts or cloud storage yet. Everything is saved in your browser, on this device.
- Autosave. Every change (animation nodes, wires, chat history, background alignment) is written to your browser's
localStorage300 ms after your last edit. Matrix setup presets live inIndexedDB. - Tied to this browser. A different browser, a private window, or another computer starts empty. Clearing your site data erases projects you have not downloaded.
- Videos can expire. A video you loaded but did not bake only exists until you close the tab. Click Bake to pixel animation, or download a
.ngprojwhile the tab is open, to keep it.
Two kinds of files
- Editable files (
.ngproj,.ngrecipe). They keep your animations as recipes, so you can open and change them later. Use them for backups, moving computers, or sharing. - Rendered files (
.ngrender.zip,.ngrender.json,.mp4). They contain the finished result as colors per frame, or as a video. Use them to play the animation on hardware or in other software, without nittygrid.
Which file do I need?
.ngproj →The full canvas, matrix setup, background photo, and every node's history in one ZIP.Reuse one animation elsewhere → .ngrecipe →One editable animation with its source matrix and media.Drive LEDs or archive for the long term → .ngrender.zip →Exact colors per LED, timing, the SVG layout, schemas, and a written spec.Share a preview → .mp4 →A normal video in the LED look, optionally on top of your product photo.1. Editable Project Bundles (.ngproj)
Download a project from the Projects overlay to get a .ngproj file. Older .at3proj files still import.
<project-slug>.ngproj (ZIP archive)
├── manifest.json Format ID ("at3proj"), schemaVersion (2), and asset inventory
├── project.json Matrix setup, animation recipes, canvas graph & chat history
├── notes.md Human-readable project summary
├── thumbnail.png|jpg|webp Project preview thumbnail (optional)
├── background/image.png|jpg|webp Aligned product/vehicle background photo (optional)
├── matrix/layout.svg Standalone sanitized SVG hardware layout (when using an SVG matrix)
└── assets/session-1.mp4|webm|... Embedded video/image assets used by animations (optional)Good to know
- No broken links. Temporary browser links (
blob:,data:) are replaced by real files inside the ZIP, referenced like this:{ "__at3AssetRef": "background/image.png", "mimeType": "image/png" } - Canvas and chat are kept (schema v2).
project.jsonstores node positions, theStart→Endwires, and each node's chat and dated versions. Older schema v1 projects import as unconnected nodes, because nittygrid will not guess a playback order. - SVG in both forms.
project.jsonkeeps the complete matrix, including its SVG code.matrix/layout.svgis an identical standalone copy for other SVG tools. Import reads and cleans the JSON copy; changing only the standalone file does not change the project. - Safe import. Every restored SVG is cleaned the same way as an uploaded one. Missing referenced background images, thumbnails, or session media stop import instead of silently losing content.
2. Reusable Recipe Bundles (.ngrecipe)
Export a single animation as a .ngrecipe to reuse it in another project. Older .at3anim files still import.
<animation-slug>.ngrecipe (ZIP archive)
├── manifest.json format: "at3anim", schemaVersion: 1, entry: "animation.json"
├── animation.json Label, timestamp, AgentAnimation recipe & source matrixConfig
├── notes.md
├── preview.png|jpg|webp Still preview when available (optional)
├── matrix/layout.svg Source SVG layout snapshot when saved from an SVG matrix (optional)
└── assets/session-1.* Embedded session media (optional)A recipe stores the generator or render_code, not fixed-size pixels, so most recipes adapt to the new project's width W and height H. If the recipe includes its source matrix (matrixContext: "saved-with-recipe"), nittygrid compares it with your current project on import and warns about differences. It never overwrites your project's matrix.
SVG matrices use the same storage rule as projects: animation.json keeps the SVG code and LED metadata, and matrix/layout.svg is an identical copy for use elsewhere. Import reads the matrix from the JSON. Older recipes with only the JSON copy still import.
3. Rendered RGBA Exports (nittygrid-animation v1.0)
A hardware controller or script should not need to run JavaScript or know nittygrid's generators. It only needs to know which LEDs exist, how fast frames advance, and the color of each LED in each frame. That is exactly what this format contains.
- One color model
Every LED in every frame is 4 bytes:
R, G, B, A, each0–255. Monochrome uses the same layout withR = G = B. Bytes are written exactly as rendered, with no gamma change and no premultiplied alpha (rgba8,srgb,straight). - Two ways to name LEDs
- Regular grid (
layout.type: "grid"): justrows,cols, andorder: "row-major". LED IDs (r0c0,r0c1, ...) are derived from the top-left, so the file stays small. - Irregular or SVG layout (
layout.type: "explicit"): only the real LEDs are listed inlayout.pixels, such as[{ "id": "a", "row": 0, "col": 0 }, ...]. Gaps never create fake black pixels.
- Regular grid (
- Shapes stay in
layout.svgThe JSON holds colors and timing only. Outlines live in the companion
layout.svg, linked bylayout.reference.sha256. - Frames are Base64
Each entry in
frames.datais one full frame in standard RFC 4648 Base64. Its decoded length is alwaysledCount * 4bytes.
What is inside a .ngrender.zip
Unzip it with any tool. The JSON is self-describing, and README.txt and FORMAT.md include a short Python 3 example for reading it.
<name>.ngrender.zip
├── README.txt Plain-text offline decoding guide + short Python 3 teaching example
├── manifest.json Package format ("nittygrid-animation-package" v1.0) & SHA-256 checksums
├── animation.nganim.json The rendered RGBA frames, timing, and LED mapping
├── preview.apng Full-color LED-look animated PNG preview for instant viewing
├── FORMAT.md Bundled offline copy of the v1.0 format specification
├── animation.schema.json JSON Schema for animation.nganim.json
├── manifest.schema.json JSON Schema for manifest.json
├── LICENSE-MIT.txt & LICENSE-CC0.txt Free-license notices for the bundled schemas and specification
└── layout.svg Included for SVG matrices; matches layout.reference.sha256Example: regular 2×2 grid (layout.type: "grid")
Two frames at 20 FPS (50 ms each, 100 ms loop). Each Base64 string decodes to 2 × 2 × 4 = 16 bytes in r0c0, r0c1, r1c0, r1c1 order:
{
"format": "nittygrid-animation",
"version": "1.0",
"meta": {
"name": "Four LEDs",
"exporter": { "name": "nittygrid", "version": "0.10.0-alpha.1" },
"exportedAt": "2026-10-17T10:00:00Z"
},
"layout": {
"type": "grid",
"rows": 2,
"cols": 2,
"order": "row-major"
},
"timing": {
"mode": "fixed",
"fps": 20,
"loop": true
},
"frames": {
"pixelFormat": "rgba8",
"colorSpace": "srgb",
"alphaMode": "straight",
"encoding": "base64",
"data": [
"/wAA/wD/AP8AAP///////w==",
"/////wAA//8A/wD//wAA/w=="
]
}
}Example: irregular or SVG layout (layout.type: "explicit")
Three real LEDs (a, b, c) over two rows, with a gap in the middle of row 0. Each frame decodes to 3 × 4 = 12 bytes. No fake LED is written for the gap:
{
"format": "nittygrid-animation",
"version": "1.0",
"layout": {
"type": "explicit",
"reference": {
"path": "layout.svg",
"sha256": "ede530d5b43f5d15bdde4b7b99af5559a9c753971ae98048db88effbba1a4ba4"
},
"pixels": [
{ "id": "a", "row": 0, "col": 0 },
{ "id": "b", "row": 0, "col": 2 },
{ "id": "c", "row": 1, "col": 1 }
]
},
"timing": {
"mode": "fixed",
"fps": 20,
"loop": true
},
"frames": {
"pixelFormat": "rgba8",
"colorSpace": "srgb",
"alphaMode": "straight",
"encoding": "base64",
"data": [
"/wAA/wD/AP8AAP//",
"/////wAA//8A/wD/"
]
}
}4. MP4 Video Export (.mp4)
The video looks like the studio preview, including round or square LEDs, SVG shapes, and optional monochrome.
On browsers with a supported video encoder, frames are calculated and encoded one at a time with fixed timestamps. A slow export takes longer to finish, but the resulting video's duration still follows the selected FPS. H.264 MP4 is preferred; when only VP9 is available, the download uses .webm. Older browsers use the existing real-time recorder with a limited frame buffer, so timing can vary slightly.
Export memory and cancellation
Portable JSON and ZIP exports process each frame immediately and retain only the actual LEDs' encoded color values. They do not collect a complete rectangular image for every frame. The file data and ZIP/APNG work still need memory.
Use Cancel export to stop a running export. If an export exceeds a resource budget, nittygrid shows a message instead of continuing to allocate larger buffers. Use a shorter clip, fewer frames per second, smaller sampling addresses, or a smaller video output as appropriate.
Limits protect nittygrid's own buffers; they cannot measure or reserve the system's free RAM. Browser/encoder resources and animation-owned state use additional memory, and an exhausted system can still terminate a tab. Rendering and export currently run locally; optional server export is planned.
Technical reference: all formats and limits
Generated from the app's own export code, so it always matches what nittygrid writes and reads. This table is for technicians and AI agents.
| File / Export | Format Identifier | Purpose | Key Rules & Budgets |
|---|---|---|---|
.ngproj (legacy .at3proj) | ZIP archive (at3proj, schema v2; reads v1) | Editable project snapshot: matrix setup, matrix/layout.svg, background alignment, animation recipes, canvas graph (nodes/edges), and per-node chat/version history. | Embedded binary assets under background/, assets/, and thumbnail.* referenced via __at3AssetRef. SVG code stays in the JSON; matrix/layout.svg is a standalone copy. |
.ngrecipe (legacy .at3anim) | ZIP archive (at3anim, schema v1) | Reusable single-animation recipe (animation.json) with source matrixConfig (matrixContext: "saved-with-recipe"), optional matrix/layout.svg snapshot, still thumbnail, and embedded session media. | Compares saved matrix context on import without replacing project settings; media hydrated from __at3AssetRef. SVG code stays in the JSON with an optional standalone copy; still previews use preview.*. |
.ngrender.zip & .ngrender.json (v1.0 spec) | ZIP (nittygrid-animation-package "1.0") + JSON (nittygrid-animation "1.0") | Self-contained rendered RGBA animation for regular grids (grid) and irregular/SVG matrices (explicit LED ID order). | Required ZIP entries: README.txt, animation.nganim.json, preview.apng, FORMAT.md, animation.schema.json, manifest.schema.json, LICENSE-MIT.txt, LICENSE-CC0.txt (+ manifest.json and layout.svg for SVG matrices). Budgets: ≤ 1,000,000 LEDs, ≤ 36,000 frames, ≤ 64 MiB RGBA, ≤ 96 MiB JSON, ≤ 8 MiB SVG, ≤ 128 MiB expanded ZIP. |
.mp4 Video | H.264 / MP4 (video/mp4) | Rendered matrix video in the configured LED look (regular grid or physical SVG shapes). | Fixed-timestamp, frame-by-frame encoding where supported (H.264 MP4 preferred, VP9 WebM fallback); older browsers use a real-time recorder. Video canvases: ≤ 8192 px per side and ≤ 8,294,400 pixels each. Encoded output: ≤ 64 MiB. Optional Include preview image composites the aligned background. |
| Browser export working buffers | Local resource budgets; independent of file format versions | Render/encode one frame before producing more; keep only encoded LED data for portable outputs. | Up to four full-raster render buffers: ≤ 64 MiB combined. Legacy JSON and older-browser video frame retention: ≤ 64 MiB. Final file data, encoder/browser resources and generator-owned state use additional memory; free system RAM cannot be guaranteed. |