Core & Formats
Raw .md

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 localStorage 300 ms after your last edit. Matrix setup presets live in IndexedDB.
  • 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 .ngproj while 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?


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:
    json
    { "__at3AssetRef": "background/image.png", "mimeType": "image/png" }
  • Canvas and chat are kept (schema v2). project.json stores node positions, the Start → End wires, 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.json keeps the complete matrix, including its SVG code. matrix/layout.svg is 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.

  1. One color model

    Every LED in every frame is 4 bytes: R, G, B, A, each 0–255. Monochrome uses the same layout with R = G = B. Bytes are written exactly as rendered, with no gamma change and no premultiplied alpha (rgba8, srgb, straight).

  2. Two ways to name LEDs
    • Regular grid (layout.type: "grid"): just rows, cols, and order: "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 in layout.pixels, such as [{ "id": "a", "row": 0, "col": 0 }, ...]. Gaps never create fake black pixels.
  3. Shapes stay in layout.svg

    The JSON holds colors and timing only. Outlines live in the companion layout.svg, linked by layout.reference.sha256.

  4. Frames are Base64

    Each entry in frames.data is one full frame in standard RFC 4648 Base64. Its decoded length is always ledCount * 4 bytes.

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.sha256

Example: 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:

json
{
  "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:

json
{
  "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 / ExportFormat IdentifierPurposeKey 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 VideoH.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 buffersLocal resource budgets; independent of file format versionsRender/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.