Web64 logo Web64 Documentation Web64 Portable Template Format

Web64 Portable Template Format

A .web64template is a self-contained JSON recipe for creating an ordinary editable Web64 project. It contains questions, complete native project variants, optional literal text substitutions and optional PNG artwork. Format v2 also supports a bounded declarative script for rendering authored text. Format v3 adds native table/matrix generation from template answers and optional inline source directives. It is data, not a plugin: it cannot execute browser code, fetch dependencies or design its own UI.

For a step-by-step introduction in the main manual, see Authoring portable templates.

Authoring and using a template

  1. Develop and save the starting project through the Web64 IDE. Include its native

assets, compiler/memory settings, build targets and disk layout as appropriate.

  1. Choose Project tree → New → New from template... → Export Template to obtain a complete

stock-format example. Replace its metadata and project variants with your own saved native project objects. Each output project should include TEMPLATE.md explaining its architecture, first edit, controls and build/run workflow.

  1. Declare the questions in parameters. Use complete variants for structural

differences and substitutions for literal text. In v3, put conditions, bounded loops and table/matrix calls directly in authored C/ASM, then list those files in inlineSource. The older JSON script blocks remain supported.

  1. Sign in to a free or paid Cloud account and import your .web64template into

My Templates. Exercise every supported answer combination, create a project, save/reopen it and build/run through normal IDE controls. Verify native asset editors and Run Disk if relevant. Schema validation alone does not prove that an example works on a C64.

The current UI imports/exports templates; it is not a graphical template authoring wizard. Editing the declarative recipe is intentional. Do not hand-invent native project/asset internals: use the actual objects saved by Web64. Download the Scripted Template Starter to see a complete v3 file with bounded source generation and a native project with every dependency embedded.

Schema and envelope

Download the v1 schema bundle, v2 schema bundle, or v3 schema bundle. Each contains schema, referencedSchemas, a minimal native-codec example and validation guidance. Register the referenced schemas by $id in a Draft-07 validator before validating against the template schema. $id values are identifiers, not instructions to fetch remote schema code. MCP publishes the same bundle as schemas/web64template/1, schemas/web64template/2 and schemas/web64template/3 respectively. Native semantic validation remains authoritative.

FieldMeaning
kindExactly web64.ide.template
versionFile format version: 1, 2 or 3
manifestTemplate identity, presentation, compatibility and guidance
parametersOptional array of bounded input definitions; absent means none
variantsNonempty array of {when, project} objects
substitutionsOptional array of {parameter, files, separator?} objects
imagesOptional logo and/or screenshot embedded PNG objects
scriptv2/v3: optional versioned blocks that render authored text; v3 adds generate
inlineSourcev3: optional { "version": 1, "files": [...] } that enables directives in authored C/ASM files

Unknown fields, unsupported versions, unsafe paths and invalid native projects reject. V1 remains valid without migration and rejects script and v2-only parameter fields. V2 remains valid and rejects generate. No version provides executable hooks, arbitrary JSON patching, remote assets or custom form-layout code.

Manifest

Required fields are version: 1, id, displayName, description, category, language, difficulty, architectureSummary, files, projectFormatVersion: 4 and positive integer templateVersion.

id is a stable 2–64 character lowercase/digit/hyphen identifier. It is not an ownership credential or globally verified marketplace identity. Increment templateVersion when publishing a revised recipe; this is separate from the envelope's format version. files describes project paths and must include TEMPLATE.md; actual output contents come from each native project, not this list.

Categories: Beginner, Game, Demo, Graphics, Audio, C / Mixed, Disk / Cartridge, Testing / SDK. Languages: ASM, C, Mixed. Difficulties: Beginner, Intermediate, Advanced.

Optional metadata includes firstEdit, tags, targetTypes, compilerAbi, sdkModules, compatibilityModules, nativeAssets, palNtsc, memoryAssumptions, estimatedPrgBytes, documentation, recommendedNextTemplates, sourceProvenance and performance. The schema lists the exact shapes. These are descriptive claims, not proof of performance or compatibility. Do not claim measurements that were not made.

