This document explains the print architecture and how the two different print players work together.
Short answer: Not always! Print components are self-contained and work with regular players.
Print components are just delivery components with transformations:
- They call
preparePrintModel()internally - They render using the same delivery component
- You can render them with any player by passing appropriate props
Use print players when:
- ✅ You want explicit print-focused APIs (
roleinstead of complex env) - ✅ You need multi-element items (passage + questions)
- ✅ You have markup strings from a CMS
- ✅ You want to match production patterns (pieoneer, content systems)
Don't need print players if:
- ✅ You can use the interactive player with print-appropriate props
- ✅ You're rendering single elements
- ✅ You have direct access to components (not markup strings)
Package: @pie-element/element-player (this repository)
Component: <pie-element-player view="print">
Purpose: Testing and developing individual element print views
<pie-element-player
view="print"
element-name="multiple-choice"
role="student"
model={model}
></pie-element-player>Use Cases:
- Element development and testing
- Element documentation
- Single element demos
- Quick print preview during development
Location: packages/element-player/src/players/PieElementPlayer.svelte
Package: @pie-player/print (pie-players repository)
Component: <pie-print>
Purpose: Production rendering of complete assessment items
<pie-print config={itemConfig}></pie-print>Where itemConfig includes:
item.markup- HTML with multiple elementsitem.elements- Package version mapitem.models- Array of element modelsoptions.mode- student/instructor
Use Cases:
- Production applications (pieoneer, content delivery)
- Multi-element assessments (passage + questions)
- Markup-driven rendering
- Floater elements (rubrics, standalone components)
Location: Moved to pie-players/packages/print-player
Current Coverage: Print support is available for 10 out of 28 elements. Print components are being added incrementally as elements are developed.
Each element package can include a print export:
packages/elements-react/multiple-choice/
├── src/
│ ├── delivery/ # Interactive component
│ ├── author/ # Configuration UI
│ ├── controller/ # Business logic
│ └── print/ # Print component
│ └── index.tsx # Print custom element
└── package.json
Print components are self-contained and handle their own transformations:
// packages/elements-react/multiple-choice/src/print/index.tsx
const preparePrintModel = (model, opts) => {
const instr = opts.mode === 'instructor';
return {
...model,
disabled: true, // Disable all interactions
lockChoiceOrder: true, // Lock randomization
alwaysShowCorrect: instr, // Show answers for instructors
animationsDisabled: true, // No animations
// ... other print-specific transformations
};
};
export default class MultipleChoicePrint extends HTMLElement {
set model(m) {
const printModel = preparePrintModel(m, this._options);
// Render with delivery component
this._root.render(<Main model={printModel} session={{}} />);
}
set options(o) {
this._options = o;
}
}Key Points:
- Each print component exports a custom element class
preparePrintModel()handles print-specific transformations- Renders using the existing delivery component
- Respects
options.modefor answer visibility - No external orchestration needed for single elements
✅ Single element rendering ✅ Have direct component access ✅ Simple use cases ✅ Can pass print-appropriate props directly
Example:
<pie-element-player
view="delivery"
element-name="multiple-choice"
model={{ ...model, disabled: true }}
session={{}}
></pie-element-player>✅ Explicit print intent in code ✅ Cleaner API (role vs complex env) ✅ Element development/testing ✅ Print-focused demos
Example:
<pie-element-player
view="print"
element-name="multiple-choice"
role="student"
model={model}
></pie-element-player>✅ Multi-element items (passage + questions + rubrics) ✅ Markup strings from CMS/database ✅ Production applications (pieoneer pattern) ✅ Floater elements (not in markup) ✅ Dynamic CDN loading
Example:
<pie-print config={itemConfig}></pie-print>| Feature | Element-Level | Item-Level |
|---|---|---|
| Package | @pie-element/element-player |
@pie-player/print |
| Tag | <pie-element-player view="print"> |
<pie-print> |
| Input | Element name + model | Full item config |
| Markup | Not used | HTML string with elements |
| Elements | Single | Multiple |
| Loading | Import maps | Dynamic CDN imports |
| Registration | Fixed tag names | Hash-based unique names |
| Use Case | Development | Production |
The element-demo app uses the element-level player:
<!-- apps/element-demo/src/lib/element-player/components/PrintView.svelte -->
<pie-element-player
view="print"
element-name={elementName}
role={role}
model={model}
></pie-element-player>This provides:
- Consistent API with interactive demos
- Easy role switching (student/instructor)
- Automatic math rendering
- Clean, focused testing environment
The new item-level player (@pie-player/print) is a drop-in replacement:
- <script src="https://cdn.jsdelivr.net/npm/@pie-framework/pie-print@2.7.0/lib/pie-print.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/@pie-player/print@1.0.0/dist/print-player.js"></script>The API remains identical - only the URL resolution changes for newer packages:
player.resolve = (tagName, pkg) => {
const [_, name, version] = pkg.match(/@pie-element\/(.*?)@(.*)/);
return Promise.resolve({
tagName,
pkg,
// Updated path for pie-elements-ng packages
url: `https://cdn.jsdelivr.net/npm/@pie-element/${name}@${version}/dist/print/index.js`,
module: true
});
};- Custom elements use the same
model/optionspattern andpreparePrintModel(model, opts). - Use
opts.mode('student'|'instructor') for answer visibility and similar behavior.
-
Start the demo server:
bun cli dev:demo multiple-choice
-
Navigate to print route:
http://localhost:5173/multiple-choice/print -
Toggle between student/instructor roles
- Student: Shows questions only
- Instructor: Shows answers and rationales
-
The demo uses
<pie-element-player view="print">automatically
Print components are built as part of the main element build:
# Build specific element
bun run turbo build --filter @pie-element/multiple-choice
# Build all elements
bun run turbo build --filter "@pie-element/*"The build outputs to dist/print/index.js and dist/print/index.d.ts.
- Element-Level Print Player README
- Item-Level Print Player README
- Item-Level Print Player Usage Examples
- PieElementPlayer Source
Print elements are self-contained - they handle their own transformations and rendering.
Print players are orchestrators:
- Element-level: For development - loads single elements with import maps
- Item-level: For production - coordinates multiple elements from markup
Both use the same underlying print components, just at different scales and for different purposes.