Skip to content

Latest commit

 

History

625 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

qti3

qti3 is a dependency-light, framework-neutral TypeScript reference implementation for QTI 3 assessment items. The core engine and CLI ship with zero third-party runtime dependencies.

Use the interactive qti3 manual to load reference fixtures, QTI packages, or item XML and inspect rendering, scoring, validation, state, diagnostics, and accessibility evidence. The shared vocabulary gallery provides runnable matrix fixtures for presentation-class review.

The project publishes packages on npm for parsing, validating, rendering, scoring, serializing, restoring, and testing QTI 3 items. The core has no UI framework dependency.

qti3 covers QTI item and question-type conformance. Host products provide runners, controllers, LMS shells, candidate attempt policy, analytics, proctoring, rostering, and gradebook integrations.

Longsight maintains qti3 as part of its open-source educational software work. The implementation also supports the open-standards direction used by QFlowLearn's QTI 3 assessment platform. Product-specific authoring and delivery remain outside this repository.

Project shape

qti3 is item-focused: the core owns QTI semantics, the player renders one item at a time, tooling proves conformance and accessibility behavior, and host products own the surrounding assessment application.

flowchart LR
  content["QTI item XML<br/>and package assets"]
  host["Host product<br/>runner, policy, LMS shell, analytics"]
  review["CI, release, and<br/>certification checks"]

  subgraph qti3["qti3 packages"]
    core["core<br/>parse, validate, process,<br/>score, serialize state"]
    player["player<br/>native web component<br/>item renderer"]
    fixtures["fixtures<br/>synthetic reference items"]
    conformance["conformance<br/>fixture runner and<br/>support matrix"]
    a11y["a11y<br/>keyboard and accessibility<br/>proof contracts"]
    cli["cli<br/>validate, score, inspect,<br/>write fixtures"]
    pnp["pnp<br/>normalize and resolve<br/>candidate preferences"]
    writer["writer<br/>QTI-shaped authoring<br/>XML output"]
    migrator["migrator<br/>QTI 1.2 and 2.x<br/>to QTI 3 authoring"]
    transcoder["transcoder<br/>QTI 3 to versioned<br/>standard and LMS profiles"]
  end

  content --> core
  content --> cli
  content --> migrator
  content --> transcoder
  core --> player
  core --> cli
  core --> pnp
  core --> writer
  writer --> migrator
  writer --> transcoder
  fixtures --> conformance
  fixtures --> cli
  conformance --> review
  a11y --> review
  cli --> review
  pnp --> host
  writer --> host
  migrator --> host
  transcoder --> host
  player --> host
  core --> host
Loading

Interaction families

The parser stores each interaction in the normalized QtiInteraction model and validates its response contract. The browser player selects a renderer from the response shape and interaction model.

Family Interactions Shared implementation
Identifier choices Choice, Inline Choice, Hot Text, Hotspot Choice parsing, identifier response checks, choice metadata
Ordered choices Order, Graphic Order Ordered identifier contract and reorder behavior
Pairing and matching Associate, Match, Graphic Associate Source/target choices, token controls, selected pair chips
Gap assignment Gap Match, Graphic Gap Match Source choices assigned to text or graphic gaps
Graphic and coordinate UI Hotspot, Graphic Order, Graphic Associate, Select Point, Position Object Responsive surfaces, object/img/picture assets, hotspot/point placement
Text responses Text Entry, Extended Text String, numeric, and record capture; Extended Text collections
File responses Upload, Drawing File response contract
Scalar and host-controlled Slider, Media, End Attempt, Portable Custom Small specialized renderers and host event bridges

Question-type support

The support matrix tracks the current public QTI 3 item interaction set described by the 1EdTech QTI 3 Implementation Guide with element names from the QTI 3 XML Binding and tracked internally as the QTI 3.0.1 ASI item profile.

In this README, "Supported" has a specific meaning. The interaction must parse into the typed model, validate against its response and element contract, render in the browser player, and process responses with scores or external grading requirements. It must also ship with a public reference fixture, pass fixture and conformance tests, include accessibility metadata, and run through browser rendering tests.