Defining inputs

Every parameter has id, type, label and a valid defaultValue. Optional common fields are description and required. IDs start with a letter, contain only letters/digits and have at most 64 characters. They must be unique; reserved prototype names are rejected. Answers omitted by a user use defaults.

TypeDefinition and answer
textRequired maxLength from 1 to 256; single-line string; required rejects blank text
numberRequired finite min and max within ±1 billion; numeric answer, no string coercion; fractions are allowed unless v2 integer: true is set
booleanBoolean true or false
selectchoices: [{value, label, description?}]; answer is one declared string value
multiselectSame choices; answer is a distinct array of declared string values; required rejects an empty array

Example input definitions, not a complete artifact:

{
  "parameters": [
    {"id":"title","type":"text","label":"Project title","defaultValue":"My Demo","maxLength":32,"required":true},
    {"id":"speed","type":"number","label":"Speed","defaultValue":2,"min":1,"max":8},
    {"id":"music","type":"boolean","label":"Include music","defaultValue":true},
    {"id":"video","type":"select","label":"Video standard","defaultValue":"pal","choices":[{"value":"pal","label":"PAL"},{"value":"ntsc","label":"NTSC"}]},
    {"id":"credits","type":"multiselect","label":"Credit sections","defaultValue":[],"choices":[{"value":"code","label":"Code"},{"value":"art","label":"Artwork"}]}
  ]
}

Multiselect answers are normalized to declared choice order, not click order. Use that order in a variant condition containing an array. Unknown answers, invalid defaults, duplicate choices and out-of-range values reject.

Defining the output

There is no separate output script. Each variants[].project is the complete JSON object from a native .web64proj, not a filename, URL or JSON string. It includes main, virtual files, settings, native asset records and any build or media manifests. Native generated bindings and dependency relationships remain native; templates do not introduce a second asset/build pipeline.

when maps parameter IDs to exact answer values. All entries must match; omitted IDs are irrelevant to that variant. Exactly one variant must match. An empty when: {} is unconditional, not a lower-priority fallback. Overlapping or missing matches are errors, not a first-match choice.

Without inline source, optional music and PAL/NTSC can use four complete projects:

whenEmbedded project
{"music":true,"video":"pal"}Saved PAL project with music
{"music":false,"video":"pal"}Saved PAL project without music
{"music":true,"video":"ntsc"}Saved NTSC project with music
{"music":false,"video":"ntsc"}Saved NTSC project without music

Use substitutions for title, speed and credits if they change only text. For example, put ; {{title}} and SPEED = {{speed}} in the saved main.asm, then:

{
  "substitutions": [
    {"parameter":"title","files":["main.asm","TEMPLATE.md"]},
    {"parameter":"speed","files":["main.asm"]},
    {"parameter":"credits","files":["TEMPLATE.md"],"separator":", "}
  ]
}

Only literal {{parameterId}} tokens in explicitly listed authored .asm/.s/.inc/.c/.h/.txt/.md files are replaced. Each listed file must exist in every variant and cannot be binary, generated or a native asset record. Numbers become decimal text, booleans true/false, and lists join with the chosen separator (comma by default). Replacement is single-pass. There is no escaping for C/ASM strings: place free text safely in comments/documentation, or use constrained choices for code constants. Answers are never host expressions.

The resulting project is independently editable. It retains compact template provenance but does not require the template, Cloud, a license server or a special runtime to build. Creation does not save, build or start the emulator.

Version 2 declarative script

Set the envelope to "version": 2 to use script. Leave manifest.version: 1 and manifest.projectFormatVersion: 4 as they are. script is optional, so a v2 file without it behaves like v1 plus v2 numeric validation. Existing v1 files need no conversion. The fragments below show the JSON script grammar; the current linked starter uses inline v3 source instead.

