Skip to content
Portable format

Docs contents

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.

Portable scalar settings
KindSettingAllowed values
clockhour_format["12", "24"]
clockshow_seconds[false, true]
clockmeridiem["auto", "hide", "show"]
calendarview["day", "week"]
imageedges["bleed", "inside"]
imagefit["fill", "fit", "smart"]
imagemat_style["full_bleed", "modern", "museum", "shadow_box"]
mediaedges["bleed", "inside"]
mediafit["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.

Portable overrides
KindFieldConstraint
weatherunit_systemstring; choices: ["metric", "imperial"] or null; default: null
weatherforecast_daysinteger; choices: [3, 7] or null; default: null
weathershow_wear_guidanceboolean or null; default: null
weathershow_air_qualityboolean or null; default: null
newsmax_storiesinteger; minimum: 1; maximum: 6 or null; default: null
newsshow_summaryboolean or null; default: null
newsshow_picturesboolean or null; default: null
newstake_turns_secondsinteger; choices: [30, 60, 120] or null; default: null
tasksmax_visibleinteger; minimum: 1; maximum: 3 or null; default: null
notesmax_visibleinteger; minimum: 1; maximum: 4 or null; default: null
calendarhorizon_daysinteger; minimum: 1; maximum: 90 or null; default: null
calendarprivate_eventsstring; choices: ["show", "title_redacted", "time_only", "hidden"] or null; default: null
calendarshow_all_dayboolean or null; default: null
calendarviewstring; choices: ["auto", "next", "agenda", "week", "columns", "lanes", "rolling_month", "month"] or null; default: null
calendarfollow_time_of_dayboolean or null; default: null
calendarview_lockboolean or null; default: null
marketfocus_symbolstring; 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.

Capability triggers
TokenTriggerFirst format release
background-canvas-v1background in album, artwork, weather; or background_mat != museum; or background_motion != false; or background_cadence_seconds != 45.0.1.0
block-overrides-v1At least one portable block has nonempty settings.overrides.0.1.0
block-style-v1Any 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 != auto0.1.0
card-v1Any card block; its exact content_ref also requires a matching manifest dependency.0.1.0
composition-v2Every portable design; emitted by the author tools.0.1.0
content-ladder-v1A custom block declares responsive forms using hero/essential/secondary roles.0.1.0
content-ladder-v2Any responsive row uses vital or incidental; every row is then serialized with v2 role names.0.1.0
gallery-pack-v1Every 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-v1appearance.layout = grid0.1.0
layout-arrangement-v1A layout declares purpose or landscape/portrait grid arrangement.0.1.0
layout-setup-v1Source suggestions, setup prompts or authored picture mats.0.1.0
library-provenance-v1Local exact block origins, application instance maps and look ownership; not portable definition fields0.1.0
localized-text-v1The definition carries localized (words by locale); a host token, never sent to a screen.0.2.0
overlay-layout-v1appearance.layout = overlay; or overlay_corner != bottom-left; or overlay_scrim != standard.0.1.0
overlay-placement-v1appearance.layout = overlay and its blocks are in cells (a layout's arrangement).0.4.0
pack-audio-v1Receiver audio support for card playback; the screen audio policy controls whether sound plays.0.1.0
pack-format-v2Every multimedia v2 manifest.0.1.0
pack-window-v1Any card block, projected to the receiver in bounded current/next windows.0.1.0
picture-fill-v1appearance.radius = soft; or image/media settings.edges = bleed or settings.fit = smart.0.1.0
responsive-layout-v1appearance.layout = auto0.1.0
reveal-sequence-v1Every current multimedia activity and v2 manifest.0.1.0
wall-layout-v1appearance.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.

Required contrast pairs
TextSurface
textbackground
textsurface
textcaptionSurface
textscrim
mutedTextbackground
mutedTextsurface
mutedTextcaptionSurface
mutedTextscrim
positivesurface
negativesurface
accentsurface
accentTextaccent

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.

Native format and runtime limits
LimitValue
Installed v1 elements (current host)500
Pending v1 imports20
V1 archive bytes262144
V1 expanded bytes131072
ZIP maximum compression ratio100
MAX_PACK_ARCHIVE134217728
MAX_PACK_EXPANDED268435456
MAX_PACK_FILES2048
MAX_PACK_DOCUMENTS4194304
MAX_PACK_ITEMS1000
MAX_PACK_INSTALLED2147483648
MAX_PACK_INSTALLED_FILES16384
MAX_PACK_STAGING536870912
MAX_PACK_JOBS2
MAX_PACK_IMAGE8388608
MAX_PACK_AUDIO2097152
MAX_PACK_AUDIO_SECONDS30
MAX_PACK_COMPRESSION_RATIO100
MAX_PACK_WINDOW16384
MAX_PACK_CHECKPOINT2048
MAX_GALLERY_WORKS200
MAX_DECODED_PIXELS12000000
MAX_IMAGE_WORKING_SET_BYTES134217728

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
Definition constraints
FieldGrammar
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
ArrangementCell constraints
FieldGrammar
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
BlockStyle constraints
FieldGrammar
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
LayoutArrangement constraints
FieldGrammar
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
LocalizedText constraints
FieldGrammar
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
PortableAppearance constraints
FieldGrammar
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
PortableBlock constraints
FieldGrammar
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
PortablePlacement constraints
FieldGrammar
region (optional)string; choices: ["auto", "header", "main", "secondary", "stage", "side"]; default: "auto"
importance (optional)string; choices: ["required", "normal", "optional"]; default: "normal"
PortraitArrangementCell fields
PortraitArrangementCell constraints
FieldGrammar
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
SetupPrompt constraints
FieldGrammar
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
SourceSlot constraints
FieldGrammar
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
SuggestedSource constraints
FieldGrammar
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
Manifest constraints
FieldGrammar
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
DefinitionRef constraints
FieldGrammar
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
PackDefinition constraints
FieldGrammar
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
PackActivity constraints
FieldGrammar
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
PackAudioCue constraints
FieldGrammar
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
PackCredit constraints
FieldGrammar
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
PackFace constraints
FieldGrammar
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
PackItem constraints
FieldGrammar
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
PackResource constraints
FieldGrammar
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
PackTiming constraints
FieldGrammar
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
PackTranslation constraints
FieldGrammar
prompt (required)PackFace
reveal (required)PackFace
GalleryDefinition fields
GalleryDefinition constraints
FieldGrammar
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
GalleryCredit constraints
FieldGrammar
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
GalleryEvidence constraints
FieldGrammar
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
GalleryPlacard constraints
FieldGrammar
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
GalleryPresentation constraints
FieldGrammar
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
GalleryResource constraints
FieldGrammar
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
GalleryRights constraints
FieldGrammar
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
GalleryWork constraints
FieldGrammar
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
PackManifest constraints
FieldGrammar
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
ContentLadderDeclaration constraints
FieldGrammar
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
ContentFormDeclaration constraints
FieldGrammar
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
ContentRowDeclaration constraints
FieldGrammar
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 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.

Author and validate

Install the standalone tool from its tagged release in the public library repository with python -m pip install "denframe-format @ git+https://github.com/atanasster/denframe-library@format-v0.3.0#subdirectory=format", or download the wheel attached to the format-v0.3.0 release. It has no dependency on the host application. Start a theme, block, content collection or text-only pack, then validate and build:

denframe-author new theme studio/my-theme /tmp/my-theme.json --name "My theme"
denframe-author validate /tmp/my-theme.json
denframe-author build /tmp/my-theme.json /tmp/my-theme.denframepack
denframe-author validate /tmp/my-theme.denframepack --json
denframe-author inspect /tmp/my-theme.denframepack
denframe-author unpack /tmp/my-theme.denframepack /tmp/unpacked
denframe-author new pack studio/my-pack /tmp/my-pack.json --name "My pack"

The source wrapper accepts id, version and definition, plus optional publisher, slug and explicit manifest metadata. Explicit manifests preserve attribution, dependencies and publisher. Put pack assets beside the source under their digest filenames. Build and unpack refuse to overwrite existing outputs. Validate does not install or authenticate a publisher.

The repository wrapper scripts/library-author.py provides the same commands and renderer previews with synthetic data. Use preview --activity, --locale and --item for packs, or --forms for block variants. Test import, source binding, use, updates and removal in a disposable host; preserve exact dependency archives when sharing. To offer a finished file to the Denframe Library, use Submit an asset: it runs the browser checks above and opens a summary-only public issue.