# Playable tutorials

A tutorial is a local lesson using your real engine and viewer. BGS provides the
chapter list and a screen-height iframe. Your game supplies the starting position,
instructions and scripted opponents. Tutorials do not create multiplayer games or
affect clocks, ratings or notifications.

Install `@boardgamers/protocol` 0.3 or later. Include tutorials in your viewer bundle;
BGS uses the same JavaScript and CSS for games and lessons.

## Define a chapter

```ts
import { createTutorial } from "@boardgamers/protocol/tutorial";

const tutorial = await createTutorial<GameState, Move>({
	game: "mygame",
	id: "first-move",
	version: 1,
	initialState: () => preparedPosition(),
	move: (state, move) => engine.move(state, move, 0),
	storage: localStorage,
	steps: [
		{ id: "welcome", title: "Your first move", text: "Place a piece on the board." },
		{
			id: "place",
			title: "Choose a space",
			text: "Click an empty space.",
			target: "board",
			hint: "Any empty space works.",
			complete: (state) => state.board.some((cell) => cell !== null),
		},
	],
	completion: { title: "Well done", text: "You placed your first piece!" },
});

// Render snapshots in your existing UI. Send its moves to tutorial.play(move).
const unsubscribe = tutorial.subscribe(({ state }) => render(state));
```

An explanation has a Continue button. An action step advances only when
`complete(state)` succeeds after a valid engine move. `text`, `hint` and `target`
may also be functions of state. Optional `validateMove(state, move)` returns a
short explanation if an otherwise legal move is outside the lesson; the engine
still validates all inputs.

For quiz steps, add `success: "Correct! …"` with a brief explanation (protocol 0.3.2+).
It appears in the guide after a correct answer, without an extra click. `success`
can also be a function of the resulting state. Omit `target` when the answers are
already beside the instructions.

Use `completion` for the final summary. It stays visible after the last action;
the chapter is already complete, with no extra Continue click.

Use a fixed seed. Apply scripted opponent actions inside `move` using the same
engine. Keep this deterministic: replaying the same choices must give the same
result. Pass only the learner's stripped view to the UI until the rules reveal
other players' information.

## Register and display it

```ts
import { registerViewer } from "@boardgamers/protocol/viewer";
import { createTutorial } from "@boardgamers/protocol/tutorial";
import { mountTutorialGuide } from "@boardgamers/protocol/tutorial/dom";

registerViewer("mygame", mountGame, {
	tutorial: async (target, { chapter, onProgress, nextChapter }) => {
		const tutorial = await createTutorial({
			...chapters[chapter],
			storage: localStorage,
			onProgress,
		});
		// Mount your game and guide inside target.
		// Render tutorial snapshots and send actions to tutorial.play(move).
		const removeGuide = mountTutorialGuide(guideElement, tutorial, { nextChapter });
		return () => {
			removeGuide();
			tutorial.destroy();
			// Unsubscribe and unmount your game UI.
		};
	},
});
```

Add the `tutorial` option to your existing `registerViewer` call (`mountGame` above).
BGS passes the selected interface language as `options.locale` to `launchTutorial`.
Localize the lesson text, hints, feedback and controls without changing chapter IDs,
move validation or saved progress. Missing or unsupported locales fall back to English.

BGS calls `mygame.launchTutorial` for lessons and `mygame.launch` for games. The library
cleans up the previous session when either starts.

The optional guide supplies progress, hints and playback controls: back to start,
previous step, replay step and continue.
Pass the host's `nextChapter` option to show **Next chapter** alongside them on
completion (protocol 0.3.3+). BGS handles navigation; standalone lessons can omit it.
Style its `.bgs-tutorial-*` classes to fit your game. Give highlighted elements a
stable name, such as `data-tutorial="board"`; the guide adds
`.bgs-tutorial-highlight`. Show area scrolls to it and briefly emphasizes the outline,
respecting reduced-motion preferences. Style `.bgs-tutorial-feedback` for success messages.
On mobile, keep the guide compact and collapsible, leaving room for the game's actions.

Let players make their moves with the ordinary game controls. Use the guide to explain
what to select, and highlight the relevant controls instead of adding buttons that perform
the move for them. A prepared example can preselect pieces or a route, but the player should
still confirm through the game's interface. Separate buttons are useful for quiz answers
or advancing scripted opponents.

You can build your own guide from `tutorial.snapshot` and `subscribe` instead.
Its controls call `continue()`, `previousStep()`, `restartStep()` and `restart()`.
Going back restores the start of that step. `play()` returns
whether the action succeeded; failures appear in `snapshot.error`.
Successful-step explanations appear in `snapshot.feedback` until the next accepted action.

## Progress and hosting

Progress resumes from browser storage. Increment a chapter’s `version` when its
setup or rules change enough to invalidate saved progress.

Upload your viewer as usual. In **Tutorial**, add chapter IDs, revisions, titles
and descriptions. Players with access to that game version get a **Learn to play**
link, including beta testers.

Chapter titles and descriptions use BGS's game-metadata translations. Translate
them from the admin **Translations** page. Text inside the lessons is localized
by your viewer.

Test lessons on desktop and mobile, including reload and retry. See the
[Fuji example](https://codeberg.org/boardgamers/fuji).

### Sections

For a longer course, group chapters into sections such as Basics, Federations or an expansion.
In the admin tutorial editor, add sections with an ID, title and description, then assign chapters
using the Section field. Sections appear in their listed order; unassigned chapters appear first.
Chapter order within a section follows the chapter list. **Next chapter** follows that same order.

Section titles and descriptions are translated with the game metadata, just like chapter cards.
Section IDs do not change chapter IDs or saved progress. Games with short tutorials can leave sections out.

Tutorials always use the primary viewer. A player’s alternate-viewer preference applies only to games.
