Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

449 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

PIE-QTI

QTI 2.1, 2.2 & 3.0 Coverage Interactions Tests Accessibility TypeScript

This project provides two major capabilities:

  1. QTI 2.1, 2.2 & 3.0 Players β€” Standards-oriented item and assessment players with a shared version-normalization architecture
  2. PIE ↔ QTI Transformation Framework β€” Bidirectional transforms between QTI and PIE, with CLI, web app, and IMS Content Package support

πŸ“š Live Examples

QTI Player Examples

Project Status: The players have broad clean-room coverage but are not yet fully conformant or certified. Several delivery blockers are tracked in SPEC-GAPS-PLAN.md. The transform framework is under active development. See STATUS.md for details.


Warning

This project is pre-1.0: APIs may change, formal QTI certification is still in progress, and the current review found conformance and security blockers for arbitrary untrusted/high-stakes delivery. Evaluate the documented gaps for your content profile, use a backend-authoritative assessment integration, and contact the maintainers before adopting it for a non-trivial production system.


Why This Project Exists

PIE (Portable Interactions and Elements) is a complete framework for playing and authoring assessment items, maintained by Renaissance Learning with implementation partner MCRO.

Many Renaissance partners exchange content in QTI format, so bidirectional QTI ↔ PIE transformation is essential. This project open sources that transformation framework for partners and the broader community.

We also built a standards-oriented QTI player because a modern, open-source option was missingβ€”and we needed one for previewing, analysis, and "convert then render" workflows.


Part 1: QTI Players

Status: Pre-1.0 with broad item-delivery coverage. Do not interpret the registered interaction count or clean-room certification matrix as a claim that every schema-valid QTI item/test is playable. See STATUS.md and the spec-gap plan.

Full-featured players for rendering QTI assessment content in the browser.

Version-Agnostic Architecture

The players use a unified architecture that supports both QTI 2.2 and 3.0 through automatic version detection:

  • QTI 2.2 syntax family β€” camelCase elements (choiceInteraction, itemBody)
  • QTI 3.0 β€” kebab-case with qti- prefix (qti-choice-interaction, qti-item-body)
  • Common Internal Model β€” Both versions convert to the same canonical representation
  • Compatible player entry points β€” Existing QTI 2.2 callers use the same version-agnostic API

See @pie-qti/qti-common for the version abstraction layer.

Item Player (@pie-qti/item-player)

Renders and scores individual QTI items:

  • Standard and portable interaction extraction β€” Broad QTI 2.x/3.0 rendering coverage, including host-resolved QTI 2.x and 3.0 PCI; remaining conformance work is tracked in the spec-gap plan
  • Response processing AST/evaluator β€” Broad operator coverage, typed record fields, canonical fixed-template behavior for the supported URI set, and explicit host-resolved processing fragments
  • Role/view-aware rendering β€” candidate, scorer, author, tutor, proctor, testConstructor
  • Adaptive items β€” Multi-attempt workflows with progressive feedback
  • Accessible β€” Full keyboard navigation and screen reader support (follows WCAG 2.2 Level AA guidelines)
  • Iframe isolation mode β€” Optional secure rendering for untrusted content

Assessment Player (@pie-qti/assessment-player)

Orchestrates multi-item assessments:

  • Navigation mode model β€” Per-testPart linear/nonlinear and individual/simultaneous modes are preserved; linear parts prohibit return after advancing
  • Sections & hierarchy runtime β€” Ordered nested sections, external section refs, controls, rubrics, weights, and feedback are retained from raw XML; dynamic preconditions and section/testPart branch execution remain open
  • Selection & ordering runtime β€” Raw XML selection, required/fixed children, and shuffle are preserved; withReplacement still requires distinct sequence-indexed clone materialization
  • Time-limit runtime β€” Independent item/section/testPart/assessment clocks, save/resume, maximums, and minTime enforcement exist; timing edge/browser evidence is still being expanded
  • Item session control β€” Max attempts, review/skip, response validation
  • State persistence β€” Auto-save with resume capability
  • Outcome processing β€” Scoring templates (total, weighted, percentage, pass/fail)
  • Backend adapter β€” Mandatory boundary for authoritative scoring in production; raw answer-bearing assessment XML uses the local reference adapter only after explicit referenceMode opt-in for preview/offline delivery

Extensibility (Docs)

The player architecture separates QTI logic from UI rendering:

  • Plugin system (QTIPlugin) β€” Register custom extractors, components, and lifecycle hooks
  • Registries β€” Priority-based ExtractionRegistry and ComponentRegistry
  • Typesetting hook β€” Host-provided math rendering (KaTeX adapter included)
  • Custom operators β€” Support for <customOperator> elements

