Skip to content
PuniDocs
Open Puni

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

FieldHolds
format, versionobject-studio-project, 2
exportedAt, revisionWhen, and which saved revision it came from
documentThe scene
assetsEach asset's bytes in base64, its SHA-256, name and MIME type

#Export and import

bash
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 --json

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

bash
puni scene export --file scene.json --asset-root ./assets --output bundle.json --json

#Pull and push

bash
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 --json

Pull 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

LimitValue
Scene JSON32 MiB
One asset64 MiB
Decoded assets in one file200 MiB
JSON input to the command line280 MiB

Read Import for what the library does with the file.

Was this useful?