Skip to content
ondaclipdocs

The tutorial file

A tutorial is a single YAML file in .ondaclip/tutorials/. Its file name is its id: tutorials/track-orders.yaml contains id: track-orders.

id: track-orders # = the file name
account: client # the role of a demo account
title: { en-US: Track your orders, es-MX: Dar seguimiento a sus pedidos }
voice: { name: Charon } # optional; chosen from the id otherwise
clock: "09:30" # fixed clock (default); "real" keeps it live
hide: # blurred on every screen
- { id: hub-manager-email }
writes: # API writes allowed (read-only otherwise)
- "^/commands/orders$"
setup: [] # actions before the first step, not filmed
steps:
- id: find-order
title: { en-US: Find an order, es-MX: Encontrar un pedido }
start: /orders # optional; otherwise go on from the current screen
shots:
- say:
en-US: To find an order, type a word from its name in the search box.
es-MX: Para encontrar un pedido, escriba una palabra de su nombre en el cuadro de búsqueda.
type: { target: { id: orders-search-input }, text: brunch }
cleanup: [] # always runs, even after a failure
Key Required What it does
id yes The id, equal to the file name.
account yes The role of the demo account that signs in (configured in the studio).
title yes The title, in every language.
steps yes The video’s chapters. Each has an id, a title, an optional start path and its shots.
voice no { name: <voice> }. See voices and languages.
clock no The time the app shows: "09:30" by default, or "real" to keep it live. Dates stay the same from one shoot to the next.
locales no This tutorial’s languages, a subset of the product’s: [en-US] to ship a new feature in one language first. Your page shows this version in the other languages. Default: every language of the product.
hide no Elements blurred on every screen: { id } (its data-ondaclip-id or data-testid) or { css }. Applies to every match, even ones that appear later. Also works per step.
before no Values set before the app code runs, for example localStorage: { theme: dark }.
writes no API paths the tutorial is allowed to write to (regular expressions). Without it, the tutorial is read-only.
frozenResponses no { url: "<regex>", delay: <ms> }: AI or external responses recorded once and then replayed, so every shoot shows the same response.
microphone no { say: { <locale>: <sentence> }, style? }: the browser hears this sentence through its microphone, for voice-driven apps. style is the style prompt for that voice.
neverShow no Text this tutorial must never show, added to the neverShow list in config.yaml. If one is visible and not hidden, the shoot stops.
replace no { file: team.json }: fictitious identities on the page (see below).
singleShoot no true keeps the captures between renders, for tutorials that write data.
setup no Actions before the first step, not filmed.
cleanup no Actions after the last step. They always run, even after a failure, to undo what the tutorial wrote. Required when the tutorial writes, unless config.yaml defines how your team resets its demo data (demoData.reset).
quiz no Questions after the video: question, choices (per language) and answer (index).

A shot is one sentence and one action. The sentence (say) sets the length of the shot, and the action is what happens on screen while it’s spoken.

shots:
- say: { en-US: Your orders are here. }
show: { id: orders-table }
- say: { en-US: Open the first one. }
click: { id: orders-row-1 }

For every action and every way to target an element, see actions and targets.

When the demo workspace shows real people (your team), replace gives them fictitious names in the video without changing your data:

setup:
- run: node scripts/demo-team.cjs # writes team.json in TUTORIAL_OUTPUT
replace: { file: team.json }

The file is a list, written at shoot time and never committed:

[{ "email": "real@example.com", "name": "Real Name", "initials": "RN",
"fake": { "email": "alex@example.com", "name": "Alex Martin", "initials": "AM" } }]

Every page shows the fictitious identity, in text as well as titles and labels, each time the page changes. Profile photos aren’t loaded. If a real name or email is still visible on a filmed screen, the shoot stops.

For names that must never appear and that you don’t want in your repository, config.yaml can read a private list at shoot time: neverShow: { secret: sm://<project>/<secret> } (a JSON list, or one entry per line; your infrastructure only). It’s never logged or written to the outputs.

  • Every text viewers read or hear must exist in every language of the product.
  • Emails typed in a tutorial must match safeEmail (fictitious addresses only).
  • Keep videos short: 50 seconds at most per clip. Split long tasks into steps or into several tutorials.

Check a file before you commit it, with tutorial.schema.json or validate_tutorial in the MCP server. For the whole folder, see the .ondaclip folder.