@pie-players/pie-section-player 0.3.66 → 0.3.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +158 -0
- package/dist/chunks/module-a516757f.js +388 -394
- package/dist/chunks/nl-NL-9312c316.js +503 -0
- package/dist/chunks/nl-NL-ef6dd604.js +503 -0
- package/dist/chunks/pie-api-client-22de9d9c.js +161 -0
- package/dist/chunks/rolldown-runtime-1287ba31.js +20 -0
- package/dist/chunks/sre-0162a7a9.js +3431 -3428
- package/dist/components/shared/section-player-host-runtime.d.ts +11 -7
- package/dist/components/shared/section-player-shell-layout.svelte.d.ts +55 -0
- package/dist/components/shared/section-player-view-state.d.ts +35 -0
- package/dist/components/shared/use-interface-i18n.svelte.d.ts +20 -0
- package/dist/controllers/SectionController.d.ts +174 -0
- package/dist/controllers/types.d.ts +128 -2
- package/dist/pie-section-player.js +19906 -15523
- package/package.json +10 -10
- package/dist/components/shared/section-player-props.d.ts +0 -1
- package/dist/components/shared/tool-surface-host.d.ts +0 -28
package/README.md
CHANGED
|
@@ -103,6 +103,164 @@ policy](#js-api-example-for-advanced-host-policy). Key event types:
|
|
|
103
103
|
loading.
|
|
104
104
|
- `section-items-complete-changed` — aggregate completion flip.
|
|
105
105
|
- `section-navigation-change` — the controller's section identity changed.
|
|
106
|
+
- `formative-try-recorded` — a learner checked an answer.
|
|
107
|
+
- `formative-reveal-changed` — the reveal state changed without a Try: a learner
|
|
108
|
+
dismissed feedback, or a host forced or withdrew a reveal (`source` says which).
|
|
109
|
+
- `section-mastery-changed` — the mastery rollup changed. Emitted on change
|
|
110
|
+
only, like `section-items-complete-changed`.
|
|
111
|
+
- `timed-media-cue-changed` — a cue activated, a gate released, or aggregate
|
|
112
|
+
completion flipped. Not emitted for media position: `timeupdate` fires about four
|
|
113
|
+
times a second and moves nothing a layout renders.
|
|
114
|
+
- `timed-media-audio-started` — media audio is running, so read-aloud must yield.
|
|
115
|
+
Emitted only where playback actually stood; a gate that re-paused on the same
|
|
116
|
+
`play` produced no audio.
|
|
117
|
+
- `timed-media-policy-degraded` — the attached media time source cannot carry out a
|
|
118
|
+
playback policy, so it is advisory from here.
|
|
119
|
+
- `timed-media-invalid` — authored `timedMedia` that cannot be delivered; the
|
|
120
|
+
section renders without cue behavior.
|
|
121
|
+
|
|
122
|
+
### Formative delivery
|
|
123
|
+
|
|
124
|
+
Set `formative` on the section and the player renders a check-answer control per
|
|
125
|
+
item, records Tries, and reveals feedback:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const section: AssessmentSection = {
|
|
129
|
+
identifier: "practice-set",
|
|
130
|
+
formative: { enabled: true, maxTries: 3, feedback: "correctness" },
|
|
131
|
+
assessmentItemRefs: [
|
|
132
|
+
{ identifier: "q1", item },
|
|
133
|
+
// Overrides the section default field by field.
|
|
134
|
+
{ identifier: "q2", item, formative: { maxTries: 1, feedback: "solution" } },
|
|
135
|
+
{ identifier: "q3", item, formative: { enabled: false } },
|
|
136
|
+
],
|
|
137
|
+
};
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Absent, or `enabled: false`, and delivery is unchanged: no control, no state, no
|
|
141
|
+
`env` override, and `getSession()` does not carry the key.
|
|
142
|
+
|
|
143
|
+
PIE renders no feedback of its own. A revealed item gets `mode: "evaluate"`
|
|
144
|
+
projected over the section env — with `role: "instructor"` under
|
|
145
|
+
`feedback: "solution"` — and the element draws the rest. Only that item's env
|
|
146
|
+
changes; its neighbours stay editable. A retry withdraws the projection.
|
|
147
|
+
|
|
148
|
+
Read the resolved state from `getFormativeProjection()`, or off
|
|
149
|
+
`compositionModel.formative` in a custom layout. Drive it from a host through the
|
|
150
|
+
same handle:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
const controller = await host.waitForSectionController?.(5000);
|
|
154
|
+
// The learner's actions, budget-respecting.
|
|
155
|
+
controller?.recordFormativeTry?.({ itemId, outcomes }); // outcomes from provideScore()
|
|
156
|
+
controller?.retryFormativeItem?.({ itemId });
|
|
157
|
+
// Host authority: a teacher-driven "show the answer". Spends no Try, ignores the
|
|
158
|
+
// Try budget, works on an item with no Try yet.
|
|
159
|
+
controller?.revealFormativeItem?.({ itemId, feedback: "solution" });
|
|
160
|
+
controller?.hideFormativeItem?.({ itemId });
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`feedback` is stated rather than taken from the policy, because a reveal under
|
|
164
|
+
`feedback: "none"` would project nothing. A learner retry clears it, so a forced
|
|
165
|
+
solution does not upgrade every later reveal on that item.
|
|
166
|
+
|
|
167
|
+
Try state persists inside `SectionControllerSessionState.formative` and hydrates
|
|
168
|
+
with the rest of the snapshot. See
|
|
169
|
+
[`docs/prds/formative-delivery-contract.md`](../../docs/prds/formative-delivery-contract.md)
|
|
170
|
+
for the full contract, its QTI 3 mapping, and the mastery denominator rule.
|
|
171
|
+
|
|
172
|
+
### Timed media
|
|
173
|
+
|
|
174
|
+
Set `sectionType: "timed-media"` and a `timedMedia` block, and the section's cue
|
|
175
|
+
timeline decides when its items are delivered:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
const section: AssessmentSection = {
|
|
179
|
+
identifier: "water-cycle",
|
|
180
|
+
sectionType: "timed-media",
|
|
181
|
+
// A correctness gate needs unlimited Tries; see below.
|
|
182
|
+
formative: { enabled: true, maxTries: "unlimited", feedback: "correctness" },
|
|
183
|
+
rubricBlocks: [
|
|
184
|
+
{
|
|
185
|
+
identifier: "video-stimulus-1",
|
|
186
|
+
class: "stimulus",
|
|
187
|
+
view: ["candidate"],
|
|
188
|
+
// An ordinary passage. Its config mounts the media element — a PIE element,
|
|
189
|
+
// or authored `<video>` markup — and it owns the accessibility catalogs that
|
|
190
|
+
// carry captions, transcript and signed alternates.
|
|
191
|
+
passage: videoPassage,
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
assessmentItemRefs: [{ identifier: "q1", item }, { identifier: "q2", item }],
|
|
195
|
+
timedMedia: {
|
|
196
|
+
stimulusRef: "video-stimulus-1",
|
|
197
|
+
cues: [
|
|
198
|
+
{ identifier: "c1", range: { startSeconds: 4 }, itemRefs: ["q1"], policy: { activation: "reveal" } },
|
|
199
|
+
{
|
|
200
|
+
identifier: "c2",
|
|
201
|
+
range: { startSeconds: 10 },
|
|
202
|
+
itemRefs: ["q2"],
|
|
203
|
+
policy: { activation: "gate", releaseOn: "correct", onUnknownCorrectness: "release" },
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
playbackPolicy: { allowSeekAhead: false, pauseOnRequiredCue: true, requireMediaCompletion: false },
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Every item a gate names must satisfy its `releaseOn`. To split must-answer items from
|
|
212
|
+
optional ones, author two cues at the same timestamp — a gate over the first set, a
|
|
213
|
+
reveal over the second. Both activate in the same pass, the reveal completes at once,
|
|
214
|
+
and only the gate holds playback.
|
|
215
|
+
|
|
216
|
+
Absent `sectionType` and delivery is unchanged: no projection, no session slice, no
|
|
217
|
+
cue behavior. An item no `reveal` or `gate` cue names is delivered normally —
|
|
218
|
+
including one a `metadata` cue names, since metadata records state and reveals
|
|
219
|
+
nothing. A cued item is mounted and hidden until its cue fires, so its session and
|
|
220
|
+
shell registration survive a seek backwards.
|
|
221
|
+
|
|
222
|
+
The section reaches media only through a **Media Time Source**. The stimulus card
|
|
223
|
+
finds the media element its passage mounted and registers a native adapter; a host
|
|
224
|
+
with its own player registers its own port instead, and that port outranks the
|
|
225
|
+
card's discovery for as long as it is attached:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
const controller = await host.waitForSectionController?.(5000);
|
|
229
|
+
// No `renderableId`: a host is asserting its own port, where a renderable's adapter
|
|
230
|
+
// has to name itself and is ignored unless it is the resolved stimulus.
|
|
231
|
+
controller?.attachMediaTimeSource?.(myThirdPartyPort);
|
|
232
|
+
controller?.detachMediaTimeSource?.();
|
|
233
|
+
controller?.getTimedMediaProjection?.(); // cues, gate, enforcement, revealed items
|
|
234
|
+
// One half of the read-aloud handoff; `false` means the port cannot pause, so the
|
|
235
|
+
// overlap stands rather than the accommodation being withheld.
|
|
236
|
+
controller?.pauseMediaForCompetingAudio?.();
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Read-aloud and media audio never run at once, and the action the learner just took
|
|
240
|
+
wins: starting read-aloud pauses media, starting media pauses read-aloud. The section
|
|
241
|
+
supplies both halves — the method above and `timed-media-audio-started` — and the
|
|
242
|
+
toolkit arbitrates between them, because only the toolkit holds the TTS service and
|
|
243
|
+
the section. Neither direction resumes what it silenced.
|
|
244
|
+
|
|
245
|
+
Where the port reports `canPause: false` or `canRestrictSeeking: false`, the
|
|
246
|
+
matching policy degrades to **advisory**: cues still fire, state is still recorded,
|
|
247
|
+
the projection says `enforcement: "advisory"`, and a recoverable `timed-media`
|
|
248
|
+
framework warning names the policy that lost its teeth. Nothing silently pretends to
|
|
249
|
+
hold.
|
|
250
|
+
|
|
251
|
+
Three authoring mistakes fail loudly rather than delivering inert cues: a
|
|
252
|
+
`stimulusRef` that resolves to no renderable in the section; a gate on correctness
|
|
253
|
+
over an item without unlimited Tries, where a learner who spent a finite budget could
|
|
254
|
+
never release playback again; and a `stimulusRef` that resolves to a renderable which
|
|
255
|
+
mounts no media, reported once the section's content has loaded and no time source
|
|
256
|
+
has attached. Each reports a `timed-media` framework error, after which the section
|
|
257
|
+
delivers as an ordinary section with every item visible.
|
|
258
|
+
|
|
259
|
+
Cue state persists inside `SectionControllerSessionState.timedMedia` and hydrates
|
|
260
|
+
with the rest of the snapshot, including the furthest position reached, which is what
|
|
261
|
+
`allowSeekAhead: false` clamps against across a reload. See
|
|
262
|
+
[`docs/prds/timed-media-section-contract.md`](../../docs/prds/timed-media-section-contract.md)
|
|
263
|
+
for the contract and the decision record.
|
|
106
264
|
|
|
107
265
|
## Usage
|
|
108
266
|
|