A script renders text into full-line anchors that already exist in authored files of every complete project variant. It cannot create, remove, rename or select virtual files, build targets, assets or settings. Use complete variants for those structural differences. Rendering occurs after the unique variant is selected, before literal {{parameterId}} substitutions and final native validation. Every referenced source/include file must be present in the selected project's virtual filesystem or in Web64's bundled virtual SDK. Publisher-local paths, downloads, packages and remote URLs are invalid dependencies. An inactive branch may name a different embedded file, as the historical PAL and NTSC branch examples do; both files travel inside the artifact.

Blocks and anchors

The script object has "version": 1 (the script-language version) and 1–64 blocks. A block has exactly file, anchor and body. file is a safe virtual path to authored .asm, .s, .inc, .c, .h, .md or .txt text. Generated files, binary files and native asset records are not destinations. anchor is an exact full-line marker, ignoring surrounding indentation:

DestinationAnchor syntax
.asm, .s, .inc; @web64template name
.c, .h/* @web64template name */
.md<!-- @web64template name -->
.txt@web64template name

The marker name starts with a letter and contains at most 64 letters/digits. The named anchor must appear exactly once in its destination in every variant; two blocks cannot name the same file and anchor. The marker line is replaced by rendered text. Surrounding source stays intact, and CRLF files keep CRLF output. Choose stable marker names and preserve them in the saved native project used as your template input.

Nodes and typed inputs

body, branches and loop bodies are ordered arrays of nodes. Unknown operations or properties reject. A text node appends its literal value; an emit node appends the current loop variable as decimal or selected-choice text. This is text output, so include needed indentation, comments, separators and \n in text.value. The supported operations are:

OperationRequired fieldsBehavior
textvalue stringAppend literal text
iftest, then; optional elseRender one branch; missing else renders nothing on false
switchparameter, nonempty cases; optional defaultRender one case by exact value; no fallthrough
forvariable, body, exactly one of count or eachRender the body once per count index or selected choice
emitvariableAppend a loop variable in its scope

An if.test is either { "parameter": "id", "equals": value } or { "parameter": "id", "contains": "choice" }. equals uses a valid answer for a text, number, boolean or select parameter. contains requires a declared choice of a multiselect parameter. There are no operators, string expressions, arithmetic, user functions, JavaScript evaluation or access to project state.

switch.parameter must name a select or boolean input. Each cases entry has value and body. Case values must be valid and distinct. Include every possible value or supply a default body. At most one case runs; no fallthrough. For a checkbox, case values are JSON true and false.

for.count has shape { "parameter": "steps" } and requires a v2 number input with "integer": true, min >= 0 and max <= 32. It iterates from zero through the chosen count minus one. An answer of zero emits no body. for.each has the same reference shape and requires a multiselect input. It iterates over selected values in declared choice order. The loop variable starts with a letter, uses letters/digits, must not collide with a parameter or an active outer variable, and is visible only inside that loop's body. Nested loops may read outer variables. emit outside a matching loop rejects.

The historical v2 scripted example uses this pattern (shown here as a fragment):

{
  "version": 2,
  "parameters": [
    {"id":"blueBackground","type":"boolean","label":"Blue background","defaultValue":true},
    {"id":"video","type":"select","label":"Video","defaultValue":"pal","choices":[{"value":"pal","label":"PAL"},{"value":"ntsc","label":"NTSC"}]},
    {"id":"steps","type":"number","label":"Border colors","defaultValue":3,"min":1,"max":4,"integer":true}
  ],
  "script": {
    "version": 1,
    "blocks": [
      {"file":"main.asm","anchor":"; @web64template video","body":[
        {"op":"switch","parameter":"video","cases":[
          {"value":"pal","body":[{"op":"text","value":"    .include \"include/video-pal.inc\"\n"}]},
          {"value":"ntsc","body":[{"op":"text","value":"    .include \"include/video-ntsc.inc\"\n"}]}
        ]}
      ]},
      {"file":"main.asm","anchor":"; @web64template background","body":[
        {"op":"if","test":{"parameter":"blueBackground","equals":true},
         "then":[{"op":"text","value":"    lda #$06\n    sta VIC_BACKGROUND\n"}],
         "else":[{"op":"text","value":"    lda #$00\n    sta VIC_BACKGROUND\n"}]}
      ]},
      {"file":"main.asm","anchor":"; @web64template colors","body":[
        {"op":"for","variable":"i","count":{"parameter":"steps"},"body":[
          {"op":"text","value":"    .byte "},{"op":"emit","variable":"i"},{"op":"text","value":"\n"}
        ]}
      ]}
    ]
  }
}

