# Blocks

The 15 blocks a course page is made of, and the keys each one takes.

A page's `blocks` hold what the page shows, from top to bottom. Each block has a `"type"`, which sets its other keys. Every text a block shows is a text ID from the words file.

| Block | What it shows |
| --- | --- |
| [`heading`](#heading) | A heading. |
| [`text`](#text) | A paragraph. |
| [`list`](#list) | A list. |
| [`steps`](#steps) | Numbered steps, such as how to use a tool. |
| [`callout`](#callout) | A note that stands out from the page. |
| [`table`](#table) | A table. |
| [`quote`](#quote) | A quotation. |
| [`image`](#image) | A picture. |
| [`audio`](#audio) | A sound. |
| [`video`](#video) | A video. |
| [`film`](#film) | A film Kapi draws and plays from its scenes, with captions, a transcript and questions that pause it. A package with a film says "sdk": "2.1". |
| [`question`](#question) | A practice question, with feedback after each answer. |
| [`contact`](#contact) | A company contact. Where the company hasn't filled it in, the page shows common.contact-missing.\<key\>. |
| [`sources`](#sources) | The titles of the documents the package was made from. |
| [`divider`](#divider) | A line between parts of a page. |

## `heading`

A heading.

- `type`: `"heading"`, required. The block's type.
- `text`: text ID, required. The text ID of the heading.

## `text`

A paragraph.

- `type`: `"text"`, required. The block's type.
- `text`: text ID, required. The text ID of the paragraph.
- `style`: `"body"`, `"lead"`, `"small"`. lead for an opening paragraph, small for a note, or body. Left out: body.

## `list`

A list.

- `type`: `"list"`, required. The block's type.
- `items`: list of text IDs, required. The items, in order.
- `ordered`: true or false. true to number the items.

## `steps`

Numbered steps, such as how to use a tool.

- `type`: `"steps"`, required. The block's type.
- `items`: list of text IDs, required. The steps, in order.

## `callout`

A note that stands out from the page.

- `type`: `"callout"`, required. The block's type.
- `tone`: `"note"`, `"important"`, `"warning"`, required. How strongly it stands out: note, important or warning.
- `text`: text ID, required. The text ID of the note.

## `table`

A table.

- `type`: `"table"`, required. The block's type.
- `header`: list of text IDs. The column headings.
- `rows`: list of lists of text IDs, required. The rows.

## `quote`

A quotation.

- `type`: `"quote"`, required. The block's type.
- `text`: text ID, required. The text ID of the quoted words.
- `cite`: text ID. The text ID of who or what it quotes.

## `image`

A picture.

- `type`: `"image"`, required. The block's type.
- `media`: ID, required. The media ID of a picture in kapi-works.json.

## `audio`

A sound.

- `type`: `"audio"`, required. The block's type.
- `media`: ID, required. The media ID of a sound in kapi-works.json.

## `video`

A video.

- `type`: `"video"`, required. The block's type.
- `media`: ID, required. The media ID of a video in kapi-works.json.

## `film`

A film Kapi draws and plays from its scenes, with captions, a transcript and questions that pause it. A package with a film says "sdk": "2.1".

- `type`: `"film"`, required. The block's type.
- `scenes`: list of film-scenes, required. The scenes, in order: 2 to 30, up to 10 minutes in all. Scene IDs are all different.
- `emails`: list of film-emails. The emails the film's email scenes show, with IDs all different: up to 4.
- `emails[].id`: ID, required. The email's ID, which email scenes name.
- `emails[].from`: text ID, required. The text ID of the sender's name.
- `emails[].address`: text ID, required. The text ID of the sender's address. Use an address that ends in .example.
- `emails[].subject`: text ID, required. The text ID of the subject.
- `emails[].lines`: list of text IDs, required. The email's lines.
- `emails[].button`: text ID. The text ID of a button in the email.
- `emails[].link`: text ID. The text ID of the address the button really goes to, shown when the pointer rests on it.
- `emails[].attachment`: text ID. The text ID of an attached file's name.
- `style`: text. CSS for the film's drawing scenes, up to 32000 bytes. It may use @keyframes, @media and @supports rules, and no addresses: url() names only a part of the same drawing. Kapi's clock plays every animation it starts, and every part sizes with box-sizing: border-box. The canvas is .kw-canvas; while a scene waits for a tap it also has .kw-targeting, and a tapped target has .kw-right or .kw-wrong. A part chosen for a question with several right parts has .kw-chosen, and every chosen part has .kw-right once the answer is right.

### Scenes

A scene of a film. Its layout sets the keys it takes.

- `scenes[].id`: ID, required. The scene's ID.
- `scenes[].title`: text ID, required. The text ID of the scene's name, shown in the transcript and on the seek bar.
- `scenes[].seconds`: number, required. How long the scene runs, from 4 to 60 seconds, in tenths at most, such as 6.5.
- `scenes[].layout`: `"title"`, `"number"`, `"email"`, `"chat"`, `"person"`, `"icons"`, `"checklist"`, `"drawing"`, required. The drawn layout.
- `scenes[].caption`: text ID, required. The text ID of what the narrator says, shown as captions. Short sentences, and never a placeholder.
- `scenes[].picture`: text ID, required. The text ID of what the scene shows, for the transcript and screen readers.
- `scenes[].headline`: text ID. The text ID of a few words on the picture.
- `scenes[].pause`: ID. The ID of a choice or multi practice question the film stops for after this scene. No page or test pool may hold it too.

### `title` scenes

A title card.

- `scenes[].heading`: text ID, required. The text ID of the title.
- `scenes[].kicker`: text ID. The text ID of a small line above it.

### `number` scenes

A number that counts up, with its label.

- `scenes[].number`: text ID, required. The text ID of the number, such as 38%.
- `scenes[].label`: text ID, required. The text ID of what the number counts.
- `scenes[].note`: text ID. The text ID of a small line under it, such as where the number comes from.

### `email` scenes

An email from this film's emails. Each beat moves the camera to the part it marks, in order.

- `scenes[].email`: ID, required. The ID of an email in this film's emails.
- `scenes[].beats`: list of `"arrive"`, `"mark-from"`, `"reveal-address"`, `"mark-subject"`, `"mark-lines"`, `"point-link"`, `"mark-attachment"`, `"report"`. What happens, in order. Left out: the email shows still.

### `chat` scenes

Chat messages that arrive one by one.

- `scenes[].messages`: list of objects, required. The messages, in order.
- `scenes[].messages[].who`: text ID, required. The text ID of who sends it.
- `scenes[].messages[].text`: text ID, required. The text ID of the message.
- `scenes[].mark`: whole number. The number of the message to mark as the one to notice, counting from 1.

### `person` scenes

A drawn person at work, on a call with someone else or saying something.

- `scenes[].label`: text ID, required. The text ID of who it is, such as You.
- `scenes[].prop`: `"phone"`, `"laptop"`, `"none"`, required. What they hold: a phone, a laptop, or none.
- `scenes[].with`: text ID. The text ID of who they're talking to, which draws a call.
- `scenes[].says`: text ID. The text ID of what they say, in a speech bubble.

### `icons` scenes

Icons with their words, each in turn.

- `scenes[].items`: list of objects, required. The icons, in order.
- `scenes[].items[].icon`: `"search"`, `"phone"`, `"flag"`, `"mail"`, `"link"`, `"file"`, `"lock"`, `"key"`, `"shield"`, `"alert"`, `"check"`, `"clock"`, `"card"`, `"person"`, required. The icon.
- `scenes[].items[].text`: text ID, required. The text ID of its words.

### `checklist` scenes

A checklist that ticks each item in turn.

- `scenes[].items`: list of text IDs, required. The items, in order.

### `drawing` scenes

A scene the author draws on a 960 by 540 canvas, with the film's style.

- `scenes[].drawing`: text, required. The scene's markup, up to 16000 bytes: div, span, p, b, strong, i, em, u, s, small, sup, sub, br, ul, ol, li, and inside an svg svg, g, path, rect, circle, ellipse, line, polyline, polygon, defs, linearGradient, radialGradient, stop, clipPath, with only class, style, id, aria-hidden, data-text, data-count, data-from, data-d, data-du, data-target, viewBox, width, height, x, y, x1, y1, x2, y2, cx, cy, r, rx, ry, fx, fy, d, points, fill, fill-opacity, fill-rule, clip-rule, clip-path, stroke, stroke-width, stroke-linejoin, stroke-linecap, stroke-dasharray, stroke-opacity, opacity, offset, stop-color, stop-opacity, transform, gradientUnits, gradientTransform, preserveAspectRatio. Every word is a text ID on an empty element, such as \<span data-text="intro.name"\>\</span\>. data-count counts a number up from data-from, after data-d seconds over data-du seconds. data-target makes a part a choice of the question the scene stops for, tapped on the picture: a choice question takes one tap, and a multi question takes every right part, then Check answer.

## `question`

A practice question, with feedback after each answer.

- `type`: `"question"`, required. The block's type.
- `question`: ID, required. The ID of a question in questions.json that isn't in a test's pool.

## `contact`

A company contact. Where the company hasn't filled it in, the page shows common.contact-missing.\<key\>.

- `type`: `"contact"`, required. The block's type.
- `contact`: ID, required. The contact's key, such as it-help, declared in context as contacts.it-help.

## `sources`

The titles of the documents the package was made from.

- `type`: `"sources"`, required. The block's type.

## `divider`

A line between parts of a page.

- `type`: `"divider"`, required. The block's type.

## What Kapi checks

| Check | Severity | What Kapi says |
| --- | --- | --- |
| [`reference_unknown`](https://docs.kapiworks.com/build/reference/checks/reference-unknown) | Error | This names …, which the package doesn't declare. |
| [`word_missing`](https://docs.kapiworks.com/build/reference/checks/word-missing) | Error | The words file has no text for …. |
| [`word_owner`](https://docs.kapiworks.com/build/reference/checks/word-owner) | Error | …'s first part names nothing in the package. Start a text ID with its lesson, page or question ID, or course, common, role or assessment. |
| [`word_unused`](https://docs.kapiworks.com/build/reference/checks/word-unused) | Warning | … isn't used anywhere. Remove it, or use it. |
| [`markup_not_allowed`](https://docs.kapiworks.com/build/reference/checks/markup-not-allowed) | Error | These words use …. Words take only \*\*strong\*\*, \_emphasis\_, \[label\](https://host/path) links and line breaks. |
| [`link_not_https`](https://docs.kapiworks.com/build/reference/checks/link-not-https) | Error | The link to … must start with https://. |
| [`link_host_undeclared`](https://docs.kapiworks.com/build/reference/checks/link-host-undeclared) | Error | These words link to …, which kapi-works.json doesn't list in links. Add the host if people may open it. |
| [`alt_missing`](https://docs.kapiworks.com/build/reference/checks/alt-missing) | Error | This picture needs alt text, or mark it decorative. |
| [`captions_missing`](https://docs.kapiworks.com/build/reference/checks/captions-missing) | Error | Sound or video with speech needs captions. |
| [`media_file_missing`](https://docs.kapiworks.com/build/reference/checks/media-file-missing) | Error | The package has no file …. |
| [`media_not_listed`](https://docs.kapiworks.com/build/reference/checks/media-not-listed) | Error | This media file isn't listed in kapi-works.json. |
