@promptbook/core 0.112.0-117 → 0.112.0-118
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/esm/index.es.js +199 -44
- package/esm/index.es.js.map +1 -1
- package/esm/src/_packages/node.index.d.ts +10 -0
- package/esm/src/book-3.0/BookNodeAgentSource.d.ts +1 -1
- package/esm/src/book-3.0/CliAgent.d.ts +7 -2
- package/esm/src/book-3.0/cliAgentEnv.d.ts +33 -0
- package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +2 -18
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +199 -44
- package/umd/index.umd.js.map +1 -1
- package/umd/src/_packages/node.index.d.ts +10 -0
- package/umd/src/book-3.0/BookNodeAgentSource.d.ts +1 -1
- package/umd/src/book-3.0/CliAgent.d.ts +7 -2
- package/umd/src/book-3.0/cliAgentEnv.d.ts +33 -0
- package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +2 -18
- package/umd/src/version.d.ts +1 -1
package/esm/index.es.js
CHANGED
|
@@ -28,7 +28,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
28
28
|
* @generated
|
|
29
29
|
* @see https://github.com/webgptorg/promptbook
|
|
30
30
|
*/
|
|
31
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
31
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-118';
|
|
32
32
|
/**
|
|
33
33
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
34
34
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -13063,21 +13063,22 @@ function getPointBounds(points) {
|
|
|
13063
13063
|
* @private helper of `fractalAvatarVisual`
|
|
13064
13064
|
*/
|
|
13065
13065
|
function drawDragonCurveLayer(context, points, options) {
|
|
13066
|
-
const {
|
|
13066
|
+
const { primaryColor, secondaryColor, tertiaryColor, shadowColor, strokeWidth, timeMs, layerIndex } = options;
|
|
13067
13067
|
const firstPoint = points[0];
|
|
13068
13068
|
const lastPoint = points[points.length - 1];
|
|
13069
13069
|
const ribbonGradient = context.createLinearGradient(firstPoint.x, firstPoint.y, lastPoint.x, lastPoint.y);
|
|
13070
13070
|
ribbonGradient.addColorStop(0, `${primaryColor}f2`);
|
|
13071
13071
|
ribbonGradient.addColorStop(0.5, `${secondaryColor}e6`);
|
|
13072
13072
|
ribbonGradient.addColorStop(1, `${tertiaryColor}f2`);
|
|
13073
|
+
// Approximate the blurred shadow stroke with a wider semi-transparent stroke instead of
|
|
13074
|
+
// context.filter blur, which triggers a costly software rasterization pass every frame.
|
|
13073
13075
|
context.save();
|
|
13074
13076
|
context.beginPath();
|
|
13075
13077
|
tracePolyline(context, points);
|
|
13076
|
-
context.strokeStyle = `${shadowColor}
|
|
13077
|
-
context.lineWidth = strokeWidth *
|
|
13078
|
+
context.strokeStyle = `${shadowColor}48`;
|
|
13079
|
+
context.lineWidth = strokeWidth * 4.5;
|
|
13078
13080
|
context.lineJoin = 'round';
|
|
13079
13081
|
context.lineCap = 'round';
|
|
13080
|
-
context.filter = `blur(${size * 0.022}px)`;
|
|
13081
13082
|
context.stroke();
|
|
13082
13083
|
context.restore();
|
|
13083
13084
|
context.beginPath();
|
|
@@ -13661,11 +13662,23 @@ function drawMinecraftBackdrop(context, size, palette, sceneCenterX, spotlightY,
|
|
|
13661
13662
|
* @private helper of `minecraft2AvatarVisual`
|
|
13662
13663
|
*/
|
|
13663
13664
|
function drawMinecraftShadow(context, size, palette, interaction, timeMs) {
|
|
13665
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.03;
|
|
13666
|
+
const cy = size * 0.85 + Math.sin(timeMs / 880) * size * 0.01;
|
|
13667
|
+
const rx = size * (0.16 + interaction.intensity * 0.015);
|
|
13668
|
+
const ry = size * 0.055;
|
|
13669
|
+
// Radial gradient approximates the blurry ellipse shadow without context.filter blur.
|
|
13664
13670
|
context.save();
|
|
13665
|
-
context.
|
|
13666
|
-
context.
|
|
13671
|
+
context.translate(cx, cy);
|
|
13672
|
+
context.scale(1, ry / rx);
|
|
13673
|
+
const blurRadius = rx * 1.4;
|
|
13674
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
13675
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
13676
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
13677
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
13678
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
13679
|
+
context.fillStyle = shadowGradient;
|
|
13667
13680
|
context.beginPath();
|
|
13668
|
-
context.
|
|
13681
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
13669
13682
|
context.fill();
|
|
13670
13683
|
context.restore();
|
|
13671
13684
|
}
|
|
@@ -13889,13 +13902,27 @@ const minecraftAvatarVisual = {
|
|
|
13889
13902
|
spotlight.addColorStop(1, `${palette.highlight}00`);
|
|
13890
13903
|
context.fillStyle = spotlight;
|
|
13891
13904
|
context.fillRect(0, 0, size, size);
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
13898
|
-
|
|
13905
|
+
{
|
|
13906
|
+
// Radial gradient approximates the blurry ellipse shadow without context.filter blur.
|
|
13907
|
+
const cx = size * 0.5;
|
|
13908
|
+
const cy = size * 0.86;
|
|
13909
|
+
const rx = size * 0.2;
|
|
13910
|
+
const ry = size * 0.06;
|
|
13911
|
+
const blurRadius = rx * 1.4;
|
|
13912
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
13913
|
+
shadowGradient.addColorStop(0, 'rgba(0,0,0,0.28)');
|
|
13914
|
+
shadowGradient.addColorStop(0.45, 'rgba(0,0,0,0.14)');
|
|
13915
|
+
shadowGradient.addColorStop(0.8, 'rgba(0,0,0,0.05)');
|
|
13916
|
+
shadowGradient.addColorStop(1, 'rgba(0,0,0,0)');
|
|
13917
|
+
context.save();
|
|
13918
|
+
context.translate(cx, cy);
|
|
13919
|
+
context.scale(1, ry / rx);
|
|
13920
|
+
context.fillStyle = shadowGradient;
|
|
13921
|
+
context.beginPath();
|
|
13922
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
13923
|
+
context.fill();
|
|
13924
|
+
context.restore();
|
|
13925
|
+
}
|
|
13899
13926
|
drawVoxelCuboid(context, {
|
|
13900
13927
|
x: bodyX,
|
|
13901
13928
|
y: bodyY,
|
|
@@ -14947,6 +14974,35 @@ const LIGHT_DIRECTION$2 = normalizeVector3({
|
|
|
14947
14974
|
y: -0.62,
|
|
14948
14975
|
z: 0.94,
|
|
14949
14976
|
});
|
|
14977
|
+
/**
|
|
14978
|
+
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
14979
|
+
*
|
|
14980
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14981
|
+
*/
|
|
14982
|
+
const octopus3dStableStateCache = new WeakMap();
|
|
14983
|
+
/**
|
|
14984
|
+
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
14985
|
+
*
|
|
14986
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14987
|
+
*/
|
|
14988
|
+
function getOctopus3dStableState(createRandom) {
|
|
14989
|
+
const cached = octopus3dStableStateCache.get(createRandom);
|
|
14990
|
+
if (cached !== undefined) {
|
|
14991
|
+
return cached;
|
|
14992
|
+
}
|
|
14993
|
+
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
14994
|
+
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
14995
|
+
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
14996
|
+
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
14997
|
+
const state = {
|
|
14998
|
+
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
14999
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
15000
|
+
leftEyePhaseOffset,
|
|
15001
|
+
rightEyePhaseOffset,
|
|
15002
|
+
};
|
|
15003
|
+
octopus3dStableStateCache.set(createRandom, state);
|
|
15004
|
+
return state;
|
|
15005
|
+
}
|
|
14950
15006
|
/**
|
|
14951
15007
|
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
14952
15008
|
*
|
|
@@ -14959,10 +15015,7 @@ const octopus3dAvatarVisual = {
|
|
|
14959
15015
|
isAnimated: true,
|
|
14960
15016
|
supportsPointerTracking: true,
|
|
14961
15017
|
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
14962
|
-
const morphologyProfile =
|
|
14963
|
-
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
14964
|
-
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
14965
|
-
const animationPhase = animationRandom() * Math.PI * 2;
|
|
15018
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
14966
15019
|
const sceneCenterX = size * 0.5;
|
|
14967
15020
|
const sceneCenterY = size * 0.56;
|
|
14968
15021
|
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
@@ -15059,12 +15112,12 @@ const octopus3dAvatarVisual = {
|
|
|
15059
15112
|
x: -faceEyeSpacing,
|
|
15060
15113
|
y: faceEyeYOffset,
|
|
15061
15114
|
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
15062
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase +
|
|
15115
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
15063
15116
|
drawProjectedOrganicEye(context, {
|
|
15064
15117
|
x: faceEyeSpacing,
|
|
15065
15118
|
y: faceEyeYOffset,
|
|
15066
15119
|
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
15067
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 +
|
|
15120
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
15068
15121
|
drawProjectedOrganicMouth(context, [
|
|
15069
15122
|
{
|
|
15070
15123
|
x: -mouthHalfWidth,
|
|
@@ -15108,14 +15161,28 @@ function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCent
|
|
|
15108
15161
|
/**
|
|
15109
15162
|
* Draws the soft ground shadow below the octopus.
|
|
15110
15163
|
*
|
|
15164
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
15165
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
15166
|
+
*
|
|
15111
15167
|
* @private helper of `octopus3dAvatarVisual`
|
|
15112
15168
|
*/
|
|
15113
15169
|
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
15170
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
15171
|
+
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
15172
|
+
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
15173
|
+
const ry = size * 0.06;
|
|
15114
15174
|
context.save();
|
|
15115
|
-
context.
|
|
15116
|
-
context.
|
|
15175
|
+
context.translate(cx, cy);
|
|
15176
|
+
context.scale(1, ry / rx);
|
|
15177
|
+
const blurRadius = rx * 1.4;
|
|
15178
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
15179
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
15180
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
15181
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
15182
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
15183
|
+
context.fillStyle = shadowGradient;
|
|
15117
15184
|
context.beginPath();
|
|
15118
|
-
context.
|
|
15185
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
15119
15186
|
context.fill();
|
|
15120
15187
|
context.restore();
|
|
15121
15188
|
}
|
|
@@ -15346,6 +15413,35 @@ const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
|
15346
15413
|
y: -0.6,
|
|
15347
15414
|
z: 0.98,
|
|
15348
15415
|
});
|
|
15416
|
+
/**
|
|
15417
|
+
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
15418
|
+
*
|
|
15419
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
15420
|
+
*/
|
|
15421
|
+
const octopus3d2StableStateCache = new WeakMap();
|
|
15422
|
+
/**
|
|
15423
|
+
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
15424
|
+
*
|
|
15425
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
15426
|
+
*/
|
|
15427
|
+
function getOctopus3d2StableState(createRandom) {
|
|
15428
|
+
const cached = octopus3d2StableStateCache.get(createRandom);
|
|
15429
|
+
if (cached !== undefined) {
|
|
15430
|
+
return cached;
|
|
15431
|
+
}
|
|
15432
|
+
const animationRandom = createRandom('octopus3d2-animation-profile');
|
|
15433
|
+
const eyeRandom = createRandom('octopus3d2-eye-profile');
|
|
15434
|
+
const leftEyePhaseOffset = eyeRandom() * 0.7;
|
|
15435
|
+
const rightEyePhaseOffset = eyeRandom() * 0.7;
|
|
15436
|
+
const state = {
|
|
15437
|
+
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
15438
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
15439
|
+
leftEyePhaseOffset,
|
|
15440
|
+
rightEyePhaseOffset,
|
|
15441
|
+
};
|
|
15442
|
+
octopus3d2StableStateCache.set(createRandom, state);
|
|
15443
|
+
return state;
|
|
15444
|
+
}
|
|
15349
15445
|
/**
|
|
15350
15446
|
* Octopus 3D 2 avatar visual.
|
|
15351
15447
|
*
|
|
@@ -15358,10 +15454,7 @@ const octopus3d2AvatarVisual = {
|
|
|
15358
15454
|
isAnimated: true,
|
|
15359
15455
|
supportsPointerTracking: true,
|
|
15360
15456
|
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
15361
|
-
const morphologyProfile =
|
|
15362
|
-
const animationRandom = createRandom('octopus3d2-animation-profile');
|
|
15363
|
-
const eyeRandom = createRandom('octopus3d2-eye-profile');
|
|
15364
|
-
const animationPhase = animationRandom() * Math.PI * 2;
|
|
15457
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3d2StableState(createRandom);
|
|
15365
15458
|
const sceneCenterX = size * 0.5;
|
|
15366
15459
|
const sceneCenterY = size * 0.575;
|
|
15367
15460
|
const bob = Math.sin(timeMs / 940 + animationPhase) * size * 0.013;
|
|
@@ -15414,8 +15507,8 @@ const octopus3d2AvatarVisual = {
|
|
|
15414
15507
|
const rightEyeLocalCenter = sampleBlobbyOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude);
|
|
15415
15508
|
const eyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.78;
|
|
15416
15509
|
const eyeRadiusY = eyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.92;
|
|
15417
|
-
drawProjectedOrganicEye(context, leftEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase +
|
|
15418
|
-
drawProjectedOrganicEye(context, rightEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.9 +
|
|
15510
|
+
drawProjectedOrganicEye(context, leftEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
15511
|
+
drawProjectedOrganicEye(context, rightEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.9 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
15419
15512
|
drawProjectedOrganicMouth(context, [
|
|
15420
15513
|
sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
|
|
15421
15514
|
sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
|
|
@@ -15444,14 +15537,28 @@ function drawBlobbyOctopusAtmosphere(context, size, palette, sceneCenterX, scene
|
|
|
15444
15537
|
/**
|
|
15445
15538
|
* Draws the soft floor shadow that anchors the single mesh in the frame.
|
|
15446
15539
|
*
|
|
15540
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
15541
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
15542
|
+
*
|
|
15447
15543
|
* @private helper of `octopus3d2AvatarVisual`
|
|
15448
15544
|
*/
|
|
15449
15545
|
function drawBlobbyOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
|
|
15546
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.045;
|
|
15547
|
+
const cy = size * 0.88 + Math.sin(timeMs / 940) * size * 0.008;
|
|
15548
|
+
const rx = size * (0.18 + (morphologyProfile.body.horizontalStretch - 1) * 0.04 + interaction.intensity * 0.018);
|
|
15549
|
+
const ry = size * 0.062;
|
|
15450
15550
|
context.save();
|
|
15451
|
-
context.
|
|
15452
|
-
context.
|
|
15551
|
+
context.translate(cx, cy);
|
|
15552
|
+
context.scale(1, ry / rx);
|
|
15553
|
+
const blurRadius = rx * 1.4;
|
|
15554
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
15555
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
15556
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
15557
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
15558
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
15559
|
+
context.fillStyle = shadowGradient;
|
|
15453
15560
|
context.beginPath();
|
|
15454
|
-
context.
|
|
15561
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
15455
15562
|
context.fill();
|
|
15456
15563
|
context.restore();
|
|
15457
15564
|
}
|
|
@@ -15607,6 +15714,40 @@ const LIGHT_DIRECTION = normalizeVector3({
|
|
|
15607
15714
|
* @private helper of `octopus3d3AvatarVisual`
|
|
15608
15715
|
*/
|
|
15609
15716
|
const OCTOPUS_TENTACLE_COUNT = 8;
|
|
15717
|
+
/**
|
|
15718
|
+
* Cache keyed by the `createRandom` factory reference, which is stable for the lifetime of one
|
|
15719
|
+
* mounted `<Avatar/>` component (created inside `resolveAvatarRenderDefinition` and held in a
|
|
15720
|
+
* React `useMemo`). Using a `WeakMap` ensures the entry is collected when the component unmounts.
|
|
15721
|
+
*
|
|
15722
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
15723
|
+
*/
|
|
15724
|
+
const stableStateCache = new WeakMap();
|
|
15725
|
+
/**
|
|
15726
|
+
* Returns the stable per-avatar state, computing it on first access and returning the cached
|
|
15727
|
+
* result on every subsequent call within the same `<Avatar/>` mount.
|
|
15728
|
+
*
|
|
15729
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
15730
|
+
*/
|
|
15731
|
+
function getOctopus3d3StableState(createRandom) {
|
|
15732
|
+
const cached = stableStateCache.get(createRandom);
|
|
15733
|
+
if (cached !== undefined) {
|
|
15734
|
+
return cached;
|
|
15735
|
+
}
|
|
15736
|
+
const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
|
|
15737
|
+
const animationRandom = createRandom('octopus3d3-animation-profile');
|
|
15738
|
+
const eyeRandom = createRandom('octopus3d3-eye-profile');
|
|
15739
|
+
const leftEyePhaseOffset = eyeRandom() * 0.7;
|
|
15740
|
+
const rightEyePhaseOffset = eyeRandom() * 0.7;
|
|
15741
|
+
const state = {
|
|
15742
|
+
morphologyProfile,
|
|
15743
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
15744
|
+
leftEyePhaseOffset,
|
|
15745
|
+
rightEyePhaseOffset,
|
|
15746
|
+
tentacleProfiles: createContinuousTentacleProfiles(createRandom, morphologyProfile),
|
|
15747
|
+
};
|
|
15748
|
+
stableStateCache.set(createRandom, state);
|
|
15749
|
+
return state;
|
|
15750
|
+
}
|
|
15610
15751
|
/**
|
|
15611
15752
|
* Octopus 3D 3 avatar visual.
|
|
15612
15753
|
*
|
|
@@ -15619,11 +15760,7 @@ const octopus3d3AvatarVisual = {
|
|
|
15619
15760
|
isAnimated: true,
|
|
15620
15761
|
supportsPointerTracking: true,
|
|
15621
15762
|
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
15622
|
-
const morphologyProfile =
|
|
15623
|
-
const animationRandom = createRandom('octopus3d3-animation-profile');
|
|
15624
|
-
const eyeRandom = createRandom('octopus3d3-eye-profile');
|
|
15625
|
-
const animationPhase = animationRandom() * Math.PI * 2;
|
|
15626
|
-
const tentacleProfiles = createContinuousTentacleProfiles(createRandom, morphologyProfile);
|
|
15763
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset, tentacleProfiles } = getOctopus3d3StableState(createRandom);
|
|
15627
15764
|
const sceneCenterX = size * 0.5;
|
|
15628
15765
|
const sceneCenterY = size * 0.535;
|
|
15629
15766
|
const bob = Math.sin(timeMs / 960 + animationPhase) * size * 0.012;
|
|
@@ -15700,8 +15837,8 @@ const octopus3d3AvatarVisual = {
|
|
|
15700
15837
|
size,
|
|
15701
15838
|
palette,
|
|
15702
15839
|
});
|
|
15703
|
-
drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase +
|
|
15704
|
-
drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.85 +
|
|
15840
|
+
drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
15841
|
+
drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.85 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
15705
15842
|
drawProjectedOrganicMouth(context, [
|
|
15706
15843
|
sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
|
|
15707
15844
|
sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
|
|
@@ -15752,14 +15889,30 @@ function drawContinuousOctopusAtmosphere(context, size, palette, sceneCenterX, s
|
|
|
15752
15889
|
/**
|
|
15753
15890
|
* Draws the soft lower shadow that anchors the octopus in the avatar frame.
|
|
15754
15891
|
*
|
|
15892
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
15893
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
15894
|
+
*
|
|
15755
15895
|
* @private helper of `octopus3d3AvatarVisual`
|
|
15756
15896
|
*/
|
|
15757
15897
|
function drawContinuousOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
|
|
15898
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.045;
|
|
15899
|
+
const cy = size * 0.9 + Math.sin(timeMs / 980) * size * 0.007;
|
|
15900
|
+
const rx = size * (0.19 + morphologyProfile.tentacles.rootSpreadScale * 0.022 + interaction.intensity * 0.02);
|
|
15901
|
+
const ry = size * 0.06;
|
|
15902
|
+
// Scale the context so that drawing a circle produces the correct ellipse aspect ratio,
|
|
15903
|
+
// then fill with a radial gradient that approximates the blurry edge without context.filter.
|
|
15758
15904
|
context.save();
|
|
15759
|
-
context.
|
|
15760
|
-
context.
|
|
15905
|
+
context.translate(cx, cy);
|
|
15906
|
+
context.scale(1, ry / rx);
|
|
15907
|
+
const blurRadius = rx * 1.4;
|
|
15908
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
15909
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
15910
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
15911
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
15912
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
15913
|
+
context.fillStyle = shadowGradient;
|
|
15761
15914
|
context.beginPath();
|
|
15762
|
-
context.
|
|
15915
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
15763
15916
|
context.fill();
|
|
15764
15917
|
context.restore();
|
|
15765
15918
|
}
|
|
@@ -29164,7 +29317,9 @@ function parseBookMessageHeader(line) {
|
|
|
29164
29317
|
* @private internal utility of `Book`
|
|
29165
29318
|
*/
|
|
29166
29319
|
function parseCommitmentHeader(line) {
|
|
29167
|
-
|
|
29320
|
+
// Require at least 2 characters in the first keyword word to avoid treating common
|
|
29321
|
+
// single-letter words (e.g. "V" in Czech, "I" or "A" in English) as commitment headers.
|
|
29322
|
+
const match = /^([A-Z][A-Z0-9]+(?: [A-Z0-9]+)*)(?:\s+(.*))?$/u.exec(line);
|
|
29168
29323
|
if (!match) {
|
|
29169
29324
|
return null;
|
|
29170
29325
|
}
|