@promptbook/remote-server 0.112.0-117 → 0.112.0-119

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.
Files changed (37) hide show
  1. package/esm/index.es.js +197 -44
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/src/_packages/node.index.d.ts +10 -0
  4. package/esm/src/book-3.0/BookNodeAgentSource.d.ts +1 -1
  5. package/esm/src/book-3.0/CliAgent.d.ts +7 -2
  6. package/esm/src/book-3.0/cliAgentEnv.d.ts +33 -0
  7. package/esm/src/book-components/BookEditor/BookEditor.d.ts +1 -1
  8. package/esm/src/book-components/BookEditor/BookEditorForClient.d.ts +1 -1
  9. package/esm/src/book-components/Chat/Chat/CitationIframePreview.d.ts +20 -0
  10. package/esm/src/book-components/_common/Dropdown/Dropdown.d.ts +1 -1
  11. package/esm/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +1 -1
  12. package/esm/src/book-components/_common/Modal/Modal.d.ts +1 -1
  13. package/esm/src/book-components/icons/AboutIcon.d.ts +1 -1
  14. package/esm/src/book-components/icons/DownloadIcon.d.ts +1 -1
  15. package/esm/src/book-components/icons/ExitFullscreenIcon.d.ts +1 -1
  16. package/esm/src/book-components/icons/FullscreenIcon.d.ts +1 -1
  17. package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +2 -18
  18. package/esm/src/version.d.ts +1 -1
  19. package/package.json +2 -2
  20. package/umd/index.umd.js +197 -44
  21. package/umd/index.umd.js.map +1 -1
  22. package/umd/src/_packages/node.index.d.ts +10 -0
  23. package/umd/src/book-3.0/BookNodeAgentSource.d.ts +1 -1
  24. package/umd/src/book-3.0/CliAgent.d.ts +7 -2
  25. package/umd/src/book-3.0/cliAgentEnv.d.ts +33 -0
  26. package/umd/src/book-components/BookEditor/BookEditor.d.ts +1 -1
  27. package/umd/src/book-components/BookEditor/BookEditorForClient.d.ts +1 -1
  28. package/umd/src/book-components/Chat/Chat/CitationIframePreview.d.ts +20 -0
  29. package/umd/src/book-components/_common/Dropdown/Dropdown.d.ts +1 -1
  30. package/umd/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +1 -1
  31. package/umd/src/book-components/_common/Modal/Modal.d.ts +1 -1
  32. package/umd/src/book-components/icons/AboutIcon.d.ts +1 -1
  33. package/umd/src/book-components/icons/DownloadIcon.d.ts +1 -1
  34. package/umd/src/book-components/icons/ExitFullscreenIcon.d.ts +1 -1
  35. package/umd/src/book-components/icons/FullscreenIcon.d.ts +1 -1
  36. package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +2 -18
  37. package/umd/src/version.d.ts +1 -1
package/esm/index.es.js CHANGED
@@ -39,7 +39,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
39
39
  * @generated
40
40
  * @see https://github.com/webgptorg/promptbook
41
41
  */
42
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-117';
42
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-119';
43
43
  /**
44
44
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
45
45
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -14239,21 +14239,22 @@ function getPointBounds(points) {
14239
14239
  * @private helper of `fractalAvatarVisual`
14240
14240
  */