That fragment omits the required kind, manifest and complete variants. The current linked v3 Scripted Template Starter expresses those choices directly in main.asm, with both include files embedded in project.files. The older JSON blocks remain valid for existing templates and for disjoint anchors.

Limits, failures and verification

Validation allows at most 64 blocks, 256 total nodes, nesting depth 8 and 32 iterations per loop. Rendering stops after 4096 executed node visits or 2 MiB of emitted UTF-8 text. Each text.value is also limited to 2 MiB. Invalid typed comparisons, unknown parameters or operations, duplicate/incomplete switch cases, out-of-scope variables, missing/duplicate anchors and missing virtual includes reject before a project is published. Literal include/import directives in the selected output are checked against the VFS and bundled SDK; dynamic assembler include expressions must still pass the ordinary build gate.

Test the default and meaningful boundary answers, each select/checkbox branch, each loop's zero/min/max where allowed, and every project variant. Create, save, reopen, edit, build and run via the IDE. If your template uses disk targets, master and Run Disk in the normal IDE controls. The generated project is an ordinary editable .web64proj; no template or authoring tool is needed to build it later.

Version 3 table and matrix generation

Use envelope version: 3 when a template must compute lookup tables or matrices from its answers. script.version stays 1; all v2 nodes remain available. This is the same native generator as Insert Table / Matrix and MCP table generation, not a second math engine. Template creation calls it locally in the IDE: no MCP bridge, account permission beyond normal template installation, network request, executable plugin or formula evaluation is needed.

Example: a user-configured sine table

In the IDE, create include/wave.inc containing the full-line anchor ; @web64template wave. Include it from your ASM program with .include "include/wave.inc", placing table data outside the execution path. Save the native project and use that saved project as your template variant. Merge this fragment with the template's manifest and variants:

{
  "version": 3,
  "parameters": [
    { "id": "sampleCount", "type": "number", "label": "Wave samples",
      "defaultValue": 64, "min": 8, "max": 256, "integer": true },
    { "id": "waveAmplitude", "type": "number", "label": "Wave amplitude",
      "defaultValue": 64, "min": 0, "max": 127 }
  ],
  "script": {
    "version": 1,
    "blocks": [{
      "file": "include/wave.inc",
      "anchor": "; @web64template wave",
      "body": [{
        "op": "generate",
        "kind": "table",
        "options": {
          "preset": "sine", "name": "wave",
          "count": { "parameter": "sampleCount" },
          "amplitude": { "parameter": "waveAmplitude" },
          "center": 128, "numericType": "uint8", "overflow": "error"
        }
      }]
    }]
  }
}

The user answers the existing template form. Create Project replaces the anchor with the computed wave data and generator comments. The resulting include is ordinary editable source in the new project's virtual filesystem; the recipe is not needed afterwards. Saving/reopening the .web64proj preserves the actual generated source, not a deferred generation request. Editing the table does not trigger regeneration. Recreating the template is a separate new project.

Node contract and bindings

A generator node has exactly op: "generate", kind: "table" | "matrix", and options. preset and name are required options. Every scalar option accepts either a literal of its documented type or { "parameter": "declaredId" }. There is no interpolation or expression language inside options; a value such as "samples * 2" is not a numeric expression. Use a declared answer directly.

integer: true and give them appropriate ranges.

every choice belongs to the supported set.

match [A-Za-z_][A-Za-z0-9_]*; Web64 rejects rather than silently renames it.