Spec interaction QTI element qti3 status Evidence
Choice qti-choice-interaction Supported choice-reference.xml; core, fixture, conformance, a11y, browser tests
Text Entry qti-text-entry-interaction Supported textEntry-reference.xml; core, fixture, conformance, a11y, browser tests
Extended Text qti-extended-text-interaction Supported extendedText-reference.xml; core, fixture, conformance, a11y, browser tests
Gap Match qti-gap-match-interaction Supported gapMatch-reference.xml; core, fixture, conformance, a11y, browser tests
Hotspot qti-hotspot-interaction Supported hotspot-reference.xml; core, fixture, conformance, a11y, browser tests
Hot Text qti-hottext-interaction Supported hottext-reference.xml; core, fixture, conformance, a11y, browser tests
Inline Choice qti-inline-choice-interaction Supported inlineChoice-reference.xml; core, fixture, conformance, a11y, browser tests
Match qti-match-interaction Supported match-reference.xml; core, fixture, conformance, a11y, browser tests
Order qti-order-interaction Supported order-reference.xml; core, fixture, conformance, a11y, browser tests
Graphic Order qti-graphic-order-interaction Supported graphicOrder-reference.xml; core, fixture, conformance, a11y, browser tests
Associate qti-associate-interaction Supported associate-reference.xml; core, fixture, conformance, a11y, browser tests
Graphic Associate qti-graphic-associate-interaction Supported graphicAssociate-reference.xml; core, fixture, conformance, a11y, browser tests
Graphic Gap Match qti-graphic-gap-match-interaction Supported graphicGapMatch-reference.xml; core, fixture, conformance, a11y, browser tests
Media qti-media-interaction Supported media-reference.xml; core, fixture, conformance, a11y, browser tests
Position Object qti-position-object-interaction Supported positionObject-reference.xml; core, fixture, conformance, a11y, browser tests
Select Point qti-select-point-interaction Supported selectPoint-reference.xml; core, fixture, conformance, a11y, browser tests
Slider qti-slider-interaction Supported slider-reference.xml; core, fixture, conformance, a11y, browser tests
Upload qti-upload-interaction Supported upload-reference.xml; core, fixture, conformance, a11y, browser tests
Drawing qti-drawing-interaction Supported drawing-reference.xml; core, fixture, conformance, a11y, browser tests
Portable Custom qti-portable-custom-interaction Supported host contract portableCustom-reference.xml; core, fixture, conformance, a11y, browser tests
Custom qti-custom-interaction Deprecated diagnostic Parsed for explicit warning; not a supported runtime target
End Attempt qti-end-attempt-interaction Supported endAttempt-reference.xml; core, fixture, conformance, a11y, browser tests

For automated review, the same support matrix is available as JSON:

node packages/cli/dist/index.js support-matrix

Goals

  • Implement the latest public QTI 3 item behavior explicitly, tracking QTI 3.0.1 ASI documents where applicable.
  • Support all QTI 3 interaction/question types in the target item profile.
  • Make scoring and response processing runnable in Node without a browser.
  • Publish an accessible, style-neutral web component player for host applications.
  • Publish a reusable conformance test suite.
  • Load QTI package ZIPs and assessment-test item references for import tests and item-focused tooling.
  • Transcode QTI 3 items and packages to explicit, versioned QTI 1.2, QTI 2.1, QTI 2.2, and product-specific import profiles.
  • Resolve host-provided QTI 3 PNP data into player-neutral delivery intents. Hosts retain responsibility for identity, storage, authorization, and institutional policy.
  • Keep qti3-core and qti3-cli free of third-party runtime dependencies.
  • Make unsupported or invalid behavior visible through structured diagnostics.

