HTML with answers (no backend)
Write the exercise with its answers, add one script, and the page grades itself in the browser.
Trade-off: the answers are in the page source. Use this mode for self-practice, homework pages, blogs, prototypes and offline use. For tests and anything with stakes, use HTML + backend.
-
Load the bundle (it registers
<astl-player>, the built-in components and the in-browser compiler):<script type="module" src="https://cdn.jsdelivr.net/npm/astrolabe@0.1/dist/cdn/astrolabe.js"></script><style>astl-player:not(:defined) { visibility: hidden; }</style>Optional:
dist/astrolabe.cssholds the same--astl-*tokens for styling the page around the player. -
Put an
<astl-doc>inside<astl-player>. Use the content format:<astl-player locale="en" persist><astl-doc lang="en"><astl-page id="p1" label="Animals"><p>An elephant is <astl-gap id="g1" answer="grey"><astl-alt>gray</astl-alt></astl-gap>, and a trout is a <astl-gap id="g2" answer="fish"></astl-gap>.</p><astl-choice id="q1" multiple scoring="per-option"><astl-prompt>Which animals are mammals?</astl-prompt><astl-option id="a" correct>Otter</astl-option><astl-option id="b">Trout</astl-option><astl-option id="c" correct>Mole</astl-option></astl-choice></astl-page><astl-page id="p2" label="Numbers"><p>Half of one is <astl-gap id="g3" type="number" answer="0.5"></astl-gap>.</p><astl-choice id="q2"><astl-prompt>How many legs does a spider have?</astl-prompt><astl-option id="a">Six</astl-option><astl-option id="b" correct>Eight</astl-option><astl-option id="c">Ten</astl-option></astl-choice></astl-page></astl-doc></astl-player> -
Open the page over
http:orhttps:(localhostworks;file:does not, because browsers load module scripts and WebCrypto only from real origins). The player compiles the source in the browser, hides it, and shows the exercise with "Check" (practice mode). Nothing is sent over the network.
What happens
Section titled “What happens”astrolabe.jsregisters acompileSourcehook: the engine compiles your source into a view and an answer key in memory and grades withlocalChecker. It uses a fixed public secret and the page path as salt, so ids stay stable across reloads (the answers are in the page anyway, so the secret protects nothing here).- If the source has errors (a gap without an answer, a choice without a correct option), the player shows them
instead of the exercise: a short notice, then each error in the player's
locale(also logged to the browser console). Runastl validate page.htmlto see them in the terminal (it checks every<astl-doc>of the page). localesets the UI language (buttons, messages);langon<astl-doc>is the content language used for grading (Polish decimal comma, diacritics).
Options
Section titled “Options”Attribute on <astl-player> |
Meaning |
|---|---|
locale |
UI language, e.g. pl, en. Default: the browser's language. |
theme |
light, dark, hc (high contrast) or auto (default, follows the system). |
persist |
Save progress in the browser (localStorage) and restore it after a reload. |
Listen to events if you want to store progress yourself (astl-snapshot, astl-result, astl-page). Every
attribute, property, method and event: Player reference.
Build it yourself instead of the bundle
Section titled “Build it yourself instead of the bundle”The bundle is a thin wrapper. With a bundler:
import { createEngine, localChecker } from '@astrolabe/engine';import { definePlayer } from '@astrolabe/player';import { builtInDefinitions } from '@astrolabe/components/definitions';import { builtInElements } from '@astrolabe/components/elements';
// Answers are public in this mode, so a fixed secret is fine and keeps ids stable across reloads.const engine = createEngine({ components: builtInDefinitions, secret: 'astrolabe-in-browser-key' });
definePlayer({ elements: builtInElements, async compileSource(source) { const result = await engine.compile(source, { salt: location.pathname }); if (!result.ok) { const errors = result.issues.filter((i) => i.severity === 'error'); throw new Error(errors.map((i) => engine.describe(i, 'en')).join('\n')); } return { view: result.view, checker: localChecker(engine, result.key) }; },});Runnable example: examples/static-html in the repository (pnpm dev:static serves it).