references, for matrices only. Its length must match the chosen rows × columns. A multiselect answer cannot supply a numeric matrix.

Output language is selected by the containing block's path: .asm/.s/.inc produces ASM and .c/.h produces C. Generation in Markdown, plain text, binary or native asset blocks is not supported. The existing anchor rules still apply: the file must already exist in every variant, must be authored text, and the marker must occur exactly once. Options cannot supply path, source, projection, file access or custom formulas. Put C anchors at file scope. The C generator emits the required native type include automatically.

generate may appear inside existing if/switch/for bodies; only selected branches execute. Bindings refer to declared parameters, not loop variables. Do not repeatedly emit the same symbol in a loop: the normal compiler will reject duplicate declarations. Use distinct named generator nodes where needed.

Supported generator families and options

Tables: sine, cosine, triangle, saw, square, ramp, easing, reciprocal, multiplication.

Matrices: rotation2d, scale2d, affine2d, rotation3d-x, rotation3d-y, rotation3d-z, euler3d, perspective, orthographic, identity, custom.

The v3 schema bundle lists every accepted option. The native generator remains the authority for applicable options and defaults:

OptionsMeaning
numericTypeuint8, int8, web64_fix8_8, web64_ufix8_8
overflowerror, clamp, wrap; use error to catch unsafe answer combinations
layoutinterleaved or separate matrix elements
asmEncodingword, pairs, planes for 16-bit values
cArrayShape, storageflat/multidimensional; static/global
count (alias length)Table samples, 1–16384; count takes precedence
amplitude, center, phase, cycles, dutyWave configuration; phase in degrees, duty in percent
start, end, easingRamp/easing endpoints and named easing function
inputStart, inputEnd, numeratorReciprocal sampling; sampling zero is an error
aCount, bCount, aStart, aEnd, bStart, bEndMultiplication table axes; counts 1–256
steps, angleStart, angleEnd, cyclicMatrix sequence, 1–4096 steps; angles in degrees
scaleXStart, scaleXEnd, scaleYStart, scaleYEnd, uniformScale2D scale sequence
shearX, shearY, translateX, translateYAffine transform
angleXOffset, angleYOffset, angleZOffset, eulerOrder, handednessEuler rotations; order xyz, xzy, yxz, yzx, zxy, zyx; handedness left/right
fovStart, fovEnd, aspect, near, farPerspective projection
zoomStart, zoomEnd, left, right, bottom, topOrthographic projection
dimension, rows, columns, customValuesIdentity/custom matrices, dimensions 2–4

Named easing functions: linear, smoothstep, smootherstep, quadratic-in, quadratic-out, quadratic-in-out, cubic-in, cubic-out, cubic-in-out. Options only affect presets which use them, as in the IDE generator; do not rely on irrelevant options. Matrix storage is row-major with column-vector math. Quantization, endpoint sampling, clamping/wrapping and fixed-point representation are identical to the existing generator.

Safety, limits and author verification

Each invocation retains the native 16 KiB encoded-data limit. The complete script retains its 2 MiB emitted-source limit and execution/node/loop limits; generator output counts towards that same budget. Encoded bytes are not the same as source-text bytes. Multiple tables must also fit your actual C64 memory map: successful generation is not a memory-layout or compilation guarantee.

Structural and reference checks run when reading the template. Resolved numeric combinations are checked when creating with answers. Invalid ranges, sampled division by zero, matrix shape, overflow with error, or oversized output fail creation before workspace replacement. There is no partial output committed to the active project. No binary assets, new build targets, or IDE commands are implicitly created. Templates cannot use this operation for host execution.

Test default, boundary and meaningful combined answers; compare output with the IDE generator, build/run, then save/reopen/edit. A template with a valid schema can still offer an answer combination that the native generator or compiler rejects. Keep the form's ranges and choices realistic for the selected preset. The v3 schema bundle includes a complete isolated native-codec fixture to help inspect the grammar; it does not replace authoring your real project in the IDE.