Non-goals

  • The core and browser player do not depend on React, Vue, or another UI framework.
  • The browser player uses native custom elements without Lit.
  • The project does not provide a full assessment-test runner, reusable LMS controller, navigation UI, or delivery shell. The LMS, assessment engine, or harness owns that.
  • The project does not provide shared stimulus delivery (S-*), full test delivery (T-*), timing policy, proctoring, analytics, rostering, gradebook, or LTI integration.
  • The PNP package does not fetch, store, transmit, or authorize candidate preference records. Hosts provide PNP data and own privacy, consent, policy, and service access.
  • The project does not provide product chrome, branding, candidate navigation, or a host product design system.
  • Production configuration must be explicit. The project should fail fast instead of using hidden fallbacks.
  • QTI XML is not compiled as framework templates.
  • There is no global singleton state store. Multiple players should not share a brain.
  • Runtime XSD validation is out of scope.

Packages

Package Path Purpose
@longsightgroup/qti3-core packages/core Zero-third-party-runtime-dependency parser, typed model, validation, processing, scoring, state
@longsightgroup/qti3-player packages/player Native custom element browser player
@longsightgroup/qti3-player-react packages/player-react React adapter for the native web component
@longsightgroup/qti3-player-preact packages/player-preact Preact adapter for the native web component
@longsightgroup/qti3-conformance packages/conformance Fixture runner and support matrix tooling
@longsightgroup/qti3-a11y packages/a11y Accessibility contracts and automated checks
@longsightgroup/qti3-fixtures packages/fixtures QTI item fixtures and expected outcomes
@longsightgroup/qti3-pnp packages/pnp Dependency-free QTI 3 PNP parser, normalizer, resolver, and diagnostics
@longsightgroup/qti3-writer packages/writer Framework-neutral QTI-shaped authoring XML and item-bank package writer with typed diagnostics
@longsightgroup/qti3-migrator packages/migrator QTI 1.2 and QTI 2.x package/item migration into QTI 3 authoring items, XML, and package input
@longsightgroup/qti3-transcoder packages/transcoder Profile-driven QTI 3 output for QTI 1.2, QTI 2.1, QTI 2.2, Canvas Classic/New Quizzes, and Moodle XML
@longsightgroup/qti3-cli packages/cli Zero-third-party-runtime-dependency validation, trusted scoring, delivery preparation, package inspection, and evidence CLI

QTI package and assessment-test support belongs in tooling, fixtures, and examples for import, inspection, validation, and item loading. The browser player renders one assessment item at a time.

Core's batch package parsers return an xmlFiles inventory with root names, namespaces, and syntax diagnostics, including unreferenced XML files. CLI inspection uses this inventory to avoid parsing those files again for discovery. See batch package import.

The transcoder converts QTI 3 items and packages through versioned profiles. Standard QTI output and product-specific compatibility use separate profiles. Each conversion returns typed mapping diagnostics instead of selecting an LMS dialect or fallback automatically.

Framework adapters wrap the native web component or core API. The repository includes React and Preact adapters. Other adapters can be added without moving framework dependencies into qti3-core.

The browser player is a native web component:

<script type="module" src="/qti3-player.js"></script>
<qti-assessment-item-player id="player"></qti-assessment-item-player>
const player = document.getElementById("player");

await player.loadXml(xml, {
  status: "interacting",
  sessionOptions: {
    randomSeed: "candidate-42-item-1",
  },
  sessionControl: {
    validateResponses: true,
    requireScoredResponses: true,
    showFeedback: false,
  },
});

// Attempt JSON stores QTI state, not host functions or capability registries. Pass the same
// sessionOptions again when loading saved state into a new player instance. reset() and restore()
// on this player retain the options object supplied above.

await player.loadUrl("/items/item-1.xml", {
  fetchXml: async (url) => {
    const response = await fetch(url);
    if (!response.ok) throw new Error(`Unable to load ${url}`);
    return response.text();
  },
});

await player.loadXml(packageItemXml, {
  resolveAsset: (url) => packageAssetUrlFor(url),
  resolveStylesheet: (stylesheet) => ({
    href: packageStylesheetUrlFor(stylesheet.href),
  }),
});

