Build Genially

KINDAback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

An authoring tool for interactive presentations and infographics, where the interesting constraint is that interactivity authored in a visual editor usually only runs inside that editor's player, and content that cannot be exported or made accessible is content with an expiry date.

estimated effort multi-daythe files for this build are in the project pack

ModelInteractions as a declarative state machine over elementsRuntimeA small player consuming the declarationAccessibilityKeyboard and screen reader paths derived from the same declarationExportSelf-contained output including the playerRuntime stackTypeScript with local documents

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the editor and builds the player.

    Get it nodejs.org, or nvm install 22. open ↗

    Verify node --version prints v22 or higher

  2. installfree

    Why Keyboard and announcement behaviour cannot be verified by reading code, and the failures are specific to how assistive technology interprets state changes.

    Get it Your platform's screen reader, plus enough familiarity to navigate a page with it.

    Verify You can traverse a simple interactive page using only the screen reader

  3. have readyfree

    Why The reduced-motion and export reviews are about whether the content still communicates, and a demonstration of shapes has nothing to lose.

    Get it Build something you would actually publish, with at least eight interactive elements and a point to make.

    Verify A piece exists with eight interactions and a stated purpose

  4. have readyfree

    Why Embeds break on real pages with real stylesheets, and testing against a blank page demonstrates nothing.

    Get it A page with aggressive global styles, a restrictive content policy and other embedded content.

    Verify The embed is tested inside it and renders correctly

  5. decidefree to read

    Why Focus order, announcements and alternative text are enforced in the editor, and adding them after authoring means revisiting every piece.

    Get it Pick the standard you will meet, write down what it requires of an interactive piece, and encode the checks.

    Verify A written standard exists and its checks are enforced at save

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- documents(id, title, canvas_size, created_at)
- elements(id, document_id, kind, x, y, width, height, z, content_json, alt_text)
- states(id, document_id, name, is_initial) · the states an interactive piece can be in
- interactions(id, document_id, trigger_kind, source_element_id, from_state_id, to_state_id, effects_json)
- focus_order(document_id, ordinal, element_id) · explicit, because derived order is usually wrong
- exports(id, document_id, kind, path, includes_player, at)
- An interaction is a transition between named states rather than a script attached to an element, which is what makes the whole piece testable and traversable by keyboard.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
DOCUMENTS_DIRrequired~/Documents/interactiveAuthored pieces. A document, stored as one.
EXPORT_DIRrequired./exportsSelf-contained bundles including the player.
BUNDLE_PLAYERrequiredalwaysPresent as a constant. A hosted player is an expiry date on the content.
REQUIRE_ALT_TEXTrequiredalwaysEnforced at save for elements carrying meaning.
MAX_ANIMATION_MSrequired400A long transition is an unresponsive interface.
INTERACTION_REPORTINGrequiredoffOff by default. Learners' interaction data is not collected without asking.

The build, in order

  1. Interactions as data, not as scripts

    What a click does is described rather than programmed.

    1. A script per element rules out everything the later phases need.

      Files src/interactions.ts

    2. An unreachable layer is a mistake nobody finds by clicking.

      Files src/analyse.tssrc/analyse.test.ts

    3. Three implementations diverge and only one gets accessibility.

      Files src/interactions.ts

    done when · tick each as it passes
    watch out
    • Attaching a script to each element makes the piece impossible to traverse without executing it, which rules out keyboard navigation, screen reader support, testing and export in one decision. Describe transitions declaratively so the whole interaction graph can be walked.
  2. Usable without a mouse

    Every interaction can be reached and triggered by keyboard.

    1. Derived order follows the document, not the meaning.

      Files src/focus.ts

    2. A silent change is invisible to anyone not watching the screen.

      Files src/announce.ts

    3. Enforced at save, not suggested in documentation.

      Files src/elements.ts

    done when · tick each as it passes
    watch out
    • Hotspots positioned visually give a focus order derived from the document that bears no relation to how the piece reads, so keyboard users traverse it in an order that makes no sense. Make the focus order explicit and part of the document rather than derived from element positions.
  3. Animation that can be turned off

    Motion is optional and the piece still communicates.

    1. It is set for medical reasons rather than as a preference.

      Files src/motion.ts

    2. Assuming graceful degradation is how information disappears.

      Files src/review.ts

    3. A long transition is an unresponsive interface.

      Files src/motion.ts

    done when · tick each as it passes
    watch out
    • Building meaning into an animation, such as an arrow that only appears while a transition plays, means the piece loses information for anyone with reduced motion enabled, and that is a preference people set for medical reasons. Check the no-motion version explicitly rather than assuming it degrades gracefully.
  4. A player small enough to ship

    The piece runs from a self-contained export.

    1. A hosted player is an expiry date on the content.

      Files src/export.ts

    2. It ships with every export. Measure and state its size.

      Files player/

    3. From a file, with networking disabled.

      Files tests/export-offline.test.ts

    done when · tick each as it passes
    watch out
    • An export that references a hosted player means the content stops working when the account lapses or the platform changes its addresses, which for educational material used for years is a real loss. Bundle the player with the export and test it from a file with networking disabled.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more design.