See the ACME Likert plugin for a complete extensibility example.

Theming

Components render via web components (Shadow DOM) with a CSS variable contract:

  • Theme tokens β€” PIE-QTI CSS variables (--pie-qti-*) with DaisyUI bridge support
  • ::part() hooks β€” Stable part names for host-side style refinement
  • Zero-CSS fallback β€” Components render correctly with no host styles

See STYLING.md for the full styling contract.

Internationalization (i18n)

The player UI supports multiple languages with runtime locale switching:

  • Type-safe translations β€” TypeScript autocomplete for all message keys
  • Runtime switching β€” Change language without page reload
  • Custom translations β€” Clients provide complete locale bundles or override specific strings
  • Small bundle β€” <10 KB gzipped (core + default locale)

See @pie-qti/i18n for the complete i18n API and custom translation examples.


Part 2: PIE ↔ QTI Transformation Framework

Status: Under active development

Bidirectional transformation between QTI XML and PIE JSON: QTI β†’ PIE ingest, plus PIE β†’ QTI 2.2 export.

Architecture Overview

The transformation framework provides a plugin-based architecture for converting between assessment formats:

QTI Transform Engine Architecture

The engine orchestrates transformations through:

  • Plugin Registry β€” Priority-based plugin selection (vendor plugins override defaults)
  • Transform Engine β€” Format detection, plugin matching, and execution
  • Extensibility System β€” Custom transformers, asset resolvers, and vendor-specific handlers

See Transformation Engine Documentation for complete architecture details.

Transform Capabilities

QTI β†’ PIE (@pie-qti/to-pie)

  • Supports QTI 2.2 and 3.0 (auto-detected)
  • Lossless round-trip when QTI originated from PIE
  • Best-effort semantic transformation otherwise
  • Vendor extension system for custom QTI variants

PIE β†’ QTI (@pie-qti/pie-to-qti2)

  • Lossless reconstruction when PIE contains embedded QTI
  • Generator registry for custom PIE model handling
  • IMS Content Package generation (imsmanifest.xml)

Extension Points

The transform pipeline is extensible at the package level. Production import workflows belong in host applications such as Composer CMS; this repository ships the reusable transform packages and examples:

  • Transform Plugins β€” Add support for custom formats or vendor-specific QTI variants
  • Vendor Extensions β€” Customize transformation behavior (detectors, transformers, asset resolvers)
  • Storage Backends β€” Choose filesystem, S3, database, or implement custom storage

CLI (@pie-qti/transform-cli)

Command-line tool for batch operations:

# Transform a single item
bun run pie-qti -- transform input.xml --format qti22:pie --output output.json

# Analyze QTI content
bun run pie-qti -- analyze-qti ./content-package/

# See all commands
bun run pie-qti -- --help

Development

# Install dependencies
bun install

# Build all packages
bun run build

# Run tests
bun run test

# Lint and typecheck
bun run lint
bun run typecheck

# E2E tests (Playwright)
bun run test:e2e

# App deployability checks (docs/demo production builds)
bun run verify:apps:deploy

# Publish readiness (publint, attw, pack, deps, metadata)
bun run verify:publish

CI runs the main quality gates on PRs:

  • Lint/type gates: Biome, Svelte checks, TypeScript, translation coverage, and unit tests
  • Certification gate: test:certification:public
  • Accessibility gate: verify:a11y
  • Deployability gate: verify:apps:deploy (apps/docs and apps/demo production buildability)
  • Publishability gate: verify:publish:quick (metadata, exports, publint, attw, pack, deps, source exports)

Release behavior is lockstep and patch-only for publishable packages/*:

  • merges to master auto-generate a temporary patch changeset when needed for release PR prep
  • local full release flow: bun run release:with-version

See docs/development/publish-verification.md for full publish-readiness details.

Local PIE Players

To test with pie-players locally, clone both repos side-by-side. The postinstall script auto-links them.

GitHub Pages Preview

bun run verify:apps:deploy
bun run docs:preview
# In another shell, preview the examples app if needed:
bun run preview:pages

Documentation

Architecture & Project Layout

  • Architecture Guide β€” System design, package map, extensibility, theming, and security
  • PRD Inventory β€” Canonical rationale and acceptance criteria map

Players

Transforms

Extensibility


License

ISC License β€” see LICENSE

About

QTI Player and QTI <-> PIE transforms framework

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages