pdfjs-reader-core 0.5.7 → 0.5.8

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/dist/index.cjs CHANGED
@@ -9191,7 +9191,7 @@ var init_DocumentContainer = __esm({
9191
9191
  const containerRef = (0, import_react37.useRef)(null);
9192
9192
  const documentRef = (0, import_react37.useRef)(null);
9193
9193
  const baseScaleRef = (0, import_react37.useRef)(scale);
9194
- const isTouchDevice2 = useIsTouchDevice();
9194
+ const isTouchDevice = useIsTouchDevice();
9195
9195
  const documentLoadingState = useViewerStore((s) => s.documentLoadingState);
9196
9196
  const { selection, clearSelection, copySelection } = useTextSelection();
9197
9197
  const handlePinchZoom = (0, import_react37.useCallback)(
@@ -9222,7 +9222,7 @@ var init_DocumentContainer = __esm({
9222
9222
  onSwipeLeft: handleSwipeLeft,
9223
9223
  onSwipeRight: handleSwipeRight,
9224
9224
  onDoubleTap: handleDoubleTap,
9225
- enabled: enableTouchGestures && isTouchDevice2,
9225
+ enabled: enableTouchGestures && isTouchDevice,
9226
9226
  swipeThreshold: 50,
9227
9227
  doubleTapInterval: 300
9228
9228
  });
@@ -9466,7 +9466,7 @@ var init_VirtualizedDocumentContainer = __esm({
9466
9466
  const pageCache = (0, import_react38.useRef)(/* @__PURE__ */ new Map());
9467
9467
  const pageDimensionsCache = (0, import_react38.useRef)(/* @__PURE__ */ new Map());
9468
9468
  const baseScaleRef = (0, import_react38.useRef)(scale);
9469
- const isTouchDevice2 = useIsTouchDevice();
9469
+ const isTouchDevice = useIsTouchDevice();
9470
9470
  const [visiblePages, setVisiblePages] = (0, import_react38.useState)([1]);
9471
9471
  const [pageObjects, setPageObjects] = (0, import_react38.useState)(/* @__PURE__ */ new Map());
9472
9472
  const [totalHeight, setTotalHeight] = (0, import_react38.useState)(0);
@@ -9669,7 +9669,7 @@ var init_VirtualizedDocumentContainer = __esm({
9669
9669
  onPinchZoom: handlePinchZoom,
9670
9670
  onSwipeLeft: nextPage,
9671
9671
  onSwipeRight: previousPage,
9672
- enabled: enableTouchGestures && isTouchDevice2
9672
+ enabled: enableTouchGestures && isTouchDevice
9673
9673
  });
9674
9674
  const setContainerRef = (0, import_react38.useCallback)(
9675
9675
  (element) => {
@@ -9877,7 +9877,7 @@ var init_DualPageContainer = __esm({
9877
9877
  const containerRef = (0, import_react40.useRef)(null);
9878
9878
  const documentRef = (0, import_react40.useRef)(null);
9879
9879
  const baseScaleRef = (0, import_react40.useRef)(scale);
9880
- const isTouchDevice2 = useIsTouchDevice();
9880
+ const isTouchDevice = useIsTouchDevice();
9881
9881
  const [leftPage, setLeftPage] = (0, import_react40.useState)(null);
9882
9882
  const [rightPage, setRightPage] = (0, import_react40.useState)(null);
9883
9883
  const [isLoading, setIsLoading] = (0, import_react40.useState)(false);
@@ -10020,7 +10020,7 @@ var init_DualPageContainer = __esm({
10020
10020
  onPinchZoom: handlePinchZoom,
10021
10021
  onSwipeLeft: goToNextSpread,
10022
10022
  onSwipeRight: goToPreviousSpread,
10023
- enabled: enableTouchGestures && isTouchDevice2
10023
+ enabled: enableTouchGestures && isTouchDevice
10024
10024
  });
10025
10025
  const setContainerRef = (0, import_react40.useCallback)(
10026
10026
  (element) => {
@@ -13268,7 +13268,7 @@ function withErrorBoundary({ component, ...props }) {
13268
13268
  init_PDFLoadingScreen2();
13269
13269
 
13270
13270
  // src/components/TutorMode/TutorModeContainer.tsx
13271
- var import_react58 = require("react");
13271
+ var import_react57 = require("react");
13272
13272
  var import_zustand2 = require("zustand");
13273
13273
  init_PDFPage2();
13274
13274
  init_hooks();
@@ -13559,13 +13559,13 @@ function AnimatedUnderline({ bbox, action }) {
13559
13559
  const blotX = x2 + 4;
13560
13560
  const blotY = y;
13561
13561
  const strokeWeight = action.style === "wavy" ? 3 : 4;
13562
- const xPad = 8;
13563
- const yAbove = 8;
13564
- const yBelow = 24;
13565
- const svgX = x1 - xPad;
13566
- const svgY = y - yAbove;
13567
- const svgW = x2 - x1 + 2 * xPad;
13568
- const svgH = yAbove + yBelow;
13562
+ const uxPad = 8;
13563
+ const uAbove = 8;
13564
+ const uBelow = 24;
13565
+ const svgX = x1 - uxPad;
13566
+ const svgY = y - uAbove;
13567
+ const svgW = x2 - x1 + 2 * uxPad;
13568
+ const svgH = uAbove + uBelow;
13569
13569
  return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
13570
13570
  "svg",
13571
13571
  {
@@ -13640,7 +13640,12 @@ function AnimatedUnderline({ bbox, action }) {
13640
13640
  // src/components/TutorMode/AnimatedHighlight.tsx
13641
13641
  var import_framer_motion4 = require("framer-motion");
13642
13642
  var import_jsx_runtime44 = require("react/jsx-runtime");
13643
- var WASH = "rgba(195, 145, 10, 0.32)";
13643
+ var DEFAULT_HUE = "rgb(230, 180, 34)";
13644
+ var WASH_OPACITY = 0.28;
13645
+ function stripAlpha(color) {
13646
+ const m = color.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);
13647
+ return m ? `rgb(${m[1]}, ${m[2]}, ${m[3]})` : color;
13648
+ }
13644
13649
  function AnimatedHighlight({ bbox, action }) {
13645
13650
  const [x1, y1, x2, y2] = bbox;
13646
13651
  const h = Math.max(1, y2 - y1);
@@ -13649,7 +13654,7 @@ function AnimatedHighlight({ bbox, action }) {
13649
13654
  const yBot = y2 + bleed;
13650
13655
  const duration = action.draw_duration_ms / 1e3;
13651
13656
  const isDefaultColour = !action.color || action.color === "rgba(250, 204, 21, 0.35)" || action.color === "rgba(250,204,21,0.35)";
13652
- const fill = isDefaultColour ? WASH : action.color;
13657
+ const fill = stripAlpha(isDefaultColour ? DEFAULT_HUE : action.color);
13653
13658
  const taper = Math.min(6, h * 0.2);
13654
13659
  const pathD = `
13655
13660
  M ${x1 - 2} ${yTop + taper}
@@ -13662,11 +13667,11 @@ function AnimatedHighlight({ bbox, action }) {
13662
13667
  L ${x1 - 2} ${yBot - taper}
13663
13668
  Z
13664
13669
  `;
13665
- const pad = 8;
13666
- const svgX = x1 - pad;
13667
- const svgY = yTop - pad;
13668
- const svgW = x2 - x1 + 2 * pad;
13669
- const svgH = yBot - yTop + 2 * pad;
13670
+ const svgPad = 8;
13671
+ const svgX = x1 - svgPad;
13672
+ const svgY = yTop - svgPad;
13673
+ const svgW = x2 - x1 + 2 * svgPad;
13674
+ const svgH = yBot - yTop + 2 * svgPad;
13670
13675
  return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
13671
13676
  "svg",
13672
13677
  {
@@ -13686,6 +13691,7 @@ function AnimatedHighlight({ bbox, action }) {
13686
13691
  {
13687
13692
  d: pathD,
13688
13693
  fill,
13694
+ fillOpacity: WASH_OPACITY,
13689
13695
  initial: { clipPath: `inset(0 100% 0 0)` },
13690
13696
  animate: { clipPath: `inset(0 0% 0 0)` },
13691
13697
  exit: { opacity: 0 },
@@ -13697,7 +13703,6 @@ function AnimatedHighlight({ bbox, action }) {
13697
13703
  }
13698
13704
 
13699
13705
  // src/components/TutorMode/PulseOverlay.tsx
13700
- var import_react56 = require("react");
13701
13706
  var import_framer_motion5 = require("framer-motion");
13702
13707
  var import_jsx_runtime45 = require("react/jsx-runtime");
13703
13708
  var INTENSITY = {
@@ -13706,7 +13711,6 @@ var INTENSITY = {
13706
13711
  strong: { bracketLen: 26, strokeWeight: 3, coreOpacity: 1, ringScale: 1.22 }
13707
13712
  };
13708
13713
  function PulseOverlay({ bbox, action }) {
13709
- const pulseId = (0, import_react56.useId)();
13710
13714
  const [x1, y1, x2, y2] = bbox;
13711
13715
  const w = Math.max(1, x2 - x1);
13712
13716
  const h = Math.max(1, y2 - y1);
@@ -13715,13 +13719,13 @@ function PulseOverlay({ bbox, action }) {
13715
13719
  const spec = INTENSITY[action.intensity] ?? INTENSITY.normal;
13716
13720
  const L = Math.min(spec.bracketLen, Math.min(w, h) / 2.5);
13717
13721
  const PAD = 6;
13722
+ const ringExtentX = (w / 2 + PAD) * spec.ringScale - w / 2;
13723
+ const ringExtentY = (h / 2 + PAD) * spec.ringScale - h / 2;
13724
+ const glowExtentX = (w / 2 + 10) * spec.ringScale - w / 2 + 24;
13725
+ const glowExtentY = (h / 2 + 10) * spec.ringScale - h / 2 + 24;
13718
13726
  const bracketExtent = PAD + L + 8;
13719
- const glowExtent = (w / 2 + 24) * spec.ringScale - w / 2;
13720
- const ringExtent = (w / 2 + PAD) * spec.ringScale - w / 2;
13721
- const glowExtentV = (h / 2 + 24) * spec.ringScale - h / 2;
13722
- const ringExtentV = (h / 2 + PAD) * spec.ringScale - h / 2;
13723
- const svgPadX = Math.ceil(Math.max(bracketExtent, glowExtent, ringExtent) + 4);
13724
- const svgPadY = Math.ceil(Math.max(bracketExtent, glowExtentV, ringExtentV) + 4);
13727
+ const svgPadX = Math.ceil(Math.max(40, ringExtentX, glowExtentX, bracketExtent));
13728
+ const svgPadY = Math.ceil(Math.max(40, ringExtentY, glowExtentY, bracketExtent));
13725
13729
  const svgX = x1 - svgPadX;
13726
13730
  const svgY = y1 - svgPadY;
13727
13731
  const svgW = w + 2 * svgPadX;
@@ -13741,22 +13745,18 @@ function PulseOverlay({ bbox, action }) {
13741
13745
  },
13742
13746
  "data-role": "pulse",
13743
13747
  children: [
13744
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("radialGradient", { id: `${pulseId}-glow`, cx: "50%", cy: "50%", r: "50%", children: [
13745
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("stop", { offset: "0%", stopColor: ACCENT_GLOW, stopOpacity: 1 }),
13746
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("stop", { offset: "60%", stopColor: ACCENT_GLOW, stopOpacity: 0.45 }),
13747
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("stop", { offset: "100%", stopColor: ACCENT_GLOW, stopOpacity: 0 })
13748
- ] }) }),
13749
13748
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
13750
13749
  import_framer_motion5.motion.ellipse,
13751
13750
  {
13752
13751
  cx,
13753
13752
  cy,
13754
- rx: w / 2 + 24,
13755
- ry: h / 2 + 24,
13756
- fill: `url(#${pulseId}-glow)`,
13753
+ rx: w / 2 + 10,
13754
+ ry: h / 2 + 10,
13755
+ fill: ACCENT_GLOW,
13757
13756
  style: {
13758
13757
  transformOrigin: `${cx}px ${cy}px`,
13759
- transformBox: "fill-box"
13758
+ transformBox: "fill-box",
13759
+ filter: "blur(16px)"
13760
13760
  },
13761
13761
  initial: { opacity: 0, scale: 0.95 },
13762
13762
  animate: {
@@ -13887,7 +13887,7 @@ function Bracket({
13887
13887
  }
13888
13888
 
13889
13889
  // src/components/TutorMode/CalloutArrow.tsx
13890
- var import_react57 = require("react");
13890
+ var import_react56 = require("react");
13891
13891
  var import_framer_motion6 = require("framer-motion");
13892
13892
  var import_jsx_runtime46 = require("react/jsx-runtime");
13893
13893
  function centerOf(b) {
@@ -13925,7 +13925,7 @@ function arrowPath(from, to, curve) {
13925
13925
  return `M ${from.x} ${from.y} Q ${cx} ${cy} ${to.x} ${to.y}`;
13926
13926
  }
13927
13927
  function CalloutArrow({ fromBbox, toBbox, action }) {
13928
- const markerId = (0, import_react57.useId)();
13928
+ const markerId = (0, import_react56.useId)();
13929
13929
  const glowId = `${markerId}-glow`;
13930
13930
  const { from, to } = edgePoints(fromBbox, toBbox);
13931
13931
  const d = arrowPath(from, to, action.curve);
@@ -14098,9 +14098,8 @@ function CinemaLayer({
14098
14098
  page,
14099
14099
  index,
14100
14100
  overlays,
14101
- coordScale
14101
+ scale
14102
14102
  }) {
14103
- if (overlays.length === 0) return null;
14104
14103
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
14105
14104
  "div",
14106
14105
  {
@@ -14109,7 +14108,7 @@ function CinemaLayer({
14109
14108
  position: "absolute",
14110
14109
  inset: 0,
14111
14110
  transformOrigin: "0 0",
14112
- transform: `scale(${coordScale})`,
14111
+ transform: `scale(${scale})`,
14113
14112
  width: page.page_dimensions.width,
14114
14113
  height: page.page_dimensions.height,
14115
14114
  pointerEvents: "none",
@@ -14699,8 +14698,7 @@ function LabelOverlay({
14699
14698
  index,
14700
14699
  currentPage,
14701
14700
  camera,
14702
- viewport,
14703
- coordScale
14701
+ viewport
14704
14702
  }) {
14705
14703
  const labels = overlays.filter((o) => o.kind === "label");
14706
14704
  const page = index.byPage.get(currentPage);
@@ -14727,8 +14725,7 @@ function LabelOverlay({
14727
14725
  a.position,
14728
14726
  page,
14729
14727
  camera,
14730
- viewport,
14731
- coordScale
14728
+ viewport
14732
14729
  );
14733
14730
  return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
14734
14731
  StickyLabel,
@@ -14742,7 +14739,7 @@ function LabelOverlay({
14742
14739
  }
14743
14740
  );
14744
14741
  }
14745
- function computeScreenAnchor(bbox, where, page, camera, viewport, coordScale) {
14742
+ function computeScreenAnchor(bbox, where, page, camera, viewport) {
14746
14743
  const [x1, y1, x2, y2] = bbox;
14747
14744
  const pageCX = page.page_dimensions.width / 2;
14748
14745
  const pageCY = page.page_dimensions.height / 2;
@@ -14768,8 +14765,8 @@ function computeScreenAnchor(bbox, where, page, camera, viewport, coordScale) {
14768
14765
  px = (x1 + x2) / 2;
14769
14766
  py = y1;
14770
14767
  }
14771
- const screenX = viewport.width / 2 + camera.x + (px - pageCX) * coordScale * camera.scale;
14772
- const screenY = viewport.height / 2 + camera.y + (py - pageCY) * coordScale * camera.scale;
14768
+ const screenX = viewport.width / 2 + camera.x + (px - pageCX) * camera.scale;
14769
+ const screenY = viewport.height / 2 + camera.y + (py - pageCY) * camera.scale;
14773
14770
  return { x: screenX, y: screenY };
14774
14771
  }
14775
14772
 
@@ -14781,8 +14778,7 @@ function CalloutLabelOverlay({
14781
14778
  index,
14782
14779
  currentPage,
14783
14780
  camera,
14784
- viewport,
14785
- coordScale
14781
+ viewport
14786
14782
  }) {
14787
14783
  const callouts = overlays.filter(
14788
14784
  (o) => o.kind === "callout" && o.action.label
@@ -14811,8 +14807,7 @@ function CalloutLabelOverlay({
14811
14807
  toHit.block.bbox,
14812
14808
  page,
14813
14809
  camera,
14814
- viewport,
14815
- coordScale
14810
+ viewport
14816
14811
  );
14817
14812
  return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
14818
14813
  CalloutLabelPill,
@@ -14827,7 +14822,7 @@ function CalloutLabelOverlay({
14827
14822
  }
14828
14823
  );
14829
14824
  }
14830
- function computePillAnchor(fromBbox, toBbox, page, camera, viewport, coordScale) {
14825
+ function computePillAnchor(fromBbox, toBbox, page, camera, viewport) {
14831
14826
  const aCX = (fromBbox[0] + fromBbox[2]) / 2;
14832
14827
  const aCY = (fromBbox[1] + fromBbox[3]) / 2;
14833
14828
  const bCX = (toBbox[0] + toBbox[2]) / 2;
@@ -14844,8 +14839,8 @@ function computePillAnchor(fromBbox, toBbox, page, camera, viewport, coordScale)
14844
14839
  const toY = bCY - uy * bOff;
14845
14840
  const pageCX = page.page_dimensions.width / 2;
14846
14841
  const pageCY = page.page_dimensions.height / 2;
14847
- const tipScreenX = viewport.width / 2 + camera.x + (toX - pageCX) * coordScale * camera.scale;
14848
- const tipScreenY = viewport.height / 2 + camera.y + (toY - pageCY) * coordScale * camera.scale;
14842
+ const tipScreenX = viewport.width / 2 + camera.x + (toX - pageCX) * camera.scale;
14843
+ const tipScreenY = viewport.height / 2 + camera.y + (toY - pageCY) * camera.scale;
14849
14844
  const isVertical = Math.abs(dy) >= Math.abs(dx);
14850
14845
  const OFFSET = resolvePillOffset(viewport.width);
14851
14846
  const MAX_PILL_W = resolveMaxPillW(viewport.width);
@@ -14988,41 +14983,6 @@ function SubtitleBar({ text }) {
14988
14983
  ) : null });
14989
14984
  }
14990
14985
 
14991
- // src/utils/render-scale.ts
14992
- function computeFitScale(input) {
14993
- const { pageWidthPt, pageHeightPt, viewport, paddingFactor = 0.95 } = input;
14994
- if (!Number.isFinite(pageWidthPt) || !Number.isFinite(pageHeightPt) || pageWidthPt <= 0 || pageHeightPt <= 0) {
14995
- return 1;
14996
- }
14997
- const w = Math.max(1, viewport.width);
14998
- const h = Math.max(1, viewport.height);
14999
- const fit = Math.min(w / pageWidthPt, h / pageHeightPt) * paddingFactor;
15000
- return Number.isFinite(fit) && fit > 0 ? fit : 1;
15001
- }
15002
- function computeCoordScale(input) {
15003
- const { renderScale, dpi } = input;
15004
- if (!Number.isFinite(renderScale) || renderScale <= 0) return 0;
15005
- if (!Number.isFinite(dpi) || dpi <= 0) return 1;
15006
- return renderScale * 72 / dpi;
15007
- }
15008
- function isTouchDevice() {
15009
- if (typeof window === "undefined") return false;
15010
- if (typeof window.matchMedia !== "function") return false;
15011
- try {
15012
- return window.matchMedia("(pointer: coarse)").matches;
15013
- } catch {
15014
- return false;
15015
- }
15016
- }
15017
- function resolveRenderScale(input) {
15018
- const { renderScaleProp, scaleProp, defaultRenderScale } = input;
15019
- if (Number.isFinite(renderScaleProp) && renderScaleProp > 0) {
15020
- return renderScaleProp;
15021
- }
15022
- const multiplier = Number.isFinite(scaleProp) && scaleProp > 0 ? scaleProp : 1;
15023
- return defaultRenderScale * multiplier;
15024
- }
15025
-
15026
14986
  // src/director/storyboard-engine.ts
15027
14987
  init_narration_store();
15028
14988
  init_camera_math();
@@ -15119,14 +15079,18 @@ var StoryboardEngine = class {
15119
15079
  this.overlayRemovalTimers.clear();
15120
15080
  }
15121
15081
  /**
15122
- * Full destructor — cancels both pending step timers AND overlay removal
15123
- * timers. Use this in component unmount/cleanup. The per-storyboard
15124
- * `cancelPending()` deliberately leaves overlay removal timers alone so a
15125
- * mid-flight overlay doesn't get stranded (see `overlayRemovalTimers` doc),
15126
- * but at destruction time we must release every timer or their closures
15082
+ * Full destructor — cancels BOTH pending step timers AND overlay
15083
+ * removal timers. Use this in component unmount / cleanup.
15084
+ *
15085
+ * The per-storyboard `cancelPending()` deliberately leaves overlay
15086
+ * removal timers alone so a mid-flight overlay doesn't get stranded
15087
+ * when a new storyboard arrives (see `overlayRemovalTimers` doc).
15088
+ * That invariant is correct inside a session, but at teardown we
15089
+ * must release every timer — otherwise their setTimeout closures
15127
15090
  * keep `deps` (narrationStore, the full bboxIndex) alive beyond the
15128
- * lifetime of this engine. On iOS Safari with many engine recreations
15129
- * this causes cumulative memory pressure and eventual tab reload.
15091
+ * lifetime of this engine. Over many component recreations on iOS
15092
+ * Safari (viewport state churns during address-bar scroll
15093
+ * animation), that cumulative retention contributes to tab reloads.
15130
15094
  */
15131
15095
  destroy() {
15132
15096
  this.cancelPending();
@@ -16279,70 +16243,42 @@ function TutorModeContainer({
16279
16243
  loadingComponent,
16280
16244
  onPageChange,
16281
16245
  storyboardProvider,
16282
- renderScale,
16283
16246
  className
16284
16247
  }) {
16285
- const containerRef = (0, import_react58.useRef)(null);
16286
- const index = (0, import_react58.useMemo)(() => buildBBoxIndex(bboxData), [bboxData]);
16248
+ const containerRef = (0, import_react57.useRef)(null);
16249
+ const index = (0, import_react57.useMemo)(() => buildBBoxIndex(bboxData), [bboxData]);
16287
16250
  const {
16288
16251
  document: document2,
16289
16252
  currentPage: viewerCurrentPage,
16290
16253
  numPages,
16291
16254
  goToPage: viewerGoToPage
16292
16255
  } = usePDFViewer();
16293
- const [pageProxy, setPageProxy] = (0, import_react58.useState)(null);
16294
- const [viewport, setViewport] = (0, import_react58.useState)({ width: 800, height: 1e3 });
16256
+ const [pageProxy, setPageProxy] = (0, import_react57.useState)(null);
16257
+ const [viewport, setViewport] = (0, import_react57.useState)({ width: 800, height: 1e3 });
16295
16258
  const camera = (0, import_zustand2.useStore)(narrationStore, (s) => s.camera);
16296
16259
  const activeOverlays = (0, import_zustand2.useStore)(narrationStore, (s) => s.activeOverlays);
16297
- const page = index.byPage.get(pageNumber);
16298
- const pagePointsW = page ? page.page_dimensions.width * 72 / page.page_dimensions.dpi : 0;
16299
- const pagePointsH = page ? page.page_dimensions.height * 72 / page.page_dimensions.dpi : 0;
16300
- const touch = isTouchDevice();
16301
- const defaultRenderScale = page ? touch ? computeFitScale({
16302
- pageWidthPt: pagePointsW,
16303
- pageHeightPt: pagePointsH,
16304
- viewport
16305
- }) : page.page_dimensions.dpi / 72 : 1;
16306
- const effectiveRenderScale = resolveRenderScale({
16307
- renderScaleProp: renderScale,
16308
- scaleProp: scale,
16309
- defaultRenderScale
16310
- });
16311
- const coordScale = page ? computeCoordScale({
16312
- renderScale: effectiveRenderScale,
16313
- dpi: page.page_dimensions.dpi
16314
- }) : 1;
16315
- const rasterScale = effectiveRenderScale;
16316
- const baseW = pagePointsW * effectiveRenderScale;
16317
- const baseH = pagePointsH * effectiveRenderScale;
16318
- (0, import_react58.useEffect)(() => {
16260
+ (0, import_react57.useEffect)(() => {
16319
16261
  if (numPages <= 0) return;
16320
16262
  if (pageNumber < 1 || pageNumber > numPages) return;
16321
16263
  if (viewerCurrentPage === pageNumber) return;
16322
16264
  viewerGoToPage(pageNumber);
16323
16265
  }, [pageNumber, numPages, viewerCurrentPage, viewerGoToPage]);
16324
- (0, import_react58.useEffect)(() => {
16266
+ (0, import_react57.useEffect)(() => {
16325
16267
  if (!onPageChange) return;
16326
16268
  if (viewerCurrentPage === pageNumber) return;
16327
16269
  if (viewerCurrentPage < 1) return;
16328
16270
  onPageChange(viewerCurrentPage);
16329
16271
  }, [viewerCurrentPage, pageNumber, onPageChange]);
16330
- (0, import_react58.useEffect)(() => {
16272
+ (0, import_react57.useEffect)(() => {
16331
16273
  if (!containerRef.current) return;
16332
16274
  const el = containerRef.current;
16333
- const update = () => {
16334
- const w = el.clientWidth;
16335
- const h = el.clientHeight;
16336
- setViewport(
16337
- (prev) => prev.width === w && prev.height === h ? prev : { width: w, height: h }
16338
- );
16339
- };
16275
+ const update = () => setViewport({ width: el.clientWidth, height: el.clientHeight });
16340
16276
  update();
16341
16277
  const ro = new ResizeObserver(update);
16342
16278
  ro.observe(el);
16343
16279
  return () => ro.disconnect();
16344
16280
  }, []);
16345
- (0, import_react58.useEffect)(() => {
16281
+ (0, import_react57.useEffect)(() => {
16346
16282
  if (!document2) {
16347
16283
  setPageProxy(null);
16348
16284
  return;
@@ -16357,40 +16293,34 @@ function TutorModeContainer({
16357
16293
  cancelled = true;
16358
16294
  };
16359
16295
  }, [document2, pageNumber]);
16360
- (0, import_react58.useEffect)(() => {
16296
+ (0, import_react57.useEffect)(() => {
16361
16297
  narrationStore.getState().setCurrentPage(pageNumber);
16362
16298
  }, [pageNumber, narrationStore]);
16363
- (0, import_react58.useEffect)(() => {
16299
+ (0, import_react57.useEffect)(() => {
16364
16300
  const page2 = index.byPage.get(pageNumber);
16365
16301
  if (!page2) return;
16366
16302
  if (viewport.width === 0 || viewport.height === 0) return;
16367
- if (baseW === 0 || baseH === 0) return;
16368
16303
  if (narrationStore.getState().activeOverlays.length > 0) return;
16369
- const fit = Math.min(viewport.width / baseW, viewport.height / baseH) * 0.95;
16304
+ const fit = Math.min(
16305
+ viewport.width / page2.page_dimensions.width,
16306
+ viewport.height / page2.page_dimensions.height
16307
+ ) * 0.95;
16370
16308
  narrationStore.getState().setCamera({ scale: fit, x: 0, y: 0 });
16371
- }, [pageNumber, viewport, index, narrationStore, baseW, baseH]);
16372
- const viewportRef = (0, import_react58.useRef)(viewport);
16373
- (0, import_react58.useEffect)(() => {
16374
- viewportRef.current = viewport;
16375
- }, [viewport]);
16376
- const engineRef = (0, import_react58.useRef)(null);
16377
- (0, import_react58.useEffect)(() => {
16378
- const engine = new StoryboardEngine({
16309
+ }, [pageNumber, viewport, index, narrationStore]);
16310
+ const engineRef = (0, import_react57.useRef)(null);
16311
+ (0, import_react57.useEffect)(() => {
16312
+ engineRef.current = new StoryboardEngine({
16379
16313
  narrationStore,
16380
16314
  bboxIndex: index,
16381
- getViewport: () => viewportRef.current,
16315
+ getViewport: () => viewport,
16382
16316
  minOverlayDurationMs
16383
16317
  });
16384
- engineRef.current = engine;
16385
- return () => {
16386
- engine.destroy();
16387
- if (engineRef.current === engine) engineRef.current = null;
16388
- };
16389
- }, [narrationStore, index, minOverlayDurationMs]);
16390
- const abortRef = (0, import_react58.useRef)(null);
16391
- const debounceRef = (0, import_react58.useRef)(null);
16392
- const lastChunkRef = (0, import_react58.useRef)(null);
16393
- (0, import_react58.useEffect)(() => {
16318
+ return () => engineRef.current?.destroy();
16319
+ }, [narrationStore, index, viewport, minOverlayDurationMs]);
16320
+ const abortRef = (0, import_react57.useRef)(null);
16321
+ const debounceRef = (0, import_react57.useRef)(null);
16322
+ const lastChunkRef = (0, import_react57.useRef)(null);
16323
+ (0, import_react57.useEffect)(() => {
16394
16324
  if (!storyboardProvider && !llm) return;
16395
16325
  if (!currentChunk || currentChunk === lastChunkRef.current) return;
16396
16326
  if (debounceRef.current) clearTimeout(debounceRef.current);
@@ -16555,7 +16485,7 @@ function TutorModeContainer({
16555
16485
  embeddingProvider,
16556
16486
  llmTimeoutMs
16557
16487
  ]);
16558
- (0, import_react58.useEffect)(() => {
16488
+ (0, import_react57.useEffect)(() => {
16559
16489
  if (!currentChunk) return;
16560
16490
  const t = setTimeout(() => {
16561
16491
  if (!engineRef.current) return;
@@ -16567,6 +16497,11 @@ function TutorModeContainer({
16567
16497
  }, idleTimeoutMs + 100);
16568
16498
  return () => clearTimeout(t);
16569
16499
  }, [currentChunk, idleTimeoutMs, narrationStore]);
16500
+ const page = index.byPage.get(pageNumber);
16501
+ const dpiScale = page ? page.page_dimensions.dpi / 72 : 1;
16502
+ const rasterScale = dpiScale * (scale || 1);
16503
+ const baseW = page ? page.page_dimensions.width * (scale || 1) : 0;
16504
+ const baseH = page ? page.page_dimensions.height * (scale || 1) : 0;
16570
16505
  const isReady = !!page && !!pageProxy;
16571
16506
  return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
16572
16507
  "div",
@@ -16645,7 +16580,7 @@ function TutorModeContainer({
16645
16580
  page,
16646
16581
  index,
16647
16582
  overlays: activeOverlays,
16648
- coordScale
16583
+ scale: scale || 1
16649
16584
  }
16650
16585
  )
16651
16586
  ]
@@ -16658,8 +16593,7 @@ function TutorModeContainer({
16658
16593
  index,
16659
16594
  currentPage: pageNumber,
16660
16595
  camera,
16661
- viewport,
16662
- coordScale
16596
+ viewport
16663
16597
  }
16664
16598
  ),
16665
16599
  /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
@@ -16669,8 +16603,7 @@ function TutorModeContainer({
16669
16603
  index,
16670
16604
  currentPage: pageNumber,
16671
16605
  camera,
16672
- viewport,
16673
- coordScale
16606
+ viewport
16674
16607
  }
16675
16608
  ),
16676
16609
  /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(GhostReferenceOverlay, { overlays: activeOverlays, index })