This project provides two major capabilities:
- QTI 2.1, 2.2 & 3.0 Players β Standards-oriented item and assessment players with a shared version-normalization architecture
- PIE β QTI Transformation Framework β Bidirectional transforms between QTI and PIE, with CLI, web app, and IMS Content Package support
π Live 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.
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.
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.
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.
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
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;
withReplacementstill requires distinct sequence-indexed clone materialization - Time-limit runtime β Independent item/section/testPart/assessment clocks, save/resume, maximums, and
minTimeenforcement 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
referenceModeopt-in for preview/offline delivery
The player architecture separates QTI logic from UI rendering:
- Plugin system (
QTIPlugin) β Register custom extractors, components, and lifecycle hooks - Registries β Priority-based
ExtractionRegistryandComponentRegistry - 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.
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.
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.
Status: Under active development
Bidirectional transformation between QTI XML and PIE JSON: QTI β PIE ingest, plus PIE β QTI 2.2 export.
The transformation framework provides a plugin-based architecture for converting between assessment formats:
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.
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)
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
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# 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:publishCI 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
masterauto-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.
To test with pie-players locally, clone both repos side-by-side. The postinstall script auto-links them.
bun run verify:apps:deploy
bun run docs:preview
# In another shell, preview the examples app if needed:
bun run preview:pages- Architecture Guide β System design, package map, extensibility, theming, and security
- PRD Inventory β Canonical rationale and acceptance criteria map
- Item Player β API, interactions, accessibility
- Assessment Player β Navigation, scoring, backend integration
- QTI Common β Version abstraction layer (QTI 2.2 & 3.0)
- Styling Contract β Theming with CSS variables and ::part
- Example App β Demo application with all interactions
- Transformation Engine β Architecture, plugin system, and extensibility
- Transformation Guide β Bidirectional transform overview
- Vendor Plugin Guide β Building custom vendor plugins
- Source Profiles β Real-world QTI source detection and import adaptation
- CLI β Command-line batch operations
- QTI β PIE β QTI to PIE transformer
- PIE β QTI β PIE to QTI transformer
- IMS Content Packages β Manifest generation
- Custom Generators β Adding PIE model support
- ACME Likert Plugin β Player extensibility example
ISC License β see LICENSE