Version 3 inline source directives

Set inlineSource in a v3 template to name 1–64 authored .asm, .s, .inc, .c or .h files in every embedded project variant:

"inlineSource": { "version": 1, "files": ["main.asm", "include/wave.inc"] }

One saved .web64proj can hold all the source alternatives. For source-only choices, embed it once as { "when": {}, "project": <saved native object> }. File records, assets, Build Targets and Disk/Media remain native project data. All optional includes or imported assets that a selected branch references must be embedded or come from the bundled SDK. An inactive branch does not link its source merely because that file exists in the VFS; separately configured build inputs still follow the normal build graph.

Use // @web64template as a whole-line comment in both Web64 ASM and default Web64 C. ASM also accepts ; @web64template; C accepts the whole-line /* @web64template ... */ form. The latter is useful with strict C90 tooling, which rejects // in unrendered source. Markers inside strings, trailing comments, C block comments or continued C logical lines are inert.

// @web64template switch video
// @web64template case "pal"
.include "include/video-pal.inc"
// @web64template case "ntsc"
.include "include/video-ntsc.inc"
// @web64template end

// @web64template if blueBackground
lda #$06
sta $d021
// @web64template else
lda #$00
sta $d021
// @web64template end

// @web64template for color in extraColors
.byte {{color}}
// @web64template end

// @web64template generate table {"preset":"ramp","name":"border_colors","count":{"parameter":"steps"},"start":0,"end":3,"numericType":"uint8"}

The commands are if id, if not id, if id == <JSON scalar>, if id contains <JSON string>, else, switch id, case <JSON scalar>, default, for variable in id, end, generate table <JSON options> and generate matrix <JSON options>. Conditions are typed exactly like JSON script nodes. A switch needs every declared case or a default, with no fallthrough. Integer loops use a declared 0–32 integer count and emit indices 0 through count minus one; multiselect loops emit choices in declared order. Nesting and variable scopes follow the existing bounded script rules.

{{variable}} emits a current loop variable. {{parameter}} works only when that parameter is listed for the file in substitutions. {{!name}} emits a literal {{name}}. Unknown or out-of-scope tokens reject. Emitted answers and generator output are never reparsed as template commands or substitutions. Authors must choose answer values suitable for their C/ASM syntax.

The one-line generator command accepts precisely the native v3 JSON options object described above, including typed { "parameter": "id" } bindings and matrix customValues. The containing source path selects C or ASM output. It can be placed in a selected if/switch branch or bounded loop. It does not create a file or bind to a loop variable. Repeated calls with the same exported symbol can produce a normal duplicate-symbol build error.

The renderer validates every branch's syntax and types, then emits only the selected branch. A named JSON script.blocks anchor can coexist outside an inline region; putting one inside a region rejects. Output limits and native generator limits apply. The generated project contains ordinary source with directive lines removed. It has normal compiler/debugger source maps for that resolved source.

In New from template, choose options and click Preview Source to view the resolved files without replacing the current workspace. Download Resolved Project saves that exact .web64proj; open it in a separate IDE workspace to build and run. Create Project follows the existing unsaved-work flow. The authoring project may contain mutually exclusive declarations and need not compile before resolution; ordinary project builds do not render it. The Scripted Template Starter shows this workflow in one saved ASM project.

Artwork

images.logo and images.screenshot each contain mimeType: "image/png", base64 data and plain-text alt. Static embedded PNG only; no SVG, HTML, scripts, external URLs or CSS. Web64 owns layout and V2 styling. Capture an actual running project for screenshots; a neutral placeholder is better than an invented result.

MCP workflow

Web64 IDE v2.4.4 and bridge v0.1.3 expose this through the existing web64_project_create tool. No template engine runs in the bridge.

  1. Discover template metadata using knowledge search (kind: templates) and read

