Portable projects
The .puni.json file: what it contains, how export and import validate it, and how pull and push move a scene between a file and the library.
A portable project is one file that stands on its own: the scene document and every asset it references, with checksums. It is what Export → Project writes, what the command line pulls, and what the library imports.
#The shape
| Field | Holds |
|---|---|
format, version | object-studio-project, 2 |
exportedAt, revision | When, and which saved revision it came from |
document | The scene |
assets | Each asset's bytes in base64, its SHA-256, name and MIME type |
#Export and import
puni scene export --file scene.json --output scene.puni.json --json
puni scene import --file scene.puni.json --output imported.json --json
puni scene validate --file imported.json --jsonExport prunes unused assets and embeds the fonts text modules need. Import checks every record, checksum and reference before writing, and keeps the assets inside the editable file so nothing dangles when the file moves.
A bare document with assets on disk needs --asset-root, a directory mirroring the asset URIs:
puni scene export --file scene.json --asset-root ./assets --output bundle.json --json#Pull and push
puni project pull PROJECT_ID --output scene.puni.json --asset-origin https://storage.example.com --base-url https://puni.design --json
puni project push PROJECT_ID --file scene.puni.json --revision 4 --base-url https://puni.design --jsonPull writes a validated bundle and records the revision it came from. Push names that revision; if the library moved on, the push is refused with PUNI_CONFLICT and nothing changes. Assets upload through direct transfers and are checked by hash before the scene commits.
--asset-origin is the exact storage origin the library redirects asset downloads to. It is an allowlist, not another API.
#Uploaded fonts
For custom text, retain the uploaded font in module.assets with its URI, SHA-256, name and MIME type, and set the text instance's fontAsset to that URI. Keep the author's source and licence in the module's provenance.
project pull includes those original bytes. Local rendering uses the retained bytes through the same text adapter as Studio and shares. It refuses missing or invalid fonts instead of fetching arbitrary URLs or substituting a typeface. Absent fontAsset keeps the built-in fonts.
Use MCP tools to upload a font with upload_asset. The tool accepts TTF, OTF, WOFF and WOFF2 up to 8 MiB, with original base64 and SHA-256.
#Limits
| Limit | Value |
|---|---|
| Scene JSON | 32 MiB |
| One asset | 64 MiB |
| Decoded assets in one file | 200 MiB |
| JSON input to the command line | 280 MiB |
Read Import for what the library does with the file.
Was this useful?