Build for Denframe · format tools 0.3.0
Portable format reference
Data-only themes, block presets, content collections and multimedia activities. This reference describes the implemented v1 design and v2 pack contracts in host 0.1.0.
Archive profile
A .denframepack is a ZIP archive with a fixed end-of-central-directory record at the end. Use one disk, ordinary 32-bit ZIP sizes, no archive comment, and regular file entries with no extra fields or comments. Entries use STORED or DEFLATE with an expansion ratio of at most 100:1. Names are unique, including after case folding. Encryption, links, directories, ZIP64 and executable content are refused.
V1 contains exactly manifest.json and definition.json at the root. V2 contains those two documents and exactly the resources declared in the definition. Resource names are assets/<lowercase SHA-256>.<png|jpg|webp|mp3>. No path traversal, undeclared files or remote-resource substitutes are accepted. The end record and directory budgets are checked before entry allocation.
The manifest uses format “denframepack”, entrypoint “definition.json”, a schema_version of 1 or 2, an id, version and definition_sha256. The definition schema version agrees with its manifest. The limits below count bytes, entries and decoded pixels separately.
JSON and canonical bytes
Documents are UTF-8 JSON without a byte-order mark, duplicate keys, NaN or Infinity. Keys and text cannot contain C0/C1 controls, DEL, or bidi embedding, override and isolate characters U+202A–U+202E and U+2066–U+2069. Ordinary right-to-left text and joiners remain valid. Strings are never Unicode-normalized.
A definition may carry localized: its name, mood and description in other languages, keyed by a canonical locale (a lowercase language, an optional title-case script, an optional uppercase region or three-digit area: bg, pt-BR, zh-Hant-TW, es-419), at least one and at most 16. Each entry has at least one of name (up to 100 characters), mood (60) and description (240), none blank: each needs a character that is neither whitespace nor a format character (zero-width spaces and joiners alone are blank); the same plain-text rules apply. Hosts show the page’s language where it is present and fall back to the base words field by field. A definition with localized requires localized-text-v1, a host token that no screen needs.
V1 hashes the raw definition.json bytes; equivalent whitespace can therefore produce a different digest. V2 requires the definition to equal its canonical encoding, with every model default written explicitly, including empty lists, objects and null values. Both use SHA-256 expressed as 64 lowercase hexadecimal characters. An archive digest hashes the entire ZIP and is a separate identity.
- Validate the model and expand defaults, then recursively sort object keys by Unicode code point. Preserve array order.
- Use commas and colons with no separator whitespace, and no final newline.
- Write UTF-8 characters directly. Escape quotation marks, backslashes and JSON control characters with JSON string escaping; reject unpaired surrogates.
- Write integers as decimal integers and booleans/null as their lowercase JSON literals. V2’s only number field is duration_seconds: a finite value from 0.01 through 30, using the shortest round-tripping decimal with a fractional digit. Thus 30 becomes 30.0 and 0.01 remains 0.01; no exponent notation is needed.
- V1 canonical author output preserves the historical omission of unauthored appearance fields and default block styles. Absent purpose/arrangement/localized, absent localized fields, absent source suggestions, empty setup lists and an empty portrait map are omitted too; existing release bytes stay unchanged. Its accepted non-strict boolean/integer values are normalized by the native model. Pack fields, portable overrides and explicitly strict appearance fields remain strict.
The shared conformance corpus pins defaults, Unicode ordering, duration boundaries and native/browser agreement. Browser inspection reports separate archive, JSON, schema, capability and contrast verdicts. Media and publisher trust remain “not checked”; an accepted preflight never grants installation or decoding permission.
Identity, versions and trust
An id is handle/name, at most 100 characters, matching ^[a-z0-9][a-z0-9.-]*/[a-z0-9][a-z0-9.-]*$. Use your own namespace. denframe/ and catalog-listed ids require authenticated catalog identity. local/ identifies an unsigned export from some Denframe; it does not establish ownership on another host.
Versions are exact three-part numeric strings, at most 30 characters. V2 uses ASCII digits; the legacy v1 schema accepts Unicode decimal digits. Version ranges and “latest” are not references. Published bytes for an id and version are immutable. V1 dependency locks contain an id, exact version and definition digest; cards also pin an archive digest and activity. Schema versions and dashboard revisions are separate numbers.
V1 license is MIT, CC0-1.0 or CC-BY-4.0; CC-BY requires attribution. V2 records credits per resource, with an attribution or license notice for MIT and CC-BY. A publisher string and a valid hash are claims, not authentication. The host verifies signed catalog provenance separately, refuses conflicting unsigned identities, and labels ordinary file imports as shared. Online catalog refresh and offline signature proofs are not part of this format-tool release.
Themes and appearance
A theme has kind “theme” and empty blocks/source_slots. Choose a compiled look and optional appearance values; theme tokens overlay that look’s base palette. All colors are six-digit hexadecimal values prefixed with #. The complete merged palette must clear the contrast gate below.
Token roles: accent, accentText, background, border, captionSurface, mutedText, negative, positive, surface, text. Appearance vocabulary, defaults and limits are generated under the field reference. Layouts, backgrounds, fonts and styles name compiled behavior; packages cannot contain custom CSS, HTML, JavaScript, remote fonts or local media/source identifiers.
Blocks and content collections
A block preset contains exactly one instance; a content collection contains one to twelve ordered instances. Instance and source-slot ids are unique. Every declared source slot is used, and each referencing block has the same kind as its slot. All non-clock, non-card blocks require a source slot. Cards use exact content references instead. A slot carries a portable capability, never household credentials or bindings.
A source slot may suggest a kind matching its own and an optional public preset id: image accepts bundled-open-art or the-met-open-access-highlights; news accepts nasa-jpl-space. Suggestions never contain household ids, credentials or configuration. Content layouts may carry setup prompts with source_slot, field and required (default false): weather accepts city and units, market accepts watchlist. Slot/field pairs are unique and carry no answers. Suggestions, setup and portable image mat_style require layout-setup-v1. Image mats use modern, museum, full_bleed or shadow_box.
Compiled kinds: calendar, card, clock, custom, guest, home, image, market, meal, media, news, notes, package, tasks, transport, weather. Placement carries region and importance hints. A content layout may also declare purpose (glance, gallery, home or media) and an arrangement behind layout-arrangement-v1. Its landscape map names every block on a 12 × 6 grid; an optional portrait map overrides cells on a 6 × 12 grid. Each cell requires col_start, row_start, col_span and row_span, must fit, and cannot overlap another authored cell. Arrangements require appearance.layout = grid. Without a portrait override, the shared renderer derives portrait from landscape. Only market instances carry symbol queries, with distinct symbols. Styles use typed fields and omit default values in v1 author output.
| Kind | Setting | Allowed values |
|---|---|---|
| clock | hour_format | ["12", "24"] |
| clock | show_seconds | [false, true] |
| clock | meridiem | ["auto", "hide", "show"] |
| calendar | view | ["day", "week"] |
| image | edges | ["bleed", "inside"] |
| image | fit | ["fill", "fit", "smart"] |
| image | mat_style | ["full_bleed", "modern", "museum", "shadow_box"] |
| media | edges | ["bleed", "inside"] |
| media | fit | ["fill", "fit", "smart"] |
The reserved settings.overrides object carries choices for the kinds below. It is validated strictly; null fields and empty objects are removed. Household profile_ids never travel. Card settings use their own schema. Other settings are refused.
| Kind | Field | Constraint |
|---|---|---|
| weather | unit_system | string; choices: ["metric", "imperial"] or null; default: null |
| weather | forecast_days | integer; choices: [3, 7] or null; default: null |
| weather | show_wear_guidance | boolean or null; default: null |
| weather | show_air_quality | boolean or null; default: null |
| news | max_stories | integer; minimum: 1; maximum: 6 or null; default: null |
| news | show_summary | boolean or null; default: null |
| news | show_pictures | boolean or null; default: null |
| news | take_turns_seconds | integer; choices: [30, 60, 120] or null; default: null |
| tasks | max_visible | integer; minimum: 1; maximum: 3 or null; default: null |
| notes | max_visible | integer; minimum: 1; maximum: 4 or null; default: null |
| calendar | horizon_days | integer; minimum: 1; maximum: 90 or null; default: null |
| calendar | private_events | string; choices: ["show", "title_redacted", "time_only", "hidden"] or null; default: null |
| calendar | show_all_day | boolean or null; default: null |
| calendar | view | string; choices: ["auto", "next", "agenda", "week", "columns", "lanes", "rolling_month", "month"] or null; default: null |
| calendar | follow_time_of_day | boolean or null; default: null |
| calendar | view_lock | boolean or null; default: null |
| market | focus_symbol | string; pattern: "^[A-Z][A-Z0-9]*(?:[.\\-][A-Z0-9]+)*(?:/[A-Z]{3})?$"; minimum characters: 1; maximum characters: 12 or null; default: null |
A custom block may declare settings.responsive with at least one of glance, line, compact or full. Each form names distinct item fields: value, label, unit, status or detail. A row may join up to three other distinct fields, never itself. Vital/hero rows use one line. Legacy hero/secondary roles map to vital/incidental; the original vocabulary is preserved unless any row uses a v2 role. Defaults and remaining row/form limits are in the field reference.
Capability admission
Declare each required token once. Missing triggered capabilities are refused; unsupported requirements prevent activation on the host or receiver. Extra unneeded tokens produce a warning. The last column is the first format toolchain release (format-v…) whose validator admits the token; a Denframe host admits it once it carries that toolchain.
| Token | Trigger | First format release |
|---|---|---|
| background-canvas-v1 | background in album, artwork, weather; or background_mat != museum; or background_motion != false; or background_cadence_seconds != 45. | 0.1.0 |
| block-overrides-v1 | At least one portable block has nonempty settings.overrides. | 0.1.0 |
| block-style-v1 | Any non-default block style; or appearance.margin != standard; or appearance.face != look; or appearance.radius != look; or appearance.picture_show != around; or appearance.background_dim != off; or appearance.picture_text != auto | 0.1.0 |
| card-v1 | Any card block; its exact content_ref also requires a matching manifest dependency. | 0.1.0 |
| composition-v2 | Every portable design; emitted by the author tools. | 0.1.0 |
| content-ladder-v1 | A custom block declares responsive forms using hero/essential/secondary roles. | 0.1.0 |
| content-ladder-v2 | Any responsive row uses vital or incidental; every row is then serialized with v2 role names. | 0.1.0 |
| gallery-pack-v1 | Every art collection (a v2 definition of kind gallery); the host installs it into its gallery and never sends the pack to a screen. | 0.1.0 |
| grid-placement-v1 | appearance.layout = grid | 0.1.0 |
| layout-arrangement-v1 | A layout declares purpose or landscape/portrait grid arrangement. | 0.1.0 |
| layout-setup-v1 | Source suggestions, setup prompts or authored picture mats. | 0.1.0 |
| library-provenance-v1 | Local exact block origins, application instance maps and look ownership; not portable definition fields | 0.1.0 |
| localized-text-v1 | The definition carries localized (words by locale); a host token, never sent to a screen. | 0.2.0 |
| overlay-layout-v1 | appearance.layout = overlay; or overlay_corner != bottom-left; or overlay_scrim != standard. | 0.1.0 |
| overlay-placement-v1 | appearance.layout = overlay and its blocks are in cells (a layout's arrangement). | 0.4.0 |
| pack-audio-v1 | Receiver audio support for card playback; the screen audio policy controls whether sound plays. | 0.1.0 |
| pack-format-v2 | Every multimedia v2 manifest. | 0.1.0 |
| pack-window-v1 | Any card block, projected to the receiver in bounded current/next windows. | 0.1.0 |
| picture-fill-v1 | appearance.radius = soft; or image/media settings.edges = bleed or settings.fit = smart. | 0.1.0 |
| responsive-layout-v1 | appearance.layout = auto | 0.1.0 |
| reveal-sequence-v1 | Every current multimedia activity and v2 manifest. | 0.1.0 |
| wall-layout-v1 | appearance.layout = wall; or wall_dock != top. | 0.4.0 |
The full contrast gate
Each pair below requires a contrast ratio of at least 4.5:1. Convert every sRGB channel c from a byte to c/255, then linearize with c/12.92 when c ≤ 0.04045, otherwise ((c + 0.055)/1.055)^2.4. Luminance is 0.2126R + 0.7152G + 0.0722B. Contrast is (lighter + 0.05)/(darker + 0.05), evaluated before display rounding.
| Text | Surface |
|---|---|
| text | background |
| text | surface |
| text | captionSurface |
| text | scrim |
| mutedText | background |
| mutedText | surface |
| mutedText | captionSurface |
| mutedText | scrim |
| positive | surface |
| negative | surface |
| accent | surface |
| accentText | accent |
For the picture scrim, light text means luminance(text) > luminance(background). Inverse-linearize the captionSurface luminance L: g = 12.92L when L ≤ 0.0031308, otherwise 1.055L^(1/2.4) − 0.055, with L clamped to [0,1]. The gray byte is 255g. Raw alpha is 1 − g for light text and g otherwise; round alpha upward to two decimal places. Composite black over a white pixel for light text, or white over black otherwise. Round the resulting byte half upward and clamp to [0,255]; that gray is the scrim surface tested above. Report a failing ratio rounded downward to two decimal places.
The v1 stored model retains its older pairs without scrim so older data can load. New import/author validation applies the full gate. Download the algorithm and conformance vectors as palette-contrast.json.
Multimedia v2 and media validation
A pack contains declared locales, unique items, resources and reveal-sequence-v1 activities. Each item supplies every declared locale, with prompt and reveal faces. Images require alternative text. Audio cues declare a locale, phase, narration/effect role and transcript. Activities reference existing items in order; every item and resource is used. Current sequences provide prompt, recall, reveal and dwell timing; they do not implement scored answers or learner accounts.
An art collection is a v2 definition of kind gallery, required capabilities pack-format-v2 and gallery-pack-v1. It declares a landscape or portrait shape, a default presentation (fit, mat, placard and cadence seconds), a WebP strip of its first works and up to 200 works. Each work names its JPEG image and WebP thumbnail, alternative text, its pixel size and the orientation that size gives, which must match the collection’s shape, a focal point, an average colour, a placard (title, creator, date, institution and canonical HTTPS link, with medium and dimensions when known) and its rights: CC0 only, with the provider’s field, value, image URL and observation time as evidence. Every resource is used and dedicated CC0. A host installs a collection into its gallery; a screen never receives the pack.
Each resource’s path, SHA-256, length and media_type must agree. Images are PNG, JPEG or WebP, match their bytes, contain one frame, and fit the decoded-pixel/working-set budget and 20,000-pixel side limit. Validation inspects metadata before loading pixels. PNG allows IHDR, PLTE, tRNS, IDAT and IEND; WebP allows VP8, VP8L, VP8X and ALPH. JPEG allows ordinary image segments and a standard JFIF header without thumbnails, and refuses COM and APP1–APP15 metadata. No trailing metadata is accepted.
MP3 uses complete MPEG Layer III frames, at least two, with a supported sample rate and non-free bitrate. The actual duration must match the declared duration within 0.1 seconds. ID3v2.3/v2.4 may contain one plain-text TSSE encoder tag; no other tags, flags, footer, ID3v1 or trailing data. The ID3 tag including its header is bounded to 4,096 bytes and the TSSE frame payload to 1,024 bytes. Frame validation stops once duration exceeds 30 seconds plus the encoder tolerance.
Playback is separate from import. Sound requires the screen’s explicit audio policy. Every animated transition honors prefers-reduced-motion. Browser preflight only checks bounded structure and image headers; native media validation runs before any imported media reaches a renderer.
Limits and field grammar
Byte counts are integers, with 1 KiB = 1,024 bytes and 1 MiB = 1,048,576 bytes. Constants below come from the native validator. Storage, staging, jobs and window/checkpoint limits are host/runtime budgets rather than extra archive fields.
| Limit | Value |
|---|---|
| Installed v1 elements (current host) | 500 |
| Pending v1 imports | 20 |
| V1 archive bytes | 262144 |
| V1 expanded bytes | 131072 |
| ZIP maximum compression ratio | 100 |
| MAX_PACK_ARCHIVE | 134217728 |
| MAX_PACK_EXPANDED | 268435456 |
| MAX_PACK_FILES | 2048 |
| MAX_PACK_DOCUMENTS | 4194304 |
| MAX_PACK_ITEMS | 1000 |
| MAX_PACK_INSTALLED | 2147483648 |
| MAX_PACK_INSTALLED_FILES | 16384 |
| MAX_PACK_STAGING | 536870912 |
| MAX_PACK_JOBS | 2 |
| MAX_PACK_IMAGE | 8388608 |
| MAX_PACK_AUDIO | 2097152 |
| MAX_PACK_AUDIO_SECONDS | 30 |
| MAX_PACK_COMPRESSION_RATIO | 100 |
| MAX_PACK_WINDOW | 16384 |
| MAX_PACK_CHECKPOINT | 2048 |
| MAX_GALLERY_WORKS | 200 |
| MAX_DECODED_PIXELS | 12000000 |
| MAX_IMAGE_WORKING_SET_BYTES | 134217728 |
Every schema field’s range, length, pattern and explicit default is listed below. Optional fields with model factories expand to their model’s defaults during canonical encoding. Object models reject extra properties; settings and token dictionaries have their separate allow-lists above. JSON Schema describes structure; cross-reference, capability, contrast and media checks still apply.
Definition fields
| Field | Grammar |
|---|---|
| schema_version (optional) | integer; value: 1; default: 1 |
| kind (required) | string; choices: ["theme", "block", "content"] |
| name (required) | string; minimum characters: 1; maximum characters: 100 |
| look (optional) | string; choices: ["painting", "modern", "glass", "ink", "linen", "botanical"]; default: "modern" |
| appearance (optional) | PortableAppearance |
| blocks (optional) | array; maximum items: 12; items: PortableBlock |
| source_slots (optional) | array; maximum items: 12; items: SourceSlot |
| purpose (optional) | string; choices: ["glance", "gallery", "home", "media"] or null; default: null |
| arrangement (optional) | LayoutArrangement or null; default: null |
| setup (optional) | array; maximum items: 24; items: SetupPrompt |
| localized (optional) | object; minimum properties: 1; maximum properties: 16; keys: pattern "^[a-z]{2,3}(?:-[A-Z][a-z]{3})?(?:-(?:[A-Z]{2}|[0-9]{3}))?$"; values: LocalizedText or null; default: null |
ArrangementCell fields
| Field | Grammar |
|---|---|
| col_span (required) | integer; minimum: 1; maximum: 12 |
| row_span (required) | integer; minimum: 1; maximum: 6 |
| col_start (required) | integer; minimum: 1; maximum: 12 |
| row_start (required) | integer; minimum: 1; maximum: 6 |
BlockStyle fields
| Field | Grammar |
|---|---|
| padding (optional) | string; choices: ["inherit", "none", "tight", "standard", "roomy"]; default: "inherit" |
| face (optional) | string; choices: ["inherit", "card", "transparent", "outlined"]; default: "inherit" |
| text_size (optional) | string; choices: ["smaller", "inherit", "larger"]; default: "inherit" |
| detail (optional) | string; choices: ["auto", "compact", "line", "glance"]; default: "auto" |
| heading (optional) | string; choices: ["inherit", "hidden"]; default: "inherit" |
| align (optional) | string; choices: ["start", "center", "end"]; default: "start" |
| accent (optional) | string; choices: ["inherit", "accent", "muted"]; default: "inherit" |
| stand_out (optional) | string; choices: ["off", "on"]; default: "off" |
| fit (optional) | string; choices: ["cell", "content"]; default: "cell" |
LayoutArrangement fields
| Field | Grammar |
|---|---|
| landscape (required) | object; minimum properties: 1; maximum properties: 12; keys: pattern "^[a-z][a-z0-9-]{0,39}$"; values: ArrangementCell |
| portrait (optional) | object; maximum properties: 12; keys: pattern "^[a-z][a-z0-9-]{0,39}$"; values: PortraitArrangementCell |
LocalizedText fields
| Field | Grammar |
|---|---|
| name (optional) | string; pattern: "[^\\s\\p{Cf}]"; minimum characters: 1; maximum characters: 100 or null; default: null |
| mood (optional) | string; pattern: "[^\\s\\p{Cf}]"; minimum characters: 1; maximum characters: 60 or null; default: null |
| description (optional) | string; pattern: "[^\\s\\p{Cf}]"; minimum characters: 1; maximum characters: 240 or null; default: null |
PortableAppearance fields
| Field | Grammar |
|---|---|
| layout (optional) | string; choices: ["auto", "flow", "columns", "stage", "grid", "overlay", "wall"]; default: "flow" |
| background (optional) | string; choices: ["theme", "solid", "aurora", "canopy", "dunes", "artwork", "album", "weather"]; default: "theme" |
| font (optional) | string; choices: ["theme", "sans", "serif"]; default: "theme" |
| spacing (optional) | string; choices: ["tight", "standard", "relaxed"]; default: "standard" |
| tokens (optional) | object; maximum properties: 10 |
| background_mat (optional) | string; choices: ["full_bleed", "modern", "museum", "shadow_box"]; default: "museum" |
| background_motion (optional) | boolean; default: false |
| background_cadence_seconds (optional) | integer; minimum: 15; maximum: 86400; default: 45 |
| margin (optional) | string; choices: ["none", "tight", "standard", "wide"]; default: "standard" |
| face (optional) | string; choices: ["look", "card", "veil", "transparent", "outlined"]; default: "look" |
| radius (optional) | string; choices: ["look", "square", "soft", "round"]; default: "look" |
| picture_show (optional) | string; choices: ["around", "behind", "featured"]; default: "around" |
| background_dim (optional) | string; choices: ["off", "soft", "strong"]; default: "off" |
| picture_text (optional) | string; choices: ["auto", "light", "dark"]; default: "auto" |
| overlay_corner (optional) | string; choices: ["bottom-left", "bottom-right", "top-left", "top-right"]; default: "bottom-left" |
| overlay_scrim (optional) | string; choices: ["soft", "standard", "strong"]; default: "standard" |
| wall_dock (optional) | string; choices: ["top", "side"]; default: "top" |
PortableBlock fields
| Field | Grammar |
|---|---|
| id (required) | string; pattern: "^[a-z][a-z0-9-]{0,39}$" |
| kind (required) | string; minimum characters: 1; maximum characters: 100 |
| enabled (optional) | boolean; default: true |
| settings (optional) | object; maximum properties: 4 |
| source_slot (optional) | string; pattern: "^[a-z][a-z0-9-]{0,39}$" or null; default: null |
| symbols (optional) | array; maximum items: 6; items: string; pattern: "^[A-Z][A-Z0-9]*(?:[.\\-][A-Z0-9]+)*$"; minimum characters: 1; maximum characters: 10 or null; default: null |
| placement (optional) | PortablePlacement |
| style (optional) | BlockStyle |
PortablePlacement fields
| Field | Grammar |
|---|---|
| region (optional) | string; choices: ["auto", "header", "main", "secondary", "stage", "side"]; default: "auto" |
| importance (optional) | string; choices: ["required", "normal", "optional"]; default: "normal" |
PortraitArrangementCell fields
| Field | Grammar |
|---|---|
| col_span (required) | integer; minimum: 1; maximum: 6 |
| row_span (required) | integer; minimum: 1; maximum: 12 |
| col_start (required) | integer; minimum: 1; maximum: 6 |
| row_start (required) | integer; minimum: 1; maximum: 12 |
SetupPrompt fields
| Field | Grammar |
|---|---|
| source_slot (required) | string; pattern: "^[a-z][a-z0-9-]{0,39}$" |
| field (required) | string; choices: ["city", "units", "watchlist"] |
| required (optional) | boolean; default: false |
SourceSlot fields
| Field | Grammar |
|---|---|
| id (required) | string; pattern: "^[a-z][a-z0-9-]{0,39}$" |
| kind (required) | string; minimum characters: 1; maximum characters: 100 |
| required (optional) | boolean; default: true |
| suggested_source (optional) | SuggestedSource or null; default: null |
SuggestedSource fields
| Field | Grammar |
|---|---|
| kind (required) | string; minimum characters: 1; maximum characters: 100 |
| preset_id (optional) | string; pattern: "^[a-z][a-z0-9-]{0,39}$" or null; default: null |
Manifest fields
| Field | Grammar |
|---|---|
| format (optional) | string; value: "denframepack"; default: "denframepack" |
| schema_version (optional) | integer; value: 1; default: 1 |
| id (required) | string; pattern: "^[a-z0-9][a-z0-9.-]*/[a-z0-9][a-z0-9.-]*$"; maximum characters: 100 |
| version (required) | string; pattern: "^\\d+\\.\\d+\\.\\d+$"; maximum characters: 30 |
| license (required) | string; choices: ["MIT", "CC0-1.0", "CC-BY-4.0"] |
| publisher (optional) | string; minimum characters: 1; maximum characters: 100; default: "Local author" |
| attribution (optional) | string; maximum characters: 500; default: "" |
| entrypoint (optional) | string; value: "definition.json"; default: "definition.json" |
| definition_sha256 (required) | string; pattern: "^[a-f0-9]{64}$" |
| dependencies (optional) | array; maximum items: 32; items: DefinitionRef |
| required_capabilities (optional) | array; maximum items: 16; items: string; minimum characters: 1; maximum characters: 100 |
DefinitionRef fields
| Field | Grammar |
|---|---|
| id (required) | string; pattern: "^[a-z0-9][a-z0-9.-]*/[a-z0-9][a-z0-9.-]*$"; maximum characters: 100 |
| version (required) | string; pattern: "^\\d+\\.\\d+\\.\\d+$"; maximum characters: 30 |
| digest (required) | string; pattern: "^[a-f0-9]{64}$" |
PackDefinition fields
| Field | Grammar |
|---|---|
| schema_version (optional) | integer; value: 2; default: 2 |
| kind (optional) | string; value: "pack"; default: "pack" |
| name (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 |
| description (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 240 |
| locales (required) | array; minimum items: 1; maximum items: 8; unique items: true; items: string; pattern: "^[a-z]{2,3}(?:-[A-Z]{2})?$"; maximum characters: 6 |
| resources (optional) | array; maximum items: 2046; items: PackResource |
| items (required) | array; minimum items: 1; maximum items: 1000; items: PackItem |
| activities (required) | array; minimum items: 1; maximum items: 32; items: PackActivity |
PackActivity fields
| Field | Grammar |
|---|---|
| id (required) | string; pattern: "^[a-z][a-z0-9-]{0,39}$" |
| name (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 |
| kind (optional) | string; value: "reveal-sequence-v1"; default: "reveal-sequence-v1" |
| item_ids (required) | array; minimum items: 1; maximum items: 1000; unique items: true; items: string; pattern: "^[a-z][a-z0-9-]{0,39}$" |
| locale (required) | string; pattern: "^[a-z]{2,3}(?:-[A-Z]{2})?$"; maximum characters: 6 |
| loop (optional) | boolean; default: false |
| timing (optional) | PackTiming |
PackAudioCue fields
| Field | Grammar |
|---|---|
| resource (required) | string; pattern: "^assets/[a-f0-9]{64}\\.(?:png|jpg|webp|mp3)$" |
| locale (required) | string; pattern: "^[a-z]{2,3}(?:-[A-Z]{2})?$"; maximum characters: 6 |
| phase (required) | string; choices: ["prompt", "reveal"] |
| role (required) | string; choices: ["narration", "effect"] |
| transcript (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 240 |
PackCredit fields
| Field | Grammar |
|---|---|
| creator (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 |
| license (required) | string; choices: ["CC0-1.0", "CC-BY-4.0", "MIT"] |
| attribution (optional) | string; maximum characters: 500; default: "" |
| source (optional) | string; maximum characters: 500; default: "" |
| modified (optional) | boolean; default: false |
PackFace fields
| Field | Grammar |
|---|---|
| text (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 240 |
| image (optional) | string; pattern: "^assets/[a-f0-9]{64}\\.(?:png|jpg|webp|mp3)$" or null; default: null |
| alt_text (optional) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 240 or null; default: null |
PackItem fields
| Field | Grammar |
|---|---|
| id (required) | string; pattern: "^[a-z][a-z0-9-]{0,39}$" |
| content_revision (required) | integer; minimum: 1; maximum: 2147483647 |
| translations (required) | object; minimum properties: 1; maximum properties: 8; keys: pattern "^[a-z]{2,3}(?:-[A-Z]{2})?$"; values: PackTranslation |
| audio_cues (optional) | array; maximum items: 4; items: PackAudioCue |
PackResource fields
| Field | Grammar |
|---|---|
| path (required) | string; pattern: "^assets/[a-f0-9]{64}\\.(?:png|jpg|webp|mp3)$" |
| sha256 (required) | string; pattern: "^[a-f0-9]{64}$" |
| length (required) | integer; minimum: 1; maximum: 8388608 |
| media_type (required) | string; choices: ["image/png", "image/jpeg", "image/webp", "audio/mpeg"] |
| duration_seconds (optional) | number; minimum: 0.01; maximum: 30 or null; default: null |
| credit (required) | PackCredit |
PackTiming fields
| Field | Grammar |
|---|---|
| prompt_seconds (optional) | integer; minimum: 1; maximum: 30; default: 3 |
| recall_seconds (optional) | integer; minimum: 0; maximum: 30; default: 3 |
| reveal_seconds (optional) | integer; minimum: 1; maximum: 30; default: 4 |
| dwell_seconds (optional) | integer; minimum: 1; maximum: 30; default: 2 |
PackTranslation fields
| Field | Grammar |
|---|---|
| prompt (required) | PackFace |
| reveal (required) | PackFace |
GalleryDefinition fields
| Field | Grammar |
|---|---|
| schema_version (optional) | integer; value: 2; default: 2 |
| kind (optional) | string; value: "gallery"; default: "gallery" |
| name (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 |
| description (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 240 |
| shape (required) | string; choices: ["landscape", "portrait"] |
| presentation (optional) | GalleryPresentation |
| strip (required) | string; pattern: "^assets/[a-f0-9]{64}\\.webp$" |
| resources (required) | array; minimum items: 3; maximum items: 2046; items: GalleryResource |
| works (required) | array; minimum items: 1; maximum items: 200; items: GalleryWork |
GalleryCredit fields
| Field | Grammar |
|---|---|
| creator (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 |
| license (required) | string; value: "CC0-1.0" |
| attribution (optional) | string; maximum characters: 500; default: "" |
| source (optional) | string; maximum characters: 500; default: "" |
| modified (optional) | boolean; default: false |
GalleryEvidence fields
| Field | Grammar |
|---|---|
| provider_field (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 |
| provider_value (required) | boolean or string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 |
| image_url (required) | string; pattern: "^https://\\S+$"; maximum characters: 1000 |
| observed_at (required) | string; pattern: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$"; maximum characters: 40 |
| image_field (optional) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 or null; default: null |
| uuid (optional) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 or null; default: null |
GalleryPlacard fields
| Field | Grammar |
|---|---|
| title (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 240 |
| creator (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 240 |
| date (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 |
| medium (optional) | string; maximum characters: 240 or null; default: null |
| dimensions (optional) | string; maximum characters: 240 or null; default: null |
| institution (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 |
| canonical_url (required) | string; pattern: "^https://\\S+$"; maximum characters: 1000 |
GalleryPresentation fields
| Field | Grammar |
|---|---|
| fit (optional) | string; choices: ["fit", "fill", "smart"]; default: "fit" |
| mat_style (optional) | string; choices: ["full_bleed", "modern", "museum", "shadow_box"]; default: "museum" |
| placard_seconds (optional) | integer; minimum: 5; maximum: 120; default: 12 |
| cadence_seconds (optional) | integer; minimum: 15; maximum: 86400; default: 45 |
GalleryResource fields
| Field | Grammar |
|---|---|
| path (required) | string; pattern: "^assets/[a-f0-9]{64}\\.(?:png|jpg|webp|mp3)$" |
| sha256 (required) | string; pattern: "^[a-f0-9]{64}$" |
| length (required) | integer; minimum: 1; maximum: 8388608 |
| media_type (required) | string; choices: ["image/jpeg", "image/webp"] |
| duration_seconds (optional) | number; minimum: 0.01; maximum: 30 or null; default: null |
| credit (required) | GalleryCredit |
GalleryRights fields
| Field | Grammar |
|---|---|
| license (optional) | string; value: "CC0-1.0"; default: "CC0-1.0" |
| uri (optional) | string; value: "https://creativecommons.org/publicdomain/zero/1.0/"; default: "https://creativecommons.org/publicdomain/zero/1.0/" |
| evidence (required) | GalleryEvidence |
GalleryWork fields
| Field | Grammar |
|---|---|
| id (required) | string; pattern: "^[a-z][a-z0-9-]{0,39}$" |
| image (required) | string; pattern: "^assets/[a-f0-9]{64}\\.jpg$" |
| thumbnail (required) | string; pattern: "^assets/[a-f0-9]{64}\\.webp$" |
| alt_text (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 240 |
| width (required) | integer; minimum: 1; maximum: 4096 |
| height (required) | integer; minimum: 1; maximum: 4096 |
| orientation (required) | string; choices: ["landscape", "portrait"] |
| focal_x (optional) | number; minimum: 0; maximum: 1; default: 0.5 |
| focal_y (optional) | number; minimum: 0; maximum: 1; default: 0.5 |
| mean_colour (required) | string; pattern: "^#[0-9a-f]{6}$" |
| placard (required) | GalleryPlacard |
| rights (required) | GalleryRights |
PackManifest fields
| Field | Grammar |
|---|---|
| format (optional) | string; value: "denframepack"; default: "denframepack" |
| schema_version (optional) | integer; value: 2; default: 2 |
| id (required) | string; pattern: "^[a-z0-9][a-z0-9.-]*/[a-z0-9][a-z0-9.-]*$"; maximum characters: 100 |
| version (required) | string; pattern: "^[0-9]+\\.[0-9]+\\.[0-9]+$"; maximum characters: 30 |
| publisher (required) | string; pattern: "\\S"; minimum characters: 1; maximum characters: 100 |
| definition_sha256 (required) | string; pattern: "^[a-f0-9]{64}$" |
| entrypoint (optional) | string; value: "definition.json"; default: "definition.json" |
| required_capabilities (optional) | array; minimum items: 2; maximum items: 2; unique items: true; items: string; choices: ["pack-format-v2", "reveal-sequence-v1", "gallery-pack-v1"] |
ContentLadderDeclaration fields
| Field | Grammar |
|---|---|
| glance (optional) | ContentFormDeclaration or null; default: null |
| line (optional) | ContentFormDeclaration or null; default: null |
| compact (optional) | ContentFormDeclaration or null; default: null |
| full (optional) | ContentFormDeclaration or null; default: null |
ContentFormDeclaration fields
| Field | Grammar |
|---|---|
| rows (required) | array; minimum items: 1; maximum items: 6; items: ContentRowDeclaration |
| items (optional) | integer; minimum: 1; maximum: 6; default: 1 |
| show_title (optional) | boolean; default: false |
ContentRowDeclaration fields
| Field | Grammar |
|---|---|
| field (required) | string; pattern: "^[a-z][a-z_]{0,23}$" |
| join (optional) | array; maximum items: 3; items: string; pattern: "^[a-z][a-z_]{0,23}$" |
| lines (optional) | integer; minimum: 1; maximum: 4; default: 1 |
| role (optional) | string; choices: ["vital", "essential", "incidental", "hero", "secondary"]; default: "essential" |
Download the contracts
- composition/block-instance.schema.json
- composition/content-ladder.schema.json
- composition/local-composition.schema.json
- composition/package-manifest.schema.json
- composition/portable-definition.schema.json
- packs/audio-policy.schema.json
- packs/card-settings.schema.json
- packs/definition.schema.json
- packs/gallery-definition.schema.json
- packs/manifest.schema.json
- vocabulary.json
- Pack capability inventory
- Generated reference tables
Composition schemas include the portable format and the local composition/block-instance contracts. Local-only bindings are not permitted in portable definitions; portable arrangements carry only bounded cell coordinates keyed by authored block ids. The schemas, vocabulary, generated tables and contrast vectors are served directly from the same contracts used by Denframe.