14241
14241
  function drawDragonCurveLayer(context, points, options) {
14242
- const { size, primaryColor, secondaryColor, tertiaryColor, shadowColor, strokeWidth, timeMs, layerIndex } = options;
14242
+ const { primaryColor, secondaryColor, tertiaryColor, shadowColor, strokeWidth, timeMs, layerIndex } = options;
14243
14243
  const firstPoint = points[0];
14244
14244
  const lastPoint = points[points.length - 1];
14245
14245
  const ribbonGradient = context.createLinearGradient(firstPoint.x, firstPoint.y, lastPoint.x, lastPoint.y);
14246
14246
  ribbonGradient.addColorStop(0, `${primaryColor}f2`);
14247
14247
  ribbonGradient.addColorStop(0.5, `${secondaryColor}e6`);
14248
14248
  ribbonGradient.addColorStop(1, `${tertiaryColor}f2`);
14249
+ // Approximate the blurred shadow stroke with a wider semi-transparent stroke instead of
14250
+ // context.filter blur, which triggers a costly software rasterization pass every frame.
14249
14251
  context.save();
14250
14252
  context.beginPath();
14251
14253
  tracePolyline(context, points);
14252
- context.strokeStyle = `${shadowColor}82`;
14253
- context.lineWidth = strokeWidth * 1.8;
14254
+ context.strokeStyle = `${shadowColor}48`;
14255
+ context.lineWidth = strokeWidth * 4.5;
14254
14256
  context.lineJoin = 'round';
14255
14257
  context.lineCap = 'round';
14256
- context.filter = `blur(${size * 0.022}px)`;
14257
14258
  context.stroke();
14258
14259
  context.restore();
14259
14260
  context.beginPath();
@@ -14837,11 +14838,23 @@ function drawMinecraftBackdrop(context, size, palette, sceneCenterX, spotlightY,
14837
14838
  * @private helper of `minecraft2AvatarVisual`
14838
14839
  */
14839
14840
  function drawMinecraftShadow(context, size, palette, interaction, timeMs) {
14841
+ const cx = size * 0.5 + interaction.gazeX * size * 0.03;
14842
+ const cy = size * 0.85 + Math.sin(timeMs / 880) * size * 0.01;
14843
+ const rx = size * (0.16 + interaction.intensity * 0.015);
14844
+ const ry = size * 0.055;
14845
+ // Radial gradient approximates the blurry ellipse shadow without context.filter blur.
14840
14846
  context.save();
14841
- context.fillStyle = `${palette.shadow}66`;
14842
- context.filter = `blur(${size * 0.02}px)`;
14847
+ context.translate(cx, cy);
14848
+ context.scale(1, ry / rx);
14849
+ const blurRadius = rx * 1.4;
14850
+ const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
14851
+ shadowGradient.addColorStop(0, `${palette.shadow}7a`);
14852
+ shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
14853
+ shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
14854
+ shadowGradient.addColorStop(1, `${palette.shadow}00`);
14855
+ context.fillStyle = shadowGradient;
14843
14856
  context.beginPath();
14844
- context.ellipse(size * 0.5 + interaction.gazeX * size * 0.03, size * 0.85 + Math.sin(timeMs / 880) * size * 0.01, size * (0.16 + interaction.intensity * 0.015), size * 0.055, 0, 0, Math.PI * 2);
14857
+ context.arc(0, 0, blurRadius, 0, Math.PI * 2);
14845
14858
  context.fill();
14846
14859
  context.restore();
14847
14860
  }
@@ -15065,13 +15078,27 @@ const minecraftAvatarVisual = {
15065
15078
  spotlight.addColorStop(1, `${palette.highlight}00`);
15066
15079
  context.fillStyle = spotlight;
15067
15080
  context.fillRect(0, 0, size, size);
15068
- context.save();
15069
- context.fillStyle = 'rgba(0, 0, 0, 0.22)';
15070
- context.filter = `blur(${size * 0.018}px)`;
15071
- context.beginPath();
15072
- context.ellipse(size * 0.5, size * 0.86, size * 0.2, size * 0.06, 0, 0, Math.PI * 2);
15073
- context.fill();
15074
- context.restore();
15081
+ {
15082
+ // Radial gradient approximates the blurry ellipse shadow without context.filter blur.
15083
+ const cx = size * 0.5;
15084
+ const cy = size * 0.86;
15085
+ const rx = size * 0.2;
15086
+ const ry = size * 0.06;
15087
+ const blurRadius = rx * 1.4;
15088
+ const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
15089
+ shadowGradient.addColorStop(0, 'rgba(0,0,0,0.28)');
15090
+ shadowGradient.addColorStop(0.45, 'rgba(0,0,0,0.14)');
15091
+ shadowGradient.addColorStop(0.8, 'rgba(0,0,0,0.05)');
15092
+ shadowGradient.addColorStop(1, 'rgba(0,0,0,0)');
15093
+ context.save();
15094
+ context.translate(cx, cy);
15095
+ context.scale(1, ry / rx);
15096
+ context.fillStyle = shadowGradient;
15097
+ context.beginPath();
15098
+ context.arc(0, 0, blurRadius, 0, Math.PI * 2);
15099
+ context.fill();
15100
+ context.restore();
15101
+ }
15075
15102
  drawVoxelCuboid(context, {
15076
15103
  x: bodyX,
15077
15104
  y: bodyY,
@@ -16123,6 +16150,35 @@ const LIGHT_DIRECTION$2 = normalizeVector3({
16123
16150
  y: -0.62,
16124
16151
  z: 0.94,
16125
16152
  });
16153
+ /**
16154
+ * Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
16155
+ *
16156
+ * @private helper of `octopus3dAvatarVisual`
16157
+ */
16158
+ const octopus3dStableStateCache = new WeakMap();
16159
+ /**
16160
+ * Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
16161
+ *
16162
+ * @private helper of `octopus3dAvatarVisual`
16163
+ */
16164
+ function getOctopus3dStableState(createRandom) {
16165
+ const cached = octopus3dStableStateCache.get(createRandom);
16166
+ if (cached !== undefined) {
16167
+ return cached;
16168
+ }
16169
+ const animationRandom = createRandom('octopus3d-animation-profile');
16170
+ const eyeRandom = createRandom('octopus3d-eye-profile');
16171
+ const leftEyePhaseOffset = eyeRandom() * 0.6;
16172
+ const rightEyePhaseOffset = eyeRandom() * 0.6;
16173
+ const state = {
16174
+ morphologyProfile: createOctopus3MorphologyProfile(createRandom),
16175
+ animationPhase: animationRandom() * Math.PI * 2,
16176
+ leftEyePhaseOffset,
16177
+ rightEyePhaseOffset,
16178
+ };
16179
+ octopus3dStableStateCache.set(createRandom, state);
16180
+ return state;
16181
+ }
16126
16182
  /**
16127
16183
  * Proper 3D Octopus visual built from projected organic meshes and tentacles.
16128
16184
  *
@@ -16135,10 +16191,7 @@ const octopus3dAvatarVisual = {
16135
16191
  isAnimated: true,
16136
16192
  supportsPointerTracking: true,
16137
16193
  render({ context, size, palette, createRandom, timeMs, interaction }) {
16138
- const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
16139
- const animationRandom = createRandom('octopus3d-animation-profile');
16140
- const eyeRandom = createRandom('octopus3d-eye-profile');
16141
- const animationPhase = animationRandom() * Math.PI * 2;
16194
+ const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
16142
16195
  const sceneCenterX = size * 0.5;
16143
16196
  const sceneCenterY = size * 0.56;
16144
16197
  const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
@@ -16235,12 +16288,12 @@ const octopus3dAvatarVisual = {
16235
16288
  x: -faceEyeSpacing,
16236
16289
  y: faceEyeYOffset,
16237
16290
  z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
16238
- }, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
16291
+ }, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
16239
16292
  drawProjectedOrganicEye(context, {
16240
16293
  x: faceEyeSpacing,
16241
16294
  y: faceEyeYOffset,
16242
16295
  z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
16243
- }, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
16296
+ }, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
16244
16297
  drawProjectedOrganicMouth(context, [
16245
16298
  {
16246
16299
  x: -mouthHalfWidth,
@@ -16284,14 +16337,28 @@ function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCent
16284
16337
  /**
16285
16338
  * Draws the soft ground shadow below the octopus.
16286
16339
  *
16340
+ * Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
16341
+ * blurry ellipse without triggering a costly software rasterization pass on every frame.
16342
+ *
16287
16343
  * @private helper of `octopus3dAvatarVisual`
16288
16344
  */
16289
16345
  function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
16346
+ const cx = size * 0.5 + interaction.gazeX * size * 0.04;
16347
+ const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
16348
+ const rx = size * (0.18 + interaction.intensity * 0.02);
16349
+ const ry = size * 0.06;
16290
16350
  context.save();
16291
- context.fillStyle = `${palette.shadow}66`;
16292
- context.filter = `blur(${size * 0.022}px)`;
16351
+ context.translate(cx, cy);
16352
+ context.scale(1, ry / rx);
16353
+ const blurRadius = rx * 1.4;
16354
+ const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
16355
+ shadowGradient.addColorStop(0, `${palette.shadow}7a`);
16356
+ shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
16357
+ shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
16358
+ shadowGradient.addColorStop(1, `${palette.shadow}00`);
16359
+ context.fillStyle = shadowGradient;
16293
16360
  context.beginPath();
16294
- context.ellipse(size * 0.5 + interaction.gazeX * size * 0.04, size * 0.87 + Math.sin(timeMs / 920) * size * 0.008, size * (0.18 + interaction.intensity * 0.02), size * 0.06, 0, 0, Math.PI * 2);
16361
+ context.arc(0, 0, blurRadius, 0, Math.PI * 2);
16295
16362
  context.fill();
16296
16363
  context.restore();
16297
16364
  }
@@ -16522,6 +16589,35 @@ const LIGHT_DIRECTION$1 = normalizeVector3({
16522
16589
  y: -0.6,
16523
16590
  z: 0.98,
16524
16591
  });
16592
+ /**
16593
+ * Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
16594
+ *
16595
+ * @private helper of `octopus3d2AvatarVisual`
16596
+ */
16597
+ const octopus3d2StableStateCache = new WeakMap();
16598
+ /**
16599
+ * Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
16600
+ *
16601
+ * @private helper of `octopus3d2AvatarVisual`
16602
+ */
16603
+ function getOctopus3d2StableState(createRandom) {
16604
+ const cached = octopus3d2StableStateCache.get(createRandom);
16605
+ if (cached !== undefined) {
16606
+ return cached;
16607
+ }
16608
+ const animationRandom = createRandom('octopus3d2-animation-profile');
16609
+ const eyeRandom = createRandom('octopus3d2-eye-profile');
16610
+ const leftEyePhaseOffset = eyeRandom() * 0.7;
16611
+ const rightEyePhaseOffset = eyeRandom() * 0.7;
16612
+ const state = {
16613
+ morphologyProfile: createOctopus3MorphologyProfile(createRandom),
16614
+ animationPhase: animationRandom() * Math.PI * 2,
16615
+ leftEyePhaseOffset,
16616
+ rightEyePhaseOffset,
16617
+ };
16618
+ octopus3d2StableStateCache.set(createRandom, state);
16619
+ return state;
16620
+ }
16525
16621
  /**
16526
16622
  * Octopus 3D 2 avatar visual.
16527
16623
  *
@@ -16534,10 +16630,7 @@ const octopus3d2AvatarVisual = {
16534
16630
  isAnimated: true,
16535
16631
  supportsPointerTracking: true,
16536
16632
  render({ context, size, palette, createRandom, timeMs, interaction }) {
16537
- const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
16538
- const animationRandom = createRandom('octopus3d2-animation-profile');
16539
- const eyeRandom = createRandom('octopus3d2-eye-profile');
16540
- const animationPhase = animationRandom() * Math.PI * 2;
16633
+ const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3d2StableState(createRandom);
16541
16634
  const sceneCenterX = size * 0.5;
16542
16635
  const sceneCenterY = size * 0.575;
16543
16636
  const bob = Math.sin(timeMs / 940 + animationPhase) * size * 0.013;
@@ -16590,8 +16683,8 @@ const octopus3d2AvatarVisual = {
16590
16683
  const rightEyeLocalCenter = sampleBlobbyOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude);
16591
16684
  const eyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.78;
16592
16685
  const eyeRadiusY = eyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.92;
16593
- drawProjectedOrganicEye(context, leftEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
16594
- drawProjectedOrganicEye(context, rightEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.9 + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
16686
+ drawProjectedOrganicEye(context, leftEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
16687
+ drawProjectedOrganicEye(context, rightEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.9 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
16595
16688
  drawProjectedOrganicMouth(context, [
16596
16689
  sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
16597
16690
  sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
@@ -16620,14 +16713,28 @@ function drawBlobbyOctopusAtmosphere(context, size, palette, sceneCenterX, scene
16620
16713
  /**
16621
16714
  * Draws the soft floor shadow that anchors the single mesh in the frame.
16622
16715
  *
16716
+ * Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
16717
+ * blurry ellipse without triggering a costly software rasterization pass on every frame.
16718
+ *
16623
16719
  * @private helper of `octopus3d2AvatarVisual`
16624
16720
  */
16625
16721
  function drawBlobbyOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
16722
+ const cx = size * 0.5 + interaction.gazeX * size * 0.045;
16723
+ const cy = size * 0.88 + Math.sin(timeMs / 940) * size * 0.008;
16724
+ const rx = size * (0.18 + (morphologyProfile.body.horizontalStretch - 1) * 0.04 + interaction.intensity * 0.018);
16725
+ const ry = size * 0.062;
16626
16726
  context.save();
16627
- context.fillStyle = `${palette.shadow}66`;
16628
- context.filter = `blur(${size * 0.024}px)`;
16727
+ context.translate(cx, cy);
16728
+ context.scale(1, ry / rx);
16729
+ const blurRadius = rx * 1.4;
16730
+ const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
16731
+ shadowGradient.addColorStop(0, `${palette.shadow}7a`);
16732
+ shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
16733
+ shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
16734
+ shadowGradient.addColorStop(1, `${palette.shadow}00`);
16735
+ context.fillStyle = shadowGradient;
16629
16736
  context.beginPath();
16630
- context.ellipse(size * 0.5 + interaction.gazeX * size * 0.045, size * 0.88 + Math.sin(timeMs / 940) * size * 0.008, size * (0.18 + (morphologyProfile.body.horizontalStretch - 1) * 0.04 + interaction.intensity * 0.018), size * 0.062, 0, 0, Math.PI * 2);
16737
+ context.arc(0, 0, blurRadius, 0, Math.PI * 2);
16631
16738
  context.fill();
16632
16739
  context.restore();
16633
16740
  }
@@ -16783,6 +16890,40 @@ const LIGHT_DIRECTION = normalizeVector3({
16783
16890
  * @private helper of `octopus3d3AvatarVisual`
16784
16891
  */
16785
16892
  const OCTOPUS_TENTACLE_COUNT = 8;
16893
+ /**
16894
+ * Cache keyed by the `createRandom` factory reference, which is stable for the lifetime of one
16895
+ * mounted `<Avatar/>` component (created inside `resolveAvatarRenderDefinition` and held in a
16896
+ * React `useMemo`). Using a `WeakMap` ensures the entry is collected when the component unmounts.
16897
+ *
16898
+ * @private helper of `octopus3d3AvatarVisual`
16899
+ */
16900
+ const stableStateCache = new WeakMap();
16901
+ /**
16902
+ * Returns the stable per-avatar state, computing it on first access and returning the cached
16903
+ * result on every subsequent call within the same `<Avatar/>` mount.
16904
+ *
16905
+ * @private helper of `octopus3d3AvatarVisual`
16906
+ */
16907
+ function getOctopus3d3StableState(createRandom) {
16908
+ const cached = stableStateCache.get(createRandom);
16909
+ if (cached !== undefined) {
16910
+ return cached;
16911
+ }
16912
+ const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
16913
+ const animationRandom = createRandom('octopus3d3-animation-profile');
16914
+ const eyeRandom = createRandom('octopus3d3-eye-profile');
16915
+ const leftEyePhaseOffset = eyeRandom() * 0.7;
16916
+ const rightEyePhaseOffset = eyeRandom() * 0.7;
16917
+ const state = {
16918
+ morphologyProfile,
16919
+ animationPhase: animationRandom() * Math.PI * 2,
16920
+ leftEyePhaseOffset,
16921
+ rightEyePhaseOffset,
16922
+ tentacleProfiles: createContinuousTentacleProfiles(createRandom, morphologyProfile),
16923
+ };
16924
+ stableStateCache.set(createRandom, state);
16925
+ return state;
16926
+ }
16786
16927
  /**
16787
16928
  * Octopus 3D 3 avatar visual.
16788
16929
  *
@@ -16795,11 +16936,7 @@ const octopus3d3AvatarVisual = {
16795
16936
  isAnimated: true,
16796
16937
  supportsPointerTracking: true,
16797
16938
  render({ context, size, palette, createRandom, timeMs, interaction }) {
16798
- const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
16799
- const animationRandom = createRandom('octopus3d3-animation-profile');
16800
- const eyeRandom = createRandom('octopus3d3-eye-profile');
16801
- const animationPhase = animationRandom() * Math.PI * 2;
16802
- const tentacleProfiles = createContinuousTentacleProfiles(createRandom, morphologyProfile);
16939
+ const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset, tentacleProfiles } = getOctopus3d3StableState(createRandom);
16803
16940
  const sceneCenterX = size * 0.5;
16804
16941
  const sceneCenterY = size * 0.535;
16805
16942
  const bob = Math.sin(timeMs / 960 + animationPhase) * size * 0.012;
@@ -16876,8 +17013,8 @@ const octopus3d3AvatarVisual = {
16876
17013
  size,
16877
17014
  palette,
16878
17015
  });
16879
- drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
16880
- drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.85 + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
17016
+ drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
17017
+ drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.85 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
16881
17018
  drawProjectedOrganicMouth(context, [
16882
17019
  sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
16883
17020
  sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
@@ -16928,14 +17065,30 @@ function drawContinuousOctopusAtmosphere(context, size, palette, sceneCenterX, s
16928
17065
  /**
16929
17066
  * Draws the soft lower shadow that anchors the octopus in the avatar frame.
16930
17067
  *
17068
+ * Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
17069
+ * blurry ellipse without triggering a costly software rasterization pass on every frame.
17070
+ *
16931
17071
  * @private helper of `octopus3d3AvatarVisual`
16932
17072
  */
16933
17073
  function drawContinuousOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
17074
+ const cx = size * 0.5 + interaction.gazeX * size * 0.045;
17075
+ const cy = size * 0.9 + Math.sin(timeMs / 980) * size * 0.007;
17076
+ const rx = size * (0.19 + morphologyProfile.tentacles.rootSpreadScale * 0.022 + interaction.intensity * 0.02);
17077
+ const ry = size * 0.06;
17078
+ // Scale the context so that drawing a circle produces the correct ellipse aspect ratio,
17079
+ // then fill with a radial gradient that approximates the blurry edge without context.filter.
16934
17080
  context.save();
16935
- context.fillStyle = `${palette.shadow}66`;
16936
- context.filter = `blur(${size * 0.025}px)`;
17081
+ context.translate(cx, cy);
17082
+ context.scale(1, ry / rx);
17083
+ const blurRadius = rx * 1.4;
17084
+ const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
17085
+ shadowGradient.addColorStop(0, `${palette.shadow}7a`);
17086
+ shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
17087
+ shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
17088
+ shadowGradient.addColorStop(1, `${palette.shadow}00`);
17089
+ context.fillStyle = shadowGradient;
16937
17090
  context.beginPath();
16938
- context.ellipse(size * 0.5 + interaction.gazeX * size * 0.045, size * 0.9 + Math.sin(timeMs / 980) * size * 0.007, size * (0.19 + morphologyProfile.tentacles.rootSpreadScale * 0.022 + interaction.intensity * 0.02), size * 0.06, 0, 0, Math.PI * 2);
17091
+ context.arc(0, 0, blurRadius, 0, Math.PI * 2);
16939
17092
  context.fill();
16940
17093
  context.restore();
16941
17094
  }
@@ -37920,7 +38073,7 @@ class OpenAiVectorStoreKnowledgeSourcePreparer {
37920
38073
  return { skippedReason: 'invalid_data_url' };
37921
38074
  }
37922
38075
  return {
37923
- file: new File([parsed.buffer], parsed.filename, {
38076
+ file: new File([new Uint8Array(parsed.buffer)], parsed.filename, {
37924
38077
  type: parsed.mimeType,
37925
38078
  }),
37926
38079
  sizeBytes: parsed.buffer.length,