Create / Mod files / Training lessons for mods
Training lessons for mods
A Lesson is one screen of the in-game handbook: a demonstration, a few lines,
the actions it names, a link into this manual, and sometimes a range to fly. The
handbook is the CONDENSED companion to these pages - a player reads a lesson in
the menu and comes here for the whole story.
Lessons are content like everything else. The base game ships its own, and an enabled mod can add lessons to any category or replace a base lesson by declaring its id.
This page is the field-by-field lesson reference. For general RON spelling rules
such as double parentheses, Some(...), and asset schemes, see
RON spelling rules.
The Lesson item
[
Lesson((
id: "my_mod_towing",
category: Flight,
order: 70,
title: "Towing a dead hull",
media: Loop(
sheet: "self://training/towing.png",
columns: 4,
rows: 3,
frames: 12,
frames_per_second: 12,
alt: "a tug closing on a drifting ship and matching its velocity",
),
body: "Match the other ship's velocity before you close on it. \
Starting a tow while you are still closing pushes both ships \
off course.",
actions: ["autopilot_stop"],
wiki_path: "wiki/flight-autopilot#manual-flight",
practice: Some("my_mod_drill_towing"),
field_notes: [
"Match the other ship's velocity before you start a tow.",
],
)),
]
| field | type | default | meaning |
|---|---|---|---|
id |
string | required | Stable key, the overlay key, and what the player's progress is recorded against. Prefix new ids with your mod id. |
category |
category | required | Which group the lesson is listed under - see Categories. |
order |
integer | required | Position within the category. Ties break on id, so the list never depends on which mods are installed. |
title |
string | required | The row label and the heading over the lesson. |
media |
media | required | The demonstration - see Media. Required, so the layout never reflows between lessons. |
body |
string | required | The whole lesson, at most 45 words. A tip that needs more is two tips. |
actions |
list of strings | [] |
Action names whose CURRENT bindings are drawn as chips. Never write a key. |
wiki_path |
string | required | Where this manual continues, without a leading slash: a page it ships, such as wiki/flight-autopilot, plus the heading anchor where the claim sits. |
practice |
Option string |
None |
A role: Lesson scenario the Practice button launches. |
field_notes |
list of strings | [] |
Short facts drawn from this lesson - see Field notes. |
Categories
Six, fixed. A mod adds lessons to them; it does not add a seventh.
| category | what belongs in it |
|---|---|
StartHere |
What the game is and how to read the screen. |
Flight |
Flying the hull, by hand and by flight computer. |
Combat |
Finding, locking and shooting things. |
Shipbuilding |
The editor, and what a hull's parts cost. |
Interface |
The TAB interface panes and the : command shell. It draws as INTERFACE. |
Advanced |
Scenarios, mods, bindings - the game around the game. |
An empty category draws no header, so a mod that only writes Flight lessons does not put five empty groups on a player's screen.
Media
Every lesson carries a demonstration, in one of two forms.
A still:
media: Image(
image: "self://training/towing.png",
alt: "a tug closing on a drifting ship",
),
A loop, as a sprite sheet:
media: Loop(
sheet: "self://training/towing.png",
columns: 4,
rows: 3,
frames: 12,
frames_per_second: 12,
alt: "a tug closing on a drifting ship and matching its velocity",
),
| field | type | meaning |
|---|---|---|
image / sheet |
asset ref | A self:// or dep:// image in your bundle's resources. A plain 2D PNG - not a cubemap. |
columns, rows |
integer | How the sheet is cut into cells. Every cell is the same size, so the sheet's pixel size must divide evenly. |
frames |
integer | How many cells are played, read left to right, top to bottom. At most columns * rows. |
frames_per_second |
number | Playback rate. Above zero. |
alt |
string | What the demonstration shows. Drawn in the frame while the image loads, and if it cannot be drawn at all. |
A sprite sheet rather than a video file: it is one image through the same pipeline every other texture uses, so it plays on the desktop build and the web build without a second decoder. Nothing in a PNG says where its cells are, which is why the grid is authored - a grid the sheet cannot be cut by is a content error.
Practice
practice names a scenario the Practice button launches, through the same
New Game hand-off the Scenarios menu uses. There is no second launch path.
The scenario must declare role: Lesson. That is what
makes "somewhere focused to fly" checkable: a practice range is ONE thing to
try, with the briefing and the cast taken out, and a Practice button that
dropped the reader into an hour of campaign would not be practice. Naming a
chapter or a backdrop is a lint error.
The range is part of the lesson, so write it like one: hand the player only the verbs this lesson names and withhold the others, put the reason on the comms channel rather than on the objective board, light the chip for the verb in hand, and END it in a banner the player can earn or retry. The practice-range contract spells out each of the four.
Pressing Practice never marks the lesson completed. Reading a lesson marks it read; only an outcome that asserts the skill can claim more.
A lesson with nothing focused to fly carries practice: None. Leave it out
rather than pointing at the nearest approximation.
Field notes
A field note is the same fact the lesson teaches, cut to the two short lines the menu card and the loading screen draw. The claim is written ONCE, on the lesson it belongs to, and the note carries its lesson with it so the menu card can open it.
Write a note as one sentence and let the slot break it: two lines of 64 characters. A note that needs a third line is a lesson, and the lint says so.
A note names an ACTION, never a key - the loading screen has no binding table to correct it with.
Overlay
A new id adds a lesson. Reusing one replaces that lesson whole - it is not a
field-level patch.
A lesson id denotes a stable learning outcome, because the player's progress is recorded against it. A replacement may change every word and the picture, but somebody who has already read that lesson has still read it, so replace a base lesson when you have a better telling of the SAME thing - and add a new id when you have something else to say.
Check it
nix develop --command cargo run content lint --target path/to/your-mod
The lint refuses a blank required field, a body over the word cap, a loop grid
that cannot be cut, a field note that does not fit the slot, and a practice
that names an unknown scenario or one that is not a practice range. It warns
about a practice range no lesson sends the player to.