the schemas/web64template/1 or /2 bundle matching the artifact's envelope version, plus this guide. Stock metadata links its portable artifact path. Public knowledge access is independent of private project access.

  1. Read the paired workspace token and use a fresh operation UUID.
  2. Supply either bundled templateId + exact templateVersion, or stage

.web64template UTF-8 bytes with web64_transfer begin/chunk/finish and supply its uploadId. Do not send an arbitrary URL or the whole file in command JSON.

  1. Call web64_project_create with mode: "inspect" and options containing the

answer object. This validates/instantiates a detached candidate without changing the workspace, even when the current project is dirty.

  1. For a stock template, call again with a new operation UUID and mode: "apply".

Apply is the default for older callers. It refuses unsaved work, rechecks the token/grant after preparation and commits once. A staged external template is inspection-only: apply returns user_action_required. The user imports it into Cloud and creates from My Templates in the UI; MCP does not gain Cloud access.

  1. Build, run or save only through separately requested normal tools. Inspection

is not evidence of a successful build or emulator run.

Both modes and staging require project:write. Inspection returns the actual templateFormatVersion (1 or 2), validated answers, at most the first four parameter definitions, their count/truncation flag and a bounded output summary (first 20 paths/targets). Full questions remain in the artifact or stock knowledge manifest. Retries reuse the same operation ID and identical arguments. Old browsers may reject the new fields: update the IDE and restart the updated bridge.

Cloud installation and future Marketplace

Bundled templates live with Web64. Everything the user adds lives in Web64 Cloud. Stock templates remain bundled and require no account. My Templates is assembled from the signed-in user's Cloud library. Importing a local file installs it into that library before it becomes available for creation. The file is the transport; Cloud is the installation authority. A free account is sufficient: this is account-gated, not subscription-gated.

Free Cloud supports 5 templates; paid Cloud supports 20. Existing shared storage/library quotas apply independently, including retained versions. The database enforces template slots under a per-owner lock, including concurrent imports and restore/reclassification paths. Downgrades do not delete templates; users can still read/export existing templates and remove installations before adding more. Removal does not alter projects already created from the template.

An installation uses the existing immutable Cloud asset version: assetType: web64template, JSON MIME type, original artifact bytes and content hash. Embedded project dependencies stay inside the file; they are not live links to the template publisher's workspace. Cloud revisions and templateVersion are separate concepts.

Marketplace ownership, license grants, price, moderation, listing IDs and install receipts belong to Cloud records, not the template envelope. A future installer can deliver the exact same bytes to native validation and template discovery. It must distinguish publisher/listing/version identity from the untrusted manifest ID, verify the downloaded content, and never overwrite a bundled entry or a user's project merely because a template was installed or updated.

Stock and Cloud entries have separate catalog identities even when manifest IDs match. There is no IndexedDB/localStorage template installation. Downloaded bytes are held only in memory while the dialog is in use. Clearing browser data does not remove Cloud installations; another signed-in device retrieves the library.

Marketplace publishing, purchasing, Marketplace installation, automatic updates and MCP Cloud operations are not implemented by this release. A future Marketplace installer uses this same Cloud-owned library, not a third catalog authority or a local install database.

Limits and verification

Current allocation policies: local JSON up to 256 MiB; 64 variants; 16 parameters; 32 choices each; 64 substitution records, each with at most 64 files; native project validation up to 32 MiB per variant. PNGs are at most 512 KiB and 2048×2048 each. Structure depth/node limits apply. MCP staging independently caps each upload at 16 MiB, with 32 MiB retained total. Cloud uploads currently have an 8 MiB per-file transport limit. Account storage quotas also apply independently.

These are implementation safeguards, not an intrinsic small-template mandate. Gigabyte-scale packs are not verified: they need measured streaming/container support rather than huge repeated in-memory JSON copies. Increasing such limits does not by itself require a new template format version.

Schema checks cover structure. Native checks additionally cover reference/path safety, canonical project/asset semantics, valid defaults and answer membership, unambiguous variant selection, substitution destinations and PNG decoding. Always verify the created project through the IDE lifecycle before distribution.