// Host-controlled opt-in. qti3 preserves qti-keyword-emphasis by default, but only
// applies extra visual emphasis when the host has resolved candidate AfA/PNP support.
player.keywordEmphasisEnabled = true;
// Equivalent DOM API:
player.setAttribute("data-keyword-emphasis", "true");

player.addEventListener("qti-statechange", (event) => {
  saveState(event.detail.state);
});

player.addEventListener("qti-responsechange", (event) => {
  console.log(event.detail.responseIdentifier, event.detail.value);
});

player.addEventListener("qti-validation", (event) => {
  console.log(event.detail.validationMessages, event.detail.state);
});

resolveAsset is a host hook for package or virtual-file environments. The player calls it for relative src, href, and data asset URLs after rendering the item, and also when hosts resolve companion-material file references through getCompanionMaterialsResolution() or catalog support content through getCatalogDeliveryResolution(). Items whose assets are available at browser URLs can omit it. Use the hook for package-backed media, graphic, and drawing assets so controls and serialized responses resolve authored references.

qti-stylesheet delivery is a separate host contract. Core preserves stylesheet metadata, and the browser player attaches item stylesheets only when loadXml / loadUrl receives resolveStylesheet. The hook must return a candidate-safe stylesheet URL for package-local CSS or undefined to decline delivery. Package import, path validation, authorization, immutable asset preservation, and unsafe URL rejection remain host responsibilities.

When resolveStylesheet is omitted, the player treats stylesheets as disabled. It does not attach them or emit player.stylesheet.unresolved diagnostics.

Interaction response contracts

  • Text Entry accepts a single string, integer, or float response, or a numeric record. Extended Text also accepts multiple and ordered collections with authored max-strings. Both interactions honor base; numeric records retain the original text and precision fields. Use string-identifier to retain raw text alongside a numeric response. Restored scalar values use the authored base; records and companion responses preserve the entered text.
  • Associate and Graphic Associate use unordered pair values; Match, Gap Match, and Graphic Gap Match use directedPair values. Each accepts single or multiple cardinality. Graphic Gap Match requires graphical hotspot targets; use Gap Match for inline text gaps.
  • Core response validation enforces authored minimums, QTI default maximums, and per-choice match-min/match-max bounds. A correct response alone does not make an answer required. The player defaults sessionControl.requireScoredResponses to true; set it to false to use only QTI constraints. An explicitly authored zero minimum remains optional under either policy.
  • qti-media-interaction records play experiences as a single / integer response. The player supports the QTI shared vocabulary data-qti-media-player-controls tokens none, default, play, rewind, captions, and audioDescription. none suppresses native media controls; all other recognized tokens render native browser controls and are preserved on the rendered <audio> or <video> element for host styling or custom enhancement. The player also supports data-qti-media-player-pause-delay and data-qti-media-player-pause-duration as second-based timers around playback start and user-initiated pauses.
  • qti-slider-interaction uses a typed numeric definition for bounds, step size, orientation, reverse direction, response validation, and keyboard operation. The player keeps display values and scored values on the same decimal-safe scale.
  • qti-drawing-interaction requires a single / file response and serializes candidate drawings as image file data URLs. The player exposes a native pen color input; the toolbar-palette-none interaction class hides it and locks the pen to black.
  • qti-portable-custom-interaction supports the Portable Custom Interaction (PCI) host contract: parsing and validating launch metadata, interaction markup, template/context bindings, stylesheets, catalog info, opaque suspend/resume state, and response/state events. The player exposes a qti3-portable-custom-host element with small launch metadata and emits qti-portable-custom-mount with the full parsed definition so a host-provided PCI runtime can attach the module. Production module loading, sandboxing, CSP, tenant allowlists, and audit policy remain host responsibilities.

Styling

The browser player ships structural styles for layout, focus visibility, forced-colors support, and accessible interaction behavior. Host products own product chrome, branding, layout density, typography, colors, page-level spacing, candidate navigation, and broader candidate experience styling.

The player renders in light DOM, so host CSS can style it directly:

qti-assessment-item-player {
  font:
    16px/1.5 system-ui,
    sans-serif;
  color: #1f2937;
}

qti-assessment-item-player .qti3-interaction {
  margin-block: 1rem;
}

qti-assessment-item-player .qti3-choice-option[data-selected="true"] {
  border-color: currentColor;
}

Rendered elements use qti3-* class names for player structure, such as qti3-player, qti3-item-body, qti3-interaction, and interaction-specific classes like qti3-choice, qti3-textEntry, and qti3-hotspot. Authored QTI shared-vocabulary classes that start with qti- are preserved on rendered interactions where applicable.

The player exposes theme-aware CSS custom properties for structural controls. For order interaction rows, hosts can set --qti3-order-row-border-color, --qti3-order-row-background, and --qti3-order-row-background-hover on the player or an ancestor. Their defaults use system colors, so they work in light mode, dark mode, and forced-colors environments.

For resolved Personal Needs and Preferences (PNP) data, use createPnpPlayerOptions() to apply keyword emphasis and exact catalog selections. The returned hostRequired data identifies remaining host work, including presenting catalog content when the player emits qti-catalogrequest.

QTI shared vocabulary classes define portable item presentation preferences. Classes such as qti-labels-none, qti-labels-decimal, qti-input-control-hidden, and qti-unselected-hidden are parsed, validated, preserved, and implemented according to the support matrix. Host applications provide product-specific CSS. The machine-readable support matrix is the source of truth for shipped shared vocabulary coverage. Inspect the sharedVocabularyClasses section for each class name, scope, interaction surface, support level, fixture evidence, and test evidence:

node packages/cli/dist/index.js support-matrix

See the 1EdTech QTI 3 Standardized Shared Vocabulary and CSS Classes document for the normative shared vocabulary and example CSS.

Platform

  • ESM-only packages.
  • Node.js 22+.
  • Modern browsers.
  • Deno 2+.
  • Light DOM for the default player, rendered into the page DOM so host CSS and tooling can inspect and style it directly.

Tooling choices

  • TypeScript 6+
  • pnpm
  • Vite 8+
  • Vitest
  • Playwright
  • axe-core
  • oxfmt
  • oxlint

Checks

Every change should pass the same release gate locally, in CI, and before publish:

pnpm release:check

pnpm release:check runs formatting, typecheck, lint, unit and conformance tests, accessibility checks, dependency policy, build, source-map validation, package export checks, transcoder evidence and legacy XSD validation, browser coverage, support metadata, and the built CLI fixture runner. It does not require official 1EdTech certification artifacts.

Run certification checks locally with member-authorized files kept outside this repository:

QTI3_EXTERNAL_QTI_DIR=/path/to/official/qti \
pnpm certification:check

pnpm test:external remains optional for local development and skips when QTI3_EXTERNAL_QTI_DIR is not configured. pnpm test:external:required and pnpm certification:check fail fast unless official external QTI content is provided. QTI3_EXTERNAL_VALIDATOR_REPORT may be supplied as supplemental evidence, but Basic IMPORT proof is generated by importing official item and test package zips. The full certification gate also writes and checks reproducible item evidence for a clean committed candidate. Set QTI3_CERTIFICATION_OUTPUT_DIR to private storage outside this repository, or retain the temporary output directory printed by the command. See certification evidence.

Public GitHub Actions runs synthetic tests, browser checks, and release validation. Keep official fixtures, certification logs, and reports in private storage. Any future recurring certification automation belongs in private CI.

Start the browser harness with:

pnpm dev

The main harness also loads packages through core, using manifest resources and assessment-test ordering. ZIPs of loose XML files without imsmanifest.xml are rejected; use the XML input to inspect an individual item. Package errors retain their diagnostic codes, paths, and severities in the debug panel.

Open /library.html to import a QTI ZIP into the reference app's IndexedDB database. ZIP extraction uses core's async reader with a bounded browser inflater; imports and database restores use parseQtiPackageFromEntries and its typed diagnostics. Import saves every original package file, including XML, metadata, stylesheets, and media. The page immediately reads the saved record back through the core importer. Close the page, reopen it, and choose Saved package and Question to inspect the questions, original XML, and diagnostics without uploading again. Delete package removes that saved record. Choose Submit response to run the question's response processing and see its score, authored feedback, responses, and outcomes. Reset attempt clears the current response and score. Questions without automatic response processing are identified as unscored; the page does not infer correctness from a positive score. Attempts are cleared when you switch questions or close the page; only the imported package is stored.

For a review, use a normal Chrome profile and a fixed local origin:

pnpm dev --port 5173 --strictPort

Open http://127.0.0.1:5173/library.html each time. Saved packages belong to that browser profile and origin; changing the hostname or port opens a different library. Clearing browser site data removes them, and browser storage may be evicted. This is a local reference library, not a backup. Imported content stays in that browser's database.

The page resolves item assets and qti-stylesheet files from saved bytes. Relative url() or @import dependencies inside CSS are not rewritten; packages that rely on them need additional stylesheet handling before their visual presentation can be demonstrated.

Open /convert.html on that dev server to create, migrate, and transcode individual items. The conversion demo keeps inputs in browser memory and shows diagnostics, output, and a preview. It does not bundle assets or convert whole packages.

Open the shared vocabulary gallery from the same Vite dev server:

pnpm dev
open "http://127.0.0.1:5173/sv-gallery?case=choice-selections-dark"

From a source checkout, run pnpm build before using the built CLI entry point. Published packages expose the same commands through the qti3 binary.

The CLI can parse local QTI directories, including external reference sets:

node packages/cli/dist/index.js parse-dir /path/to/items

Use validation when diagnostics should fail the command:

node packages/cli/dist/index.js validate-dir /path/to/items

Score each item with its declared correct responses:

node packages/cli/dist/index.js score-correct-dir /path/to/items

Use a server-trusted response file to score one item:

node packages/cli/dist/index.js score item.xml --responses trusted-responses.json

Prepare static or server-materialized adaptive candidate XML with:

node packages/cli/dist/index.js prepare-delivery item.xml --out candidate.xml
node packages/cli/dist/index.js prepare-delivery adaptive.xml \
  --mode server-materialized-adaptive \
  --state trusted-state.json \
  --out candidate.xml

Response and state JSON are server-trusted inputs, not raw browser submissions. Hosts manage adaptive turns through the library API and versioned attempt-state contract.

Inspect a package with:

node packages/cli/dist/index.js inspect-package /path/to/package.zip

This enumerates XML files, assets, manifest/test item references, and parse diagnostics for loadable assessment items.

Use strict package validation for conformance-oriented package checks:

node packages/cli/dist/index.js validate-package /path/to/package.zip

Strict package validation requires imsmanifest.xml, requires manifest or assessment-test item references, and fails direct item XML files that are not referenced by the package metadata.

Write standalone reference items for targeted interactions, processing patterns, and adaptive behavior:

node packages/cli/dist/index.js write-fixtures packages/fixtures/xml

The support matrix is machine-readable. It includes evidence for supported interactions, deprecated interactions, processing elements, and shared vocabulary classes:

node packages/cli/dist/index.js support-matrix

The accessibility proof matrix is also machine-readable. It lists each interaction's role, keyboard contract, automated evidence, and manual assistive-technology scripts:

node packages/cli/dist/index.js a11y-proof

Before publishing, verify these requirements:

  • Supported interactions need parser, validation, scoring, rendering, keyboard, and accessibility evidence.
  • Accessibility checks cover real operation as well as automated scans.
  • Dependencies stay small, exact, and reviewed.
  • Published packages use explicit npm files allowlists so package contents stay small and deliberate.
  • Release checks must pass before publishing. Certification evidence is checked separately.

Attempt state

Serialized attempt state uses qti3.attempt-state.v1. It captures responses, outcomes, generated template values, validation messages, lifecycle status, and QTI's built-in completionStatus outcome. PCI suspend/resume data is stored as opaque JSON under interactionStates keyed by response identifier. The optional builtInVariables record stores numAttempts, accumulated duration seconds (or NULL when unavailable), the open-attempt flag, and the three QTI_CONTEXT string fields.

  • Hosts can save, restore, and review attempts through this state contract.
  • Hosts can check restored JSON with isQtiAttemptStateV1() or assertQtiAttemptStateV1().
  • Reset and restore replace the active session; events from old controls cannot overwrite its responses.
  • Non-adaptive items reset authored outcomes before each scoring run.
  • Single integer/float outcomes without an authored default initialize to zero; other undeclared defaults remain NULL, and non-adaptive scoring resets to these effective defaults.
  • Adaptive items retain outcome values across response-processing runs.
  • An attempt starts on beginAttempt(), entering the interacting state, or the first response; scoring ends it. Resume preserves its count, and the next attempt increments it.
  • The browser supplies a monotonic clock and excludes suspended/closed time from duration. Core hosts provide now (milliseconds) or accumulated duration (seconds), plus optional context, in session options before template processing. A timed expression without time data returns NULL with a diagnostic. Non-timed items cannot reference duration.
  • For non-adaptive items, endAttempt() completes the item after a valid score run.
  • For adaptive items, endAttempt() runs response processing and leaves the item open unless processing sets completionStatus to "completed".
  • Templated items restore saved template values before deriving generated correct responses, so resume does not require the original random seed.

Items with SCORE marked external-scored="human" or external-scored="externalMachine" return score: null; submission materialization reports manual-scoring-required. Hosts obtain and store the external grade. An authored outcome default in saved state is not a completed grade.

Randomized item instances

qti3 supports QTI-native randomized item instances through template processing. Authors can use qti-random-integer, generated template variables, printed variables, and qti-set-correct-response to build deterministic randomized math-style items. The canonical random-integer-template-reference fixture proves this path by rendering a generated equation, storing the generated values in templateValues, and scoring the generated numeric answer.

Hosts should create a variant once, persist the full qti3.attempt-state.v1 value, and restore from that state on resume. A randomSeed is useful for deterministic initial generation, but saved templateValues are the authority after an attempt exists. Static candidate-safe XML redaction remains conservative for template-processing items. Server-materialized adaptive delivery can render safe template-derived presentation values from authoritative session state while stripping generated answer keys, template and response processing, mappings, lookup tables, and declaration defaults from the candidate XML.

Coverage

qti3 includes public synthetic fixtures for every current, non-deprecated QTI 3 item interaction. The canonical examples use MIT-licensed classroom prompts instead of placeholder QTI terminology. The fixtures cover response shape, scoring, browser rendering, keyboard operation, and accessibility evidence.

Processing coverage includes response processing, template processing, feedback, printed variables, MathML/template variables, catalogs, shared CSS vocabulary, advanced numeric/container/point expressions, and adaptive completionStatus behavior.

The manual harness exposes debugger panels for responses, outcomes, template values, diagnostics, validation messages, serialized state, package item navigation, action history, and accessibility proof scripts.

Publishing

The packages listed above publish under the longsightgroup npm organization. Releases publish from the longsightgroup/qti3 repository after pnpm release:check passes. Package tarballs come from the same checked build output that CI verifies.

The root and all 12 published packages use the same version. Release preparation updates their manifests and the changelog, then runs pnpm release:check. Pushing a matching v<version> tag starts the Publish workflow, which reruns the checks, packs each package, and publishes the tarballs. The workflow can also be dispatched manually.

Hosts upgrading from 0.10.x should review the 0.11.0 compatibility notes for changes to numeric defaults, mapping scores, comparisons, and interpolation tables.

Certification

The project is not certified. pnpm certification:check requires official 1EdTech external content. Content-validator reports are checked separately against an exact package and an explicitly trusted download digest; see validator evidence.

About

Dependency-light, framework-neutral TypeScript reference implementation for QTI 3 assessment items.

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages