Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions design/author.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,42 @@ to 3,000. Nineteen things the code does not say by itself:
play, and the third reached npm and built with it. The first three had the tool swapped for a
stand-in that logged its runs, and each refused to run it, as it should: a test serves the file
as it is.
- **A source's own fields are written where a chat reads, and the author is asked for**
(2026-11-11, #182). The owner's run in ChatGPT on 0.9.1 wrote a quiz with no `authors`. Each
of the 28 content types the skill lists refuses a source without `title`, `language`,
`license` or `authors` (each built with `params` alone), and each type's own required fields
are marked in its file's Fields section; but every type file's example is `type` and `params`,
and since #180 a chat reads it. Of the four, only the author has nothing to fall back on: the
language comes from the request, the licence is `U`. The owner's flow, the same day: the
content type, chosen with the user; then the author and licence, asked once the type is chosen,
which the user gives or skips, each on its own: a name they skip is the one the model knows
them by, or "Unknown", a licence they skip `U`, what they gave stays, and never a name made
up; then the source; then the build the environment allows best, said to the user. So
`SKILL.md` names that order before step 1, step 1 asks for the type and then the author and
licence, step 2's first point says every source names the four, step 3
opens with the three ways to build and what each needs (npm here, two files here, the build
page in the user's browser, with no attempt here first where nothing runs or fetches), and
`schemaMarkdown` writes the same under each content type's Fields heading
(`SOURCE_FIELDS`; not a part's, which is sub-content), for a chat that has the type file
alone, as the build page hands it over. It says the example is `type` and `params` alone rather
than the example holding the four: a name written in an example would be copied as the author
and build, where the model is to ask. Measured on Haiku in the chat stand-in (a fetch tool
that opens only whole addresses, npm cut off, a scripted user who answers when asked): with
0.9.1's text and a Question Set named, two of three runs asked for the author, from the brief's
list, and the third wrote "Quiz author" and built. With the flow, a quiz asked for and neither
type nor author named: until step 1 said that "a quiz" names no type, four of six runs chose
the Question Set themselves, three of them asking for the author in the same message; since,
all four proposed two types and waited, then asked for the author and licence on their own,
and wrote the name given or, on a skip, "Unknown" and `U`. Every package plays. The skip was
first written for both at once ("a skip takes the name you know them by, or "Unknown", and
the licence `U`"), which cubic's review of #183 read as replacing a name the user gave when
they skip only the licence. Haiku did not read it so: three runs on that text (a name and no
licence, a licence and no name, the author named in the request and the licence skipped) kept
what was given. It is written out all the same, each on its own and only what is missing asked
for, so that no reader has to guess: on the new text five of five runs (those three, both
skipped, both given) wrote what was given and the default for what was skipped, and the run
with the author named in the request asked for the licence alone. Those eight packages play
too.

Not built: editing an existing package, which a tool beside it does with `checkContent` as its
check; layout for Drag and Drop and Crossword; and any judgement of whether content is right, which
Expand Down
14 changes: 13 additions & 1 deletion packages/author/lib/schema.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,20 @@ export function withSection(text, section, name) {
return `${text.slice(0, start)}${section}${text.slice(end + GENERATED_END.length)}`
}

/**
* What a source of any content type names beside its fields. A type file's example shows only
* `type` and `params`, and a chat that copies it left the author out, the one of them it has no
* value of its own for (#182). The example says so here rather than holding them: a name written
* in it would be copied as the author and build, where the model is to ask for what the user
* has not given, and to write for a name they skip the one it knows them by, or "Unknown", and
* for a licence they skip `U`, each on its own: what they gave stays. A part other content
* holds has none: it is sub-content.
*/
export const SOURCE_FIELDS = 'The example is `type` and `params` alone, and `params` holds the fields below. A source also names its own `title`, `language`, `license` and `authors`, all four required: the build refuses a source that leaves out any of them. The author\'s name and the licence are the user\'s: ask for what they have not given. For a name they skip, write the one you know them by, or "Unknown"; for a licence they skip, `U`.'

/**
* The generated section of a type file: the fields, under a heading, between markers that a
* refresh rewrites.
* refresh rewrites, and for a content type what a source names beside them.
* @param {any} library its `library.json`
* @param {any[]} semantics
* @param {SchemaOptions} [options]
Expand All @@ -234,6 +245,7 @@ export function schemaMarkdown(library, semantics, options = {}) {
'',
`## Fields of ${library.machineName} ${library.majorVersion}.${library.minorVersion}`,
'',
...(library.runnable ? [SOURCE_FIELDS, ''] : []),
...fields,
'',
interfaceTexts
Expand Down
14 changes: 13 additions & 1 deletion packages/author/tests/layout.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { join } from 'node:path'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { buildPackage, SourceError } from '../lib/author.mjs'
import { imageSize } from '../lib/media.mjs'
import { GENERATED_END, GENERATED_START, schemaLines, schemaMarkdown, withSection } from '../lib/schema.mjs'
import { GENERATED_END, GENERATED_START, schemaLines, schemaMarkdown, SOURCE_FIELDS, withSection } from '../lib/schema.mjs'
import { jpeg, png } from './helpers/media'

const META = { title: 'Layout', language: 'en', license: 'U', authors: [{ name: 'Ann Author', role: 'Author' }] }
Expand Down Expand Up @@ -276,6 +276,18 @@ describe('the schema a source is written from', () => {
expect(markdown.startsWith(`${GENERATED_START}\n\n## Fields of H5P.Test 1.2\n`)).toBe(true)
expect(markdown.endsWith(`\`h5p-author schema H5P.Test --all\` lists them, for a source to set one.\n\n${GENERATED_END}`)).toBe(true)
})

it('says what a content type\'s source names beside its fields, the author asked of the user, and not for a part (#182)', () => {
const type = schemaMarkdown({ machineName: 'H5P.Test', majorVersion: 1, minorVersion: 2, runnable: 1 }, semantics)
expect(type.startsWith(`${GENERATED_START}\n\n## Fields of H5P.Test 1.2\n\n${SOURCE_FIELDS}\n\n- `)).toBe(true)
for (const field of ['`title`', '`language`', '`license`', '`authors`']) expect(SOURCE_FIELDS).toContain(field)
expect(SOURCE_FIELDS).toContain('all four required')
expect(SOURCE_FIELDS).toContain('The example is `type` and `params` alone')
expect(SOURCE_FIELDS).toContain('ask for what they have not given')
expect(SOURCE_FIELDS).toContain('For a name they skip, write the one you know them by, or "Unknown"')
expect(SOURCE_FIELDS).toContain('for a licence they skip, `U`')
expect(schemaMarkdown({ machineName: 'H5P.Test', majorVersion: 1, minorVersion: 2, runnable: 0 }, semantics)).not.toContain(SOURCE_FIELDS)
})
})

describe('what a file is', () => {
Expand Down
32 changes: 29 additions & 3 deletions skills/h5p-author/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,22 @@ With this text alone and none of its files beside it, open https://missing-eleme
first and take every address from it: it writes out in full each file this text names and each
file step 3 fetches, and a fetch tool may refuse an address put together from a name.

## 1. Choose the content type with the user
Work in this order, one question at a time: the content type, chosen with the user; then the
author and licence, which they give or skip; then the source; then the build, the best way this
environment allows.

Read [the brief](./references/authoring.md) once. If the user named no type, propose one or
two that fit the material and objective, a sentence each on why, and wait for their choice.
## 1. Choose the content type, then the author and licence, with the user

Read [the brief](./references/authoring.md) once. Unless the user named a type from the table
below, propose one or two that fit the material and objective, a sentence each on why, ask them
to choose, and wait: "a quiz" or "flash cards" says what they want, not which type. Ask nothing
else in that message.

Once they have chosen, ask in a message of its own for the author's name and the licence, only
for what they have not given yet, and say they may skip; then wait. What they gave stays as they
gave it. A name they skip is the one you know them by, or "Unknown"; a licence they skip is `U`
(undisclosed). Every source names its author and the build refuses one without, but never write
a name made up for them.

| Type | Use it for |
|---|---|
Expand Down Expand Up @@ -75,6 +87,9 @@ from what you know of the type: the build says, for each place that is wrong, wh
}
```

- Every source names its own `title`, `language`, `license` and `authors` beside `type` and
`params`, as above, whatever a type file's example leaves out; the author and licence are the
ones step 1 settled.
- `params` holds only fields that differ from their defaults. Never interface texts (Check,
Retry…): they come from the libraries' translations for `language`.
- Text is plain, or markup with only the tags a field marked `html` lists.
Expand All @@ -87,6 +102,17 @@ from what you know of the type: the build says, for each place that is wrong, wh

## 3. Build

Build the best way this environment allows, and tell the user which you take:

- **Here, with npm**: a shell that reaches the npm registry (Claude Code, a terminal). The
command below.
- **Here, from two files**: Node runs and files can be fetched, but npm cannot install, as in
ChatGPT. *If it cannot install here*, below.
- **In the user's browser**: nothing here runs, or nothing fetches, as in Gemini or a chat with
no tools. *The build page*, below, with no attempt here first.

Take the first that applies, and the next if it fails.

Build in a working folder of your own, not in the folder the user named:

```bash
Expand Down
7 changes: 5 additions & 2 deletions skills/h5p-author/references/authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ Use what the user already gave. Ask for what is missing and matters:
texts too, from their own translations, which are often incomplete.
- **Media**, for a type that needs them: files the user has, or web addresses they may use,
with who made them and under which licence.
- **Author and licence**: the author's name, and the licence for the whole, an H5P code: `U`
- **Author and licence**, asked once the type is chosen: the author's name, which every source
needs, and the licence for the whole, an H5P code: `U`
(undisclosed, when unknown), `CC BY`, `CC BY-SA`, `CC BY-ND`, `CC BY-NC`, `CC BY-NC-SA`,
`CC BY-NC-ND`, `CC0 1.0`, `CC PDM`, `GNU GPL`, `PD`, `ODC PDDL` or `C`; `licenseVersion`
`4.0` for a CC BY one. Never choose a licence the user has not.
`4.0` for a CC BY one. The user may skip either: a name they skip is the one you know them
by, or "Unknown", and a licence they skip is `U`. What they gave stays. Never make up a name,
or choose a licence the user has not.
- **A pass mark**, for scored content an LMS records, and what a learner who passes or fails
is told.
- **Where it goes**: an LMS, a website, a file to hand out.
Expand Down
2 changes: 2 additions & 0 deletions skills/h5p-author/references/types/H5P.Accordion.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Text in panels that open on a click, for reference material a learner looks up.

## Fields of H5P.Accordion 1.0

The example is `type` and `params` alone, and `params` holds the fields below. A source also names its own `title`, `language`, `license` and `authors`, all four required: the build refuses a source that leaves out any of them. The author's name and the licence are the user's: ask for what they have not given. For a name they skip, write the one you know them by, or "Unknown"; for a licence they skip, `U`.

- `panels` list 1–100 of, required — Panels
- `title` text, required — Title
- `content` sub-content: H5P.AdvancedText, required — Content type
Expand Down
2 changes: 2 additions & 0 deletions skills/h5p-author/references/types/H5P.Audio.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ An audio player. On its own it suits a listening task beside other content; in a

## Fields of H5P.Audio 1.5

The example is `type` and `params` alone, and `params` holds the fields below. A source also names its own `title`, `language`, `license` and `authors`, all four required: the build refuses a source that leaves out any of them. The author's name and the licence are the user's: ask for what they have not given. For a name they skip, write the one you know them by, or "Unknown"; for a licence they skip, `U`.

- `files` audio files, required — Source files
- `playerMode` one of "minimalistic" | "full" | "transparent" = "minimalistic" — Player mode: Select the layout of the player.
- `fitToWrapper` boolean = false; only when playerMode is "minimalistic" or playerMode is "full" — Fit to wrapper
Expand Down
2 changes: 2 additions & 0 deletions skills/h5p-author/references/types/H5P.Blanks.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Text with gaps the learner types the missing words into. For recall of exact wor

## Fields of H5P.Blanks 1.14

The example is `type` and `params` alone, and `params` holds the fields below. A source also names its own `title`, `language`, `license` and `authors`, all four required: the build refuses a source that leaves out any of them. The author's name and the licence are the user's: ask for what they have not given. For a name they skip, write the one you know them by, or "Unknown"; for a licence they skip, `U`.

- `media` group — Media
- `type` sub-content: H5P.Image | H5P.Video | H5P.Audio — Type: Optional media to display above the question.
- `disableImageZooming` boolean = false; only when type is "H5P.Image 1.1" — Disable image zooming
Expand Down
2 changes: 2 additions & 0 deletions skills/h5p-author/references/types/H5P.BranchingScenario.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ A story in which the learner's choices lead to different paths and endings: deci

## Fields of H5P.BranchingScenario 1.11

The example is `type` and `params` alone, and `params` holds the fields below. A source also names its own `title`, `language`, `license` and `authors`, all four required: the build refuses a source that leaves out any of them. The author's name and the licence are the user's: ask for what they have not given. For a name they skip, write the one you know them by, or "Unknown"; for a licence they skip, `U`.

- `branchingScenario` group — Branching Scenario Editor
- `title` text, required — Title
- `startScreen` group — Start screen
Expand Down
2 changes: 2 additions & 0 deletions skills/h5p-author/references/types/H5P.Column.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ A page of content one below another: text, pictures, video and questions, in the

## Fields of H5P.Column 1.22

The example is `type` and `params` alone, and `params` holds the fields below. A source also names its own `title`, `language`, `license` and `authors`, all four required: the build refuses a source that leaves out any of them. The author's name and the licence are the user's: ask for what they have not given. For a name they skip, write the one you know them by, or "Unknown"; for a licence they skip, `U`.

- `content` list 1+ of, required — List of Column Content
- `content` sub-content: H5P.Accordion | H5P.Agamotto | H5P.Audio | H5P.AudioRecorder | H5P.Blanks | H5P.Chart | H5P.Collage | H5P.CoursePresentation | H5P.Dialogcards | H5P.DocumentationTool | H5P.DragQuestion | H5P.DragText | H5P.Essay | H5P.GuessTheAnswer | H5P.Table | H5P.AdvancedText | H5P.IFrameEmbed | H5P.Image | H5P.ImageHotspots | H5P.ImageHotspotQuestion | H5P.ImageSlider | H5P.InteractiveVideo | H5P.Link | H5P.MarkTheWords | H5P.MemoryGame | H5P.MultiChoice | H5P.Questionnaire | H5P.QuestionSet | H5P.Row | H5P.SingleChoiceSet | H5P.Summary | H5P.Timeline | H5P.TrueFalse | H5P.Video | H5P.MultiMediaChoice, required — Content
- `useSeparator` one of "auto" | "disabled" | "enabled" = "auto" — Separate content with a horizontal ruler
Expand Down
2 changes: 2 additions & 0 deletions skills/h5p-author/references/types/H5P.CoursePresentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ Slides with text, pictures, video and questions; a summary slide with the score

## Fields of H5P.CoursePresentation 1.27

The example is `type` and `params` alone, and `params` holds the fields below. A source also names its own `title`, `language`, `license` and `authors`, all four required: the build refuses a source that leaves out any of them. The author's name and the licence are the user's: ask for what they have not given. For a name they skip, write the one you know them by, or "Unknown"; for a licence they skip, `U`.

- `presentation` group
- `slides` list of
- `elements` list of
Expand Down
2 changes: 2 additions & 0 deletions skills/h5p-author/references/types/H5P.Dialogcards.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Flash cards: a prompt on the front, the answer on the back, turned by the learne

## Fields of H5P.Dialogcards 1.9

The example is `type` and `params` alone, and `params` holds the fields below. A source also names its own `title`, `language`, `license` and `authors`, all four required: the build refuses a source that leaves out any of them. The author's name and the licence are the user's: ask for what they have not given. For a name they skip, write the one you know them by, or "Unknown"; for a licence they skip, `U`.

- `title` html: strong em code — Heading
- `mode` one of "normal" | "repetition" = "normal" — Mode: Mode of presenting the dialog cards
- `description` html: strong em code — Task description
Expand Down
2 changes: 2 additions & 0 deletions skills/h5p-author/references/types/H5P.Dictation.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ The learner hears sentences and types them; the content compares what was typed

## Fields of H5P.Dictation 1.3

The example is `type` and `params` alone, and `params` holds the fields below. A source also names its own `title`, `language`, `license` and `authors`, all four required: the build refuses a source that leaves out any of them. The author's name and the licence are the user's: ask for what they have not given. For a name they skip, write the one you know them by, or "Unknown"; for a licence they skip, `U`.

- `media` group — Media
- `type` sub-content: H5P.Image | H5P.Video | H5P.Audio — Type: Optional media to display above the question.
- `disableImageZooming` boolean = false; only when type is "H5P.Image 1.1" — Disable image zooming
Expand Down
2 changes: 2 additions & 0 deletions skills/h5p-author/references/types/H5P.DragText.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Text with gaps the learner fills by dragging words from a list. Easier than typi

## Fields of H5P.DragText 1.10

The example is `type` and `params` alone, and `params` holds the fields below. A source also names its own `title`, `language`, `license` and `authors`, all four required: the build refuses a source that leaves out any of them. The author's name and the licence are the user's: ask for what they have not given. For a name they skip, write the one you know them by, or "Unknown"; for a licence they skip, `U`.

- `media` group — Media
- `type` sub-content: H5P.Image | H5P.Video | H5P.Audio — Type: Optional media to display above the question.
- `disableImageZooming` boolean = false; only when type is "H5P.Image 1.1" — Disable image zooming
Expand Down
2 changes: 2 additions & 0 deletions skills/h5p-author/references/types/H5P.Essay.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ The learner writes a text, scored by the keywords it contains, with feedback per

## Fields of H5P.Essay 1.5

The example is `type` and `params` alone, and `params` holds the fields below. A source also names its own `title`, `language`, `license` and `authors`, all four required: the build refuses a source that leaves out any of them. The author's name and the licence are the user's: ask for what they have not given. For a name they skip, write the one you know them by, or "Unknown"; for a licence they skip, `U`.

- `media` group — Media
- `type` sub-content: H5P.Image | H5P.Video | H5P.Audio — Type: Optional media to display above the question.
- `disableImageZooming` boolean = false; only when type is "H5P.Image 1.1" — Disable image zooming
Expand Down
Loading
Loading