pdfjs-reader-core 0.4.3 → 0.5.2
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 +51 -0
- package/dist/index.cjs +162 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -20
- package/dist/index.d.ts +47 -20
- package/dist/index.js +162 -76
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12996,10 +12996,26 @@ var PAPER = "#faf6ec";
|
|
|
12996
12996
|
var ACCENT = "#b04a1a";
|
|
12997
12997
|
var ACCENT_SOFT = "rgba(176, 74, 26, 0.18)";
|
|
12998
12998
|
var ACCENT_GLOW = "rgba(176, 74, 26, 0.35)";
|
|
12999
|
-
var MARKER = "#e6b422";
|
|
13000
|
-
var MARKER_SOFT = "rgba(230, 180, 34, 0.38)";
|
|
13001
12999
|
var SERIF = "'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', 'EB Garamond', 'Hoefler Text', Georgia, serif";
|
|
13002
13000
|
var EASE_OUT_EXPO = [0.22, 1, 0.36, 1];
|
|
13001
|
+
var PILL_FONT_CAPS = "clamp(10.5px, 0.55vw + 8.5px, 14.5px)";
|
|
13002
|
+
var PILL_FONT_BODY = "clamp(12px, 0.6vw + 10px, 16.5px)";
|
|
13003
|
+
var PILL_FONT_DISPLAY = "clamp(14px, 0.75vw + 12px, 19px)";
|
|
13004
|
+
var PILL_MAX_W_CAPS = "clamp(180px, 26vw, 380px)";
|
|
13005
|
+
var PILL_MAX_W_BODY = "clamp(200px, 28vw, 440px)";
|
|
13006
|
+
function resolvePillOffset(viewportWidthPx) {
|
|
13007
|
+
return clamp(0.022 * viewportWidthPx + 12, 20, 44);
|
|
13008
|
+
}
|
|
13009
|
+
function resolveMaxPillW(viewportWidthPx) {
|
|
13010
|
+
return clamp(0.26 * viewportWidthPx, 180, 380);
|
|
13011
|
+
}
|
|
13012
|
+
function resolveMaxPillH(viewportWidthPx) {
|
|
13013
|
+
const font = clamp(55e-4 * viewportWidthPx + 8.5, 10.5, 14.5);
|
|
13014
|
+
return clamp(font * 2.6, 28, 42);
|
|
13015
|
+
}
|
|
13016
|
+
function clamp(v, lo, hi) {
|
|
13017
|
+
return Math.min(hi, Math.max(lo, v));
|
|
13018
|
+
}
|
|
13003
13019
|
|
|
13004
13020
|
// src/components/TutorMode/SpotlightMask.tsx
|
|
13005
13021
|
import { jsx as jsx42, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
@@ -13285,17 +13301,17 @@ function AnimatedUnderline({ bbox, action }) {
|
|
|
13285
13301
|
import { useId as useId2 } from "react";
|
|
13286
13302
|
import { motion as motion4 } from "framer-motion";
|
|
13287
13303
|
import { jsx as jsx44, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
13304
|
+
var WASH = "rgba(230, 180, 34, 0.22)";
|
|
13288
13305
|
function AnimatedHighlight({ bbox, action }) {
|
|
13289
13306
|
const [x1, y1, x2, y2] = bbox;
|
|
13290
13307
|
const h = Math.max(1, y2 - y1);
|
|
13291
13308
|
const bleed = Math.min(4, h * 0.12);
|
|
13292
13309
|
const yTop = y1 - bleed;
|
|
13293
13310
|
const yBot = y2 + bleed;
|
|
13294
|
-
const height = yBot - yTop;
|
|
13295
13311
|
const duration = action.draw_duration_ms / 1e3;
|
|
13296
13312
|
const filterId = useId2();
|
|
13297
|
-
const
|
|
13298
|
-
const
|
|
13313
|
+
const isDefaultColour = !action.color || action.color === "rgba(250, 204, 21, 0.35)" || action.color === "rgba(250,204,21,0.35)";
|
|
13314
|
+
const fill = isDefaultColour ? WASH : action.color;
|
|
13299
13315
|
const taper = Math.min(6, h * 0.2);
|
|
13300
13316
|
const pathD = `
|
|
13301
13317
|
M ${x1 - 2} ${yTop + taper}
|
|
@@ -13325,44 +13341,24 @@ function AnimatedHighlight({ bbox, action }) {
|
|
|
13325
13341
|
"feTurbulence",
|
|
13326
13342
|
{
|
|
13327
13343
|
type: "fractalNoise",
|
|
13328
|
-
baseFrequency: "1.
|
|
13344
|
+
baseFrequency: "1.8",
|
|
13329
13345
|
numOctaves: "1",
|
|
13330
13346
|
seed: 3,
|
|
13331
13347
|
result: "noise"
|
|
13332
13348
|
}
|
|
13333
13349
|
),
|
|
13334
|
-
/* @__PURE__ */ jsx44("feDisplacementMap", { in: "SourceGraphic", in2: "noise", scale: 1
|
|
13350
|
+
/* @__PURE__ */ jsx44("feDisplacementMap", { in: "SourceGraphic", in2: "noise", scale: 1 })
|
|
13335
13351
|
] }) }),
|
|
13336
|
-
/* @__PURE__ */
|
|
13337
|
-
motion4.
|
|
13352
|
+
/* @__PURE__ */ jsx44(
|
|
13353
|
+
motion4.path,
|
|
13338
13354
|
{
|
|
13355
|
+
d: pathD,
|
|
13356
|
+
fill,
|
|
13339
13357
|
initial: { clipPath: `inset(0 100% 0 0)` },
|
|
13340
13358
|
animate: { clipPath: `inset(0 0% 0 0)` },
|
|
13341
13359
|
exit: { opacity: 0 },
|
|
13342
|
-
|
|
13343
|
-
|
|
13344
|
-
/* @__PURE__ */ jsx44(
|
|
13345
|
-
"path",
|
|
13346
|
-
{
|
|
13347
|
-
d: pathD,
|
|
13348
|
-
fill,
|
|
13349
|
-
opacity: 0.85,
|
|
13350
|
-
filter: `url(#${filterId})`
|
|
13351
|
-
}
|
|
13352
|
-
),
|
|
13353
|
-
/* @__PURE__ */ jsx44(
|
|
13354
|
-
"rect",
|
|
13355
|
-
{
|
|
13356
|
-
x: x1 - 1,
|
|
13357
|
-
y: y1 - bleed * 0.4,
|
|
13358
|
-
width: x2 - x1 + 2,
|
|
13359
|
-
height: height - bleed * 0.8,
|
|
13360
|
-
fill: inner,
|
|
13361
|
-
opacity: 0.5,
|
|
13362
|
-
filter: `url(#${filterId})`
|
|
13363
|
-
}
|
|
13364
|
-
)
|
|
13365
|
-
]
|
|
13360
|
+
filter: `url(#${filterId})`,
|
|
13361
|
+
transition: { duration, ease: EASE_OUT_EXPO }
|
|
13366
13362
|
}
|
|
13367
13363
|
)
|
|
13368
13364
|
]
|
|
@@ -13932,9 +13928,11 @@ function GhostReference({
|
|
|
13932
13928
|
{
|
|
13933
13929
|
style: {
|
|
13934
13930
|
position: "relative",
|
|
13935
|
-
|
|
13931
|
+
// Padding scales with viewport: compact on phones, breathing on
|
|
13932
|
+
// desktop. Extra 4px on the left preserves the footnote-rule gap.
|
|
13933
|
+
padding: "clamp(14px, 1.4vw + 10px, 26px) clamp(14px, 1.4vw + 10px, 26px) clamp(14px, 1.4vw + 10px, 26px) clamp(18px, 1.4vw + 14px, 30px)",
|
|
13936
13934
|
display: "flex",
|
|
13937
|
-
gap:
|
|
13935
|
+
gap: "clamp(12px, 1.1vw + 8px, 20px)",
|
|
13938
13936
|
alignItems: "flex-start"
|
|
13939
13937
|
},
|
|
13940
13938
|
children: [
|
|
@@ -13948,7 +13946,7 @@ function GhostReference({
|
|
|
13948
13946
|
transition: { duration: 0.45, delay: 0.18, ease: [0.22, 1, 0.36, 1] },
|
|
13949
13947
|
style: {
|
|
13950
13948
|
flexShrink: 0,
|
|
13951
|
-
width:
|
|
13949
|
+
width: "clamp(40px, 4vw + 20px, 64px)",
|
|
13952
13950
|
aspectRatio: `${page.width} / ${page.height}`,
|
|
13953
13951
|
background: PAPER_DEEP,
|
|
13954
13952
|
borderRadius: 2,
|
|
@@ -14013,7 +14011,7 @@ function GhostReference({
|
|
|
14013
14011
|
flex: 1,
|
|
14014
14012
|
minWidth: 0,
|
|
14015
14013
|
fontFamily: SERIF2,
|
|
14016
|
-
fontSize:
|
|
14014
|
+
fontSize: PILL_FONT_DISPLAY,
|
|
14017
14015
|
lineHeight: 1.55,
|
|
14018
14016
|
color: INK2,
|
|
14019
14017
|
fontFeatureSettings: "'liga' 1, 'kern' 1, 'onum' 1",
|
|
@@ -14035,7 +14033,7 @@ function GhostReference({
|
|
|
14035
14033
|
left: -14,
|
|
14036
14034
|
top: -2,
|
|
14037
14035
|
color: ACCENT2,
|
|
14038
|
-
fontSize:
|
|
14036
|
+
fontSize: "clamp(18px, 1vw + 14px, 28px)",
|
|
14039
14037
|
lineHeight: 1,
|
|
14040
14038
|
fontWeight: 500
|
|
14041
14039
|
// ornamental flourish anchoring the paragraph
|
|
@@ -14145,10 +14143,6 @@ import { AnimatePresence as AnimatePresence3 } from "framer-motion";
|
|
|
14145
14143
|
// src/components/TutorMode/StickyLabel.tsx
|
|
14146
14144
|
import { motion as motion9 } from "framer-motion";
|
|
14147
14145
|
import { jsx as jsx51, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
14148
|
-
var INK3 = "#2a2420";
|
|
14149
|
-
var PAPER3 = "#faf6ec";
|
|
14150
|
-
var ACCENT3 = "#b04a1a";
|
|
14151
|
-
var SERIF3 = "'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', 'EB Garamond', 'Hoefler Text', Georgia, serif";
|
|
14152
14146
|
var STEM = 18;
|
|
14153
14147
|
function StickyLabel({ screenAnchor, action }) {
|
|
14154
14148
|
const { x, y } = screenAnchor;
|
|
@@ -14187,7 +14181,7 @@ function StickyLabel({ screenAnchor, action }) {
|
|
|
14187
14181
|
transition: { duration: 0.35, ease: [0.22, 1, 0.36, 1] },
|
|
14188
14182
|
style: {
|
|
14189
14183
|
position: "absolute",
|
|
14190
|
-
background:
|
|
14184
|
+
background: ACCENT,
|
|
14191
14185
|
transformOrigin: layout.stemOrigin,
|
|
14192
14186
|
...layout.stem
|
|
14193
14187
|
}
|
|
@@ -14206,8 +14200,8 @@ function StickyLabel({ screenAnchor, action }) {
|
|
|
14206
14200
|
width: 6,
|
|
14207
14201
|
height: 6,
|
|
14208
14202
|
borderRadius: "50%",
|
|
14209
|
-
background:
|
|
14210
|
-
boxShadow: `0 0 0 2px ${
|
|
14203
|
+
background: ACCENT,
|
|
14204
|
+
boxShadow: `0 0 0 2px ${PAPER}, 0 0 0 3px rgba(176, 74, 26, 0.25)`,
|
|
14211
14205
|
...layout.dot
|
|
14212
14206
|
}
|
|
14213
14207
|
}
|
|
@@ -14222,25 +14216,25 @@ function StickyLabel({ screenAnchor, action }) {
|
|
|
14222
14216
|
style: {
|
|
14223
14217
|
position: "absolute",
|
|
14224
14218
|
...layout.bodyAnchor,
|
|
14225
|
-
background:
|
|
14226
|
-
color:
|
|
14219
|
+
background: PAPER,
|
|
14220
|
+
color: INK,
|
|
14227
14221
|
border: "1px solid rgba(42, 36, 32, 0.10)",
|
|
14228
14222
|
borderRadius: 3,
|
|
14229
14223
|
padding: "6px 12px 6px 14px",
|
|
14230
|
-
fontFamily:
|
|
14231
|
-
fontSize:
|
|
14224
|
+
fontFamily: SERIF,
|
|
14225
|
+
fontSize: PILL_FONT_BODY,
|
|
14232
14226
|
lineHeight: 1.25,
|
|
14233
14227
|
letterSpacing: 0.6,
|
|
14234
14228
|
textTransform: "uppercase",
|
|
14235
14229
|
fontWeight: 500,
|
|
14236
14230
|
whiteSpace: "nowrap",
|
|
14237
|
-
maxWidth:
|
|
14231
|
+
maxWidth: PILL_MAX_W_BODY,
|
|
14238
14232
|
overflow: "hidden",
|
|
14239
14233
|
textOverflow: "ellipsis",
|
|
14240
14234
|
// Warm two-layer shadow (matches GhostReference's palette).
|
|
14241
14235
|
boxShadow: "0 1px 2px rgba(42, 36, 32, 0.12), 0 8px 18px -6px rgba(42, 36, 32, 0.22)",
|
|
14242
14236
|
// Internal left accent rule — a 2px terracotta stripe.
|
|
14243
|
-
backgroundImage: `linear-gradient(to right, ${
|
|
14237
|
+
backgroundImage: `linear-gradient(to right, ${ACCENT} 0, ${ACCENT} 2px, transparent 2px)`,
|
|
14244
14238
|
backgroundRepeat: "no-repeat",
|
|
14245
14239
|
backgroundSize: "2px 100%",
|
|
14246
14240
|
backgroundPosition: "left top"
|
|
@@ -14482,9 +14476,9 @@ function computePillAnchor(fromBbox, toBbox, page, camera, viewport) {
|
|
|
14482
14476
|
const tipScreenX = viewport.width / 2 + camera.x + (toX - pageCX) * camera.scale;
|
|
14483
14477
|
const tipScreenY = viewport.height / 2 + camera.y + (toY - pageCY) * camera.scale;
|
|
14484
14478
|
const isVertical = Math.abs(dy) >= Math.abs(dx);
|
|
14485
|
-
const OFFSET =
|
|
14486
|
-
const MAX_PILL_W =
|
|
14487
|
-
const MAX_PILL_H =
|
|
14479
|
+
const OFFSET = resolvePillOffset(viewport.width);
|
|
14480
|
+
const MAX_PILL_W = resolveMaxPillW(viewport.width);
|
|
14481
|
+
const MAX_PILL_H = resolveMaxPillH(viewport.width);
|
|
14488
14482
|
const SAFE = 16;
|
|
14489
14483
|
if (isVertical) {
|
|
14490
14484
|
const canFitRight = tipScreenX + OFFSET + MAX_PILL_W < viewport.width - SAFE;
|
|
@@ -14528,13 +14522,13 @@ function CalloutLabelPill({
|
|
|
14528
14522
|
borderRadius: 3,
|
|
14529
14523
|
padding: spec.padding,
|
|
14530
14524
|
fontFamily: SERIF,
|
|
14531
|
-
fontSize:
|
|
14525
|
+
fontSize: PILL_FONT_CAPS,
|
|
14532
14526
|
lineHeight: 1.2,
|
|
14533
14527
|
letterSpacing: 0.6,
|
|
14534
14528
|
textTransform: "uppercase",
|
|
14535
14529
|
fontWeight: 500,
|
|
14536
14530
|
whiteSpace: "nowrap",
|
|
14537
|
-
maxWidth:
|
|
14531
|
+
maxWidth: PILL_MAX_W_CAPS,
|
|
14538
14532
|
overflow: "hidden",
|
|
14539
14533
|
textOverflow: "ellipsis",
|
|
14540
14534
|
boxShadow: "0 1px 2px rgba(42, 36, 32, 0.12), 0 8px 18px -6px rgba(42, 36, 32, 0.22)",
|
|
@@ -14925,7 +14919,12 @@ var StoryboardStepSchema = z.object({
|
|
|
14925
14919
|
});
|
|
14926
14920
|
var StoryboardSchema = z.object({
|
|
14927
14921
|
version: z.literal(1),
|
|
14928
|
-
reasoning
|
|
14922
|
+
// `reasoning` was required in 0.4.x as a model-generated explanation used
|
|
14923
|
+
// by DebugLog. It carries no visual effect and costs 50–150 output tokens
|
|
14924
|
+
// per call, so from 0.5.1 it's optional (default empty). Consumers who
|
|
14925
|
+
// still send it (from cached prompts or older directors) keep working —
|
|
14926
|
+
// the field is still accepted, just not required.
|
|
14927
|
+
reasoning: z.string().max(500).optional().default(""),
|
|
14929
14928
|
steps: z.array(StoryboardStepSchema).min(1).max(4)
|
|
14930
14929
|
});
|
|
14931
14930
|
function storyboardJsonSchema(opts = {}) {
|
|
@@ -15040,7 +15039,10 @@ function storyboardJsonSchema(opts = {}) {
|
|
|
15040
15039
|
return {
|
|
15041
15040
|
type: "object",
|
|
15042
15041
|
additionalProperties: false,
|
|
15043
|
-
required
|
|
15042
|
+
// `reasoning` intentionally omitted from `required` — the field is still
|
|
15043
|
+
// accepted when present but the model doesn't need to generate it,
|
|
15044
|
+
// which saves 50–150 output tokens per call. See zod schema above.
|
|
15045
|
+
required: ["version", "steps"],
|
|
15044
15046
|
properties: {
|
|
15045
15047
|
version: { type: "integer", enum: [1] },
|
|
15046
15048
|
reasoning: { type: "string" },
|
|
@@ -15079,7 +15081,6 @@ Anchoring rules:
|
|
|
15079
15081
|
Output ONLY this JSON, nothing else:
|
|
15080
15082
|
{
|
|
15081
15083
|
"version": 1,
|
|
15082
|
-
"reasoning": "<which block(s) you picked, which intent you used, and why \u2014 name the block_id>",
|
|
15083
15084
|
"steps": [ { "at_ms": <int>, "duration_ms": <int>, "action": <action> }, ... ]
|
|
15084
15085
|
}
|
|
15085
15086
|
|
|
@@ -15116,7 +15117,6 @@ When narration fits one of these patterns, emit the corresponding storyboard sha
|
|
|
15116
15117
|
Shape: spotlight the term + underline it + drop a label tag. No camera move if the block is already on-screen.
|
|
15117
15118
|
{
|
|
15118
15119
|
"version": 1,
|
|
15119
|
-
"reasoning": "define recipe: spotlighting and underlining the term, labeling as 'definition'",
|
|
15120
15120
|
"steps": [
|
|
15121
15121
|
{ "at_ms":0, "duration_ms":700, "action": { "type":"spotlight", "target_block":"p1_para0", "dim_opacity":0.6, "feather_px":40, "shape":"rounded" } },
|
|
15122
15122
|
{ "at_ms":200, "duration_ms":800, "action": { "type":"underline", "target_block":"p1_para0", "color":"#FBBF24", "style":"sketch", "draw_duration_ms":700 } },
|
|
@@ -15128,7 +15128,6 @@ Shape: spotlight the term + underline it + drop a label tag. No camera move if t
|
|
|
15128
15128
|
Shape: gentle camera move + callout arrow from caption to figure + pulse the figure.
|
|
15129
15129
|
{
|
|
15130
15130
|
"version": 1,
|
|
15131
|
-
"reasoning": "point_out recipe: drawing attention from caption p1_cap1 to figure p1_fig0",
|
|
15132
15131
|
"steps": [
|
|
15133
15132
|
{ "at_ms":0, "duration_ms":600, "action": { "type":"camera", "target_block":"p1_fig0", "scale":1.3, "padding":80, "easing":"ease-out" } },
|
|
15134
15133
|
{ "at_ms":400, "duration_ms":900, "action": { "type":"callout", "from_block":"p1_cap1", "to_block":"p1_fig0", "label":"see here", "curve":"curved" } },
|
|
@@ -15140,7 +15139,6 @@ Shape: gentle camera move + callout arrow from caption to figure + pulse the fig
|
|
|
15140
15139
|
Shape: box A + box B + callout between them with a relational label.
|
|
15141
15140
|
{
|
|
15142
15141
|
"version": 1,
|
|
15143
|
-
"reasoning": "compare recipe: framing fibrous vs synovial joints",
|
|
15144
15142
|
"steps": [
|
|
15145
15143
|
{ "at_ms":0, "duration_ms":600, "action": { "type":"box", "target_block":"p1_list5", "color":"#3B82F6", "style":"solid" } },
|
|
15146
15144
|
{ "at_ms":300, "duration_ms":600, "action": { "type":"box", "target_block":"p1_list12", "color":"#F472B6", "style":"solid" } },
|
|
@@ -15152,7 +15150,6 @@ Shape: box A + box B + callout between them with a relational label.
|
|
|
15152
15150
|
Shape: highlight + pulse. Fast, punchy, no camera.
|
|
15153
15151
|
{
|
|
15154
15152
|
"version": 1,
|
|
15155
|
-
"reasoning": "emphasize recipe: highlighting key keyword and pulsing for stress",
|
|
15156
15153
|
"steps": [
|
|
15157
15154
|
{ "at_ms":0, "duration_ms":500, "action": { "type":"highlight", "target_block":"p1_list0", "color":"rgba(250,204,21,0.35)", "draw_duration_ms":450 } },
|
|
15158
15155
|
{ "at_ms":350, "duration_ms":800, "action": { "type":"pulse", "target_block":"p1_list0", "count":2, "intensity":"strong" } }
|
|
@@ -15421,32 +15418,32 @@ function clampNumericRanges(input) {
|
|
|
15421
15418
|
}
|
|
15422
15419
|
const type = typeof out.type === "string" ? out.type : void 0;
|
|
15423
15420
|
if (type === "camera") {
|
|
15424
|
-
if (typeof out.scale === "number") out.scale =
|
|
15421
|
+
if (typeof out.scale === "number") out.scale = clamp2(out.scale, 0.5, 4);
|
|
15425
15422
|
if (typeof out.padding === "number") {
|
|
15426
|
-
out.padding =
|
|
15423
|
+
out.padding = clamp2(out.padding, 0, 400);
|
|
15427
15424
|
}
|
|
15428
15425
|
}
|
|
15429
15426
|
if (typeof out.dim_opacity === "number") {
|
|
15430
|
-
out.dim_opacity =
|
|
15427
|
+
out.dim_opacity = clamp2(out.dim_opacity, 0, 1);
|
|
15431
15428
|
}
|
|
15432
15429
|
if (typeof out.feather_px === "number") {
|
|
15433
|
-
out.feather_px =
|
|
15430
|
+
out.feather_px = clamp2(out.feather_px, 0, 200);
|
|
15434
15431
|
}
|
|
15435
15432
|
if (typeof out.draw_duration_ms === "number") {
|
|
15436
|
-
out.draw_duration_ms =
|
|
15433
|
+
out.draw_duration_ms = clamp2(out.draw_duration_ms, 100, 3e3);
|
|
15437
15434
|
}
|
|
15438
15435
|
if (typeof out.count === "number") {
|
|
15439
|
-
out.count = Math.round(
|
|
15436
|
+
out.count = Math.round(clamp2(out.count, 1, 5));
|
|
15440
15437
|
}
|
|
15441
15438
|
if (typeof out.at_ms === "number") {
|
|
15442
|
-
out.at_ms =
|
|
15439
|
+
out.at_ms = clamp2(out.at_ms, 0, 5e3);
|
|
15443
15440
|
}
|
|
15444
15441
|
if (typeof out.duration_ms === "number" && type === void 0) {
|
|
15445
|
-
out.duration_ms =
|
|
15442
|
+
out.duration_ms = clamp2(out.duration_ms, 100, 5e3);
|
|
15446
15443
|
}
|
|
15447
15444
|
return out;
|
|
15448
15445
|
}
|
|
15449
|
-
function
|
|
15446
|
+
function clamp2(v, lo, hi) {
|
|
15450
15447
|
return Math.min(hi, Math.max(lo, v));
|
|
15451
15448
|
}
|
|
15452
15449
|
function enforceOverlayPresence(sb) {
|
|
@@ -15459,9 +15456,10 @@ function enforceOverlayPresence(sb) {
|
|
|
15459
15456
|
if (!cameraStep || cameraStep.action.type !== "camera") return sb;
|
|
15460
15457
|
const target = cameraStep.action.target_block;
|
|
15461
15458
|
if (!target) return sb;
|
|
15459
|
+
const prefix = sb.reasoning ? `${sb.reasoning} ` : "";
|
|
15462
15460
|
return {
|
|
15463
15461
|
...sb,
|
|
15464
|
-
reasoning: `${
|
|
15462
|
+
reasoning: `${prefix}[auto-appended pulse: camera-only storyboards are forbidden]`,
|
|
15465
15463
|
steps: [
|
|
15466
15464
|
...sb.steps,
|
|
15467
15465
|
{
|
|
@@ -15853,6 +15851,7 @@ function TutorModeContainer({
|
|
|
15853
15851
|
backgroundColor = "#ffffff",
|
|
15854
15852
|
loadingComponent,
|
|
15855
15853
|
onPageChange,
|
|
15854
|
+
storyboardProvider,
|
|
15856
15855
|
className
|
|
15857
15856
|
}) {
|
|
15858
15857
|
const containerRef = useRef27(null);
|
|
@@ -15931,7 +15930,7 @@ function TutorModeContainer({
|
|
|
15931
15930
|
const debounceRef = useRef27(null);
|
|
15932
15931
|
const lastChunkRef = useRef27(null);
|
|
15933
15932
|
useEffect28(() => {
|
|
15934
|
-
if (!llm) return;
|
|
15933
|
+
if (!storyboardProvider && !llm) return;
|
|
15935
15934
|
if (!currentChunk || currentChunk === lastChunkRef.current) return;
|
|
15936
15935
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
15937
15936
|
debounceRef.current = setTimeout(async () => {
|
|
@@ -15952,6 +15951,75 @@ function TutorModeContainer({
|
|
|
15952
15951
|
});
|
|
15953
15952
|
abortRef.current?.abort();
|
|
15954
15953
|
abortRef.current = new AbortController();
|
|
15954
|
+
if (storyboardProvider) {
|
|
15955
|
+
narrationStore.getState().setLlmStatus("in-flight");
|
|
15956
|
+
narrationStore.getState().appendDebugEvent({
|
|
15957
|
+
kind: "llm-request",
|
|
15958
|
+
summary: `provider (page ${pageNumber}, ${page2.blocks.length} blocks)`,
|
|
15959
|
+
payload: {
|
|
15960
|
+
via: "storyboardProvider",
|
|
15961
|
+
pageNumber,
|
|
15962
|
+
blockCount: page2.blocks.length
|
|
15963
|
+
}
|
|
15964
|
+
});
|
|
15965
|
+
try {
|
|
15966
|
+
const raw = await storyboardProvider({
|
|
15967
|
+
chunk,
|
|
15968
|
+
pageNumber,
|
|
15969
|
+
page: page2,
|
|
15970
|
+
history: narrationStore.getState().chunkHistory,
|
|
15971
|
+
signal: abortRef.current.signal
|
|
15972
|
+
});
|
|
15973
|
+
if (!raw) {
|
|
15974
|
+
narrationStore.getState().setLlmStatus("idle");
|
|
15975
|
+
narrationStore.getState().appendDebugEvent({
|
|
15976
|
+
kind: "note",
|
|
15977
|
+
summary: "provider returned null \u2014 no storyboard for this chunk"
|
|
15978
|
+
});
|
|
15979
|
+
return;
|
|
15980
|
+
}
|
|
15981
|
+
const parsed = StoryboardSchema.safeParse(raw);
|
|
15982
|
+
if (!parsed.success) {
|
|
15983
|
+
narrationStore.getState().setLlmStatus(
|
|
15984
|
+
"failed",
|
|
15985
|
+
parsed.error.message
|
|
15986
|
+
);
|
|
15987
|
+
narrationStore.getState().appendDebugEvent({
|
|
15988
|
+
kind: "llm-error",
|
|
15989
|
+
summary: `provider storyboard rejected by schema: ${parsed.error.issues[0]?.message ?? "unknown"}`,
|
|
15990
|
+
payload: { raw, error: parsed.error.message }
|
|
15991
|
+
});
|
|
15992
|
+
return;
|
|
15993
|
+
}
|
|
15994
|
+
const storyboard = parsed.data;
|
|
15995
|
+
narrationStore.getState().setLlmStatus("idle");
|
|
15996
|
+
narrationStore.getState().appendDebugEvent({
|
|
15997
|
+
kind: "llm-response",
|
|
15998
|
+
summary: summariseStoryboard(storyboard),
|
|
15999
|
+
payload: { via: "storyboardProvider", storyboard }
|
|
16000
|
+
});
|
|
16001
|
+
engineRef.current?.execute(storyboard);
|
|
16002
|
+
narrationStore.getState().appendDebugEvent({
|
|
16003
|
+
kind: "storyboard-execute",
|
|
16004
|
+
summary: `engine executing ${storyboard.steps.length} steps`,
|
|
16005
|
+
payload: storyboard.steps.map((s) => ({
|
|
16006
|
+
at_ms: s.at_ms,
|
|
16007
|
+
type: s.action.type,
|
|
16008
|
+
target: "target_block" in s.action ? s.action.target_block : void 0
|
|
16009
|
+
}))
|
|
16010
|
+
});
|
|
16011
|
+
} catch (e) {
|
|
16012
|
+
if (e.name === "AbortError") return;
|
|
16013
|
+
narrationStore.getState().setLlmStatus("failed", e.message);
|
|
16014
|
+
narrationStore.getState().appendDebugEvent({
|
|
16015
|
+
kind: "llm-error",
|
|
16016
|
+
summary: `provider threw: ${e.message.slice(0, 80)}`,
|
|
16017
|
+
payload: e
|
|
16018
|
+
});
|
|
16019
|
+
}
|
|
16020
|
+
return;
|
|
16021
|
+
}
|
|
16022
|
+
if (!llm) return;
|
|
15955
16023
|
narrationStore.getState().setLlmStatus("in-flight");
|
|
15956
16024
|
narrationStore.getState().appendDebugEvent({
|
|
15957
16025
|
kind: "llm-request",
|
|
@@ -15973,7 +16041,7 @@ function TutorModeContainer({
|
|
|
15973
16041
|
narrationStore.getState().setLlmStatus("idle");
|
|
15974
16042
|
narrationStore.getState().appendDebugEvent({
|
|
15975
16043
|
kind: "llm-response",
|
|
15976
|
-
summary:
|
|
16044
|
+
summary: summariseStoryboard(result.storyboard),
|
|
15977
16045
|
payload: { raw: result.raw, storyboard: result.storyboard }
|
|
15978
16046
|
});
|
|
15979
16047
|
engineRef.current?.execute(result.storyboard);
|
|
@@ -16016,7 +16084,16 @@ function TutorModeContainer({
|
|
|
16016
16084
|
return () => {
|
|
16017
16085
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
16018
16086
|
};
|
|
16019
|
-
}, [
|
|
16087
|
+
}, [
|
|
16088
|
+
currentChunk,
|
|
16089
|
+
llm,
|
|
16090
|
+
storyboardProvider,
|
|
16091
|
+
index,
|
|
16092
|
+
pageNumber,
|
|
16093
|
+
narrationStore,
|
|
16094
|
+
embeddingProvider,
|
|
16095
|
+
llmTimeoutMs
|
|
16096
|
+
]);
|
|
16020
16097
|
useEffect28(() => {
|
|
16021
16098
|
if (!currentChunk) return;
|
|
16022
16099
|
const t = setTimeout(() => {
|
|
@@ -16206,6 +16283,15 @@ function TutorLoadingState({
|
|
|
16206
16283
|
}
|
|
16207
16284
|
);
|
|
16208
16285
|
}
|
|
16286
|
+
function summariseStoryboard(sb) {
|
|
16287
|
+
const stepCount = sb.steps.length;
|
|
16288
|
+
const trimmedReasoning = (sb.reasoning ?? "").trim();
|
|
16289
|
+
if (trimmedReasoning) {
|
|
16290
|
+
return `storyboard \u2713 ${stepCount} steps \u2014 ${trimmedReasoning.slice(0, 60)}`;
|
|
16291
|
+
}
|
|
16292
|
+
const kinds = sb.steps.map((s) => s.action.type).join(" \u2192 ");
|
|
16293
|
+
return `storyboard \u2713 ${stepCount} steps \u2014 ${kinds}`;
|
|
16294
|
+
}
|
|
16209
16295
|
|
|
16210
16296
|
// src/director/transformers-embedding.ts
|
|
16211
16297
|
var loaded = null;
|