Package files
Every field of Style, Format, Manifest, and rapid.lock, with types and defaults.
Every field of the four package files, from the schemas in contracts/src/ (style.ts, format.ts, manifest.ts). A field with a default may be left out.
Common types:
| Type | Is |
|---|---|
| hex | #rrggbb or #rrggbbaa |
| token | lowercase, starting with a letter, then a-z, 0-9, -; up to 40 characters |
| name | lowercase, starting with a letter, then a-z, 0-9, -; 2–48 characters |
| version | semantic: 1.2.3, optionally with a pre-release, 1.2.3-beta.1 |
| sha256 | 64 lowercase hex digits |
| seconds | a finite number, 0 or more |
Style
style.json. Schema version 1.
| Field | Type | Default |
|---|---|---|
schema_version | 1 | required |
tokens | Tokens | required |
motion | Motion | all defaults |
sound | Sound | all defaults |
components | object: component name → object of parameters | {}; a place for a style to note values for agents. No code reads it, and it isn't the components/ folder |
formats | object: token (a format's name) → Adaptation | required; a format not listed isn't supported |
grid | Grid | none |
video | VideoType | none |
The components folder
Apart from style.json, a style may ship components/: working scenes for the pieces its look needs that the kit doesn't have, one file each, with components/README.md listing them. A style can't carry scripts, so each piece's behaviour lives in a marked <script> block with its settings at the top. A builder copies that into a scene and tunes it, or writes a variation; the piece's look stays in style.css, and its pictures load as rapid:style/<path>. Render one to see it:
rapid still styles/bubble/components/<file> --style styles/bubble --t 1.8
See making a style.
Tokens
| Field | Type | Default |
|---|---|---|
palette | object: token → hex | required; colours blend in OKLab |
fonts | object: token (a role: display, voice, ui, …) → FontFace | required |
type_scale | object: token → positive number | {}; pixels at the format's base width |
leading | { min, max }, positive numbers | { "min": 0.86, "max": 1.2 } |
margins | { x, y }, numbers 0 or more | { "x": 72, "y": 72 }; pixels at the base width |
FontFace
| Field | Type | Default |
|---|---|---|
family | string, 1–120 | required; as the system names it |
weight | integer 100–1000 | 400 |
style | normal or italic | normal |
substitutes | array of strings | []; families that may stand in, in order |
Motion
| Field | Type | Default |
|---|---|---|
exit | off-edge, fade, cut, or scale | off-edge |
easing | object: token → string | {}; eases by role |
transitions | array of strings | []; a note of the hand-offs the look prefers, for agents to read. No code reads it, and its words needn't be the join's named moves: the storyboard's out decides what's drawn |
pacing.line_hold | seconds | 0.6; how long a line holds after it lands |
pacing.shot | positive number | 2.5; typical shot length in seconds |
pacing.words_per_second | positive number | 3.6; for timing spoken lines |
pacing.chars_per_second | positive number | 38; for timing typed replies |
Sound
| Field | Type | Default |
|---|---|---|
cues | object: cue kind → instrument | {} |
colors | object: token (a palette name) → instrument | {}; used when a cue carries a colour |
tempo | positive number | none |
An instrument is one of the engine's voices: kick, hat, pad, sub, keys, rim, room,
click, or whoosh. A cue picks its instrument by its colour first, then its kind; a kind that is
itself an instrument's name plays it with no mapping. rapid style check refuses a style that
names any other instrument, and rapid mix reports the cues that played nothing and fails a video
whose cues all played nothing.
Adaptation
| Field | Type | Default |
|---|---|---|
margins | { x, y } | the style's margins |
type_k | positive number | none; a factor on the type scale |
grid | Grid | the style's grid |
Grid
The grid scenes align to, in pixels at the base width; scenes see it as --rapid-grid-*, and the grid check holds key-frame text to it.
| Field | Type | Default |
|---|---|---|
columns | integer 1–24 | required; between the margins |
gutter | number, 0 or more | required |
baseline | positive number | none; text blocks start on its multiples from the top margin |
VideoType
| Field | Type | Default |
|---|---|---|
steps | object: token → positive number | {}; sizes in pixels at the base width, as --rapid-video-<step> |
hero_ratio | number, 1 or more | 3; the least the hero type may be over the body, for the scale check |
Format
format.json. Schema version 1.
| Field | Type | Default |
|---|---|---|
schema_version | 1 | required |
width, height | positive even integers | required |
fps | positive number, up to 120 | required |
length | { min, max }: seconds; max may be null for no limit | required |
guides | array of Guide | [] |
min_text | positive number | none; the smallest line height type may have, in pixels |
phone.max_bytes | positive integer | 30000000 |
phone.shrink_after | positive number | 120; above this many seconds the phone copy drops to 720p on its short side |
Guide
A named region of the frame that is never drawn; the checks hold elements to it by role.
| Field | Type | Default |
|---|---|---|
name | string, 1–40 | required |
role | safe, keep-out, band, trim, or note | required |
rect | { x, y, w, h } in frame pixels | required |
applies | array of element roles (type, object, card, bubble, texture, mark, other) | []: every role but texture |
safe is where elements must stay; keep-out is where they must not go; band is where type must sit. The reel format:
{
"schema_version": 1,
"width": 1080,
"height": 1920,
"fps": 30,
"min_text": 40,
"length": { "min": 0, "max": null },
"guides": [
{ "name": "safe", "role": "safe", "rect": { "x": 72, "y": 72, "w": 936, "h": 1776 }, "applies": [] },
{ "name": "band", "role": "band", "rect": { "x": 0, "y": 240, "w": 1080, "h": 1320 }, "applies": [] },
{ "name": "feed-buttons", "role": "keep-out", "rect": { "x": 960, "y": 900, "w": 120, "h": 750 }, "applies": ["type", "card", "bubble"] }
],
"phone": { "max_bytes": 30000000, "shrink_after": 120 }
}
Manifest
manifest.json, at the root of every style, format, or recipe.
| Field | Type | Default |
|---|---|---|
kind | style, format, or recipe | required |
name | name | required |
version | version | required |
schema_version | positive integer | required; the major version of the kind's schema the package was made for. A newer one than rapid knows is refused |
description | string, 1–280 | required |
tags | array of strings 1–32, at most 16 | [] |
formats | array of names | []; for a style, the formats it supports, each also in style.json |
fonts | array of FontFace | [] |
files | array of { path, sha256, bytes } | required; every file but manifest.json |
proof | Proof | none; required to share a style in rapid's repository |
A file's path is relative to the package root, with forward slashes, no leading /, no .., and no \. rapid style check --write fills files in.
Proof
| Field | Type | Default |
|---|---|---|
scene | string | required; the sample scene, proof/scene.html: an HTML scene that links rapid:style |
video | string | required; the example video, at phone size |
poster | string | required; the poster still |
golden | array of { t, path }, at least 1 | required; frames a new render of the sample must match (rapid style proof --check) |
Every proof path must be a file in the package. rapid style proof writes all of them and fills this in; see making a style.
Rules
- Allowed file types:
.json,.css,.html,.md,.txt,.svg,.png,.jpg,.jpeg,.webp,.mp4,.wav, and the fonts.woff2,.woff,.ttf,.otf. - A font file sits in a folder with the full text of a free licence (
OFL.txt,LICENSE.txt,LICENCE.txt,LICENSE.md,LICENCE.md, orUFL.txt). - A style holds
style.css, which styles every class of the kit. - A stylesheet has no
@import, and itsurl()s name only the package's own files. - At most 25 MiB in all.
- Every file is listed, and every listed file is present with its size and sha256.
- A repository holding several packages lists them in an
index.json:{ "packages": [{ "name", "path", "kind"? }] }.
The lockfile
A project's pins, written by rapid style use and rapid format use.
| Field | Type |
|---|---|
lock_version | 1 |
packages | array of LockEntry, sorted by kind then name |
LockEntry
| Field | Type | Means |
|---|---|---|
kind | style, format, or recipe | |
name | name | |
version | version | |
sha256 | sha256 | of the package packed canonically (sorted entries, fixed stamps), not of the bytes as downloaded, so the same files pin the same hash from any source |
source | string | where to fetch it again: an absolute path, an address, or a github: spec |
{
"lock_version": 1,
"packages": [
{ "kind": "style", "name": "swiss", "version": "0.1.0", "sha256": "3a74…", "source": "/Users/you/code/rapid/styles/swiss" }
]
}