@promptbook/cli 0.112.0-103 → 0.112.0-104

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 (31) hide show
  1. package/apps/agents-server/src/app/AddAgentButton.tsx +0 -5
  2. package/apps/agents-server/src/app/actions.ts +50 -0
  3. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +3 -4
  4. package/apps/agents-server/src/app/api/health/route.ts +18 -0
  5. package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +1 -4
  6. package/apps/agents-server/src/components/Header/Header.tsx +0 -11
  7. package/apps/agents-server/src/components/Header/useHeaderAgentMenus.tsx +0 -5
  8. package/apps/agents-server/src/components/NewAgentDialog/useNewAgentDialog.tsx +39 -16
  9. package/apps/agents-server/src/constants/defaultAgentAvatarVisual.ts +1 -1
  10. package/apps/agents-server/src/database/migrations/2026-06-0200-default-agent-avatar-visual-octopus3d3.sql +16 -0
  11. package/apps/agents-server/src/middleware.ts +2 -1
  12. package/apps/agents-server/src/tools/$provideCdnForServer.ts +43 -2
  13. package/apps/agents-server/src/utils/agentRouting/resolveAgentRouteTarget.ts +27 -4
  14. package/apps/agents-server/src/utils/defaultAgents/defaultAgents.ts +168 -0
  15. package/apps/agents-server/src/utils/defaultAgents/installDefaultAgents.ts +139 -0
  16. package/esm/index.es.js +518 -7
  17. package/esm/index.es.js.map +1 -1
  18. package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  19. package/esm/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
  20. package/package.json +1 -1
  21. package/src/avatars/types/AvatarVisualDefinition.ts +1 -0
  22. package/src/avatars/visuals/avatarVisualRegistry.ts +2 -0
  23. package/src/avatars/visuals/octopus3d3AvatarVisual.ts +903 -0
  24. package/src/other/templates/getTemplatesPipelineCollection.ts +784 -716
  25. package/src/utils/agents/resolveAgentAvatarImageUrl.ts +1 -1
  26. package/src/version.ts +1 -1
  27. package/src/versions.txt +1 -1
  28. package/umd/index.umd.js +518 -7
  29. package/umd/index.umd.js.map +1 -1
  30. package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  31. package/umd/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
package/esm/index.es.js CHANGED
@@ -58,7 +58,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
58
58
  * @generated
59
59
  * @see https://github.com/webgptorg/promptbook
60
60
  */
61
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-103';
61
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-104';
62
62
  /**
63
63
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
64
64
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -11041,7 +11041,7 @@ function fillTextureRect(texture, x, y, width, height, color) {
11041
11041
  *
11042
11042
  * @private helper of `minecraft2AvatarVisual`
11043
11043
  */
11044
- const LIGHT_DIRECTION$2 = normalizeVector3({
11044
+ const LIGHT_DIRECTION$3 = normalizeVector3({
11045
11045
  x: 0.4,
11046
11046
  y: -0.65,
11047
11047
  z: 0.92,
@@ -11253,7 +11253,7 @@ function resolveVisibleCuboidFaces(cuboid, size, sceneCenterX, sceneCenterY) {
11253
11253
  corners: projectedCorners,
11254
11254
  texture: faceDefinition.texture,
11255
11255
  averageDepth: transformedCorners.reduce((depthSum, corner) => depthSum + corner.z, 0) / transformedCorners.length,
11256
- lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$2), -1, 1),
11256
+ lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$3), -1, 1),
11257
11257
  outlineColor: cuboid.outlineColor,
11258
11258
  };
11259
11259
  });
@@ -12444,7 +12444,7 @@ function formatAlphaHex(opacity) {
12444
12444
  *
12445
12445
  * @private helper of `octopus3dAvatarVisual`
12446
12446
  */
12447
- const LIGHT_DIRECTION$1 = normalizeVector3({
12447
+ const LIGHT_DIRECTION$2 = normalizeVector3({
12448
12448
  x: 0.48,
12449
12449
  y: -0.62,
12450
12450
  z: 0.94,
@@ -12654,7 +12654,7 @@ function resolveVisibleEllipsoidPatches(options) {
12654
12654
  corners: projectedCorners,
12655
12655
  averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
12656
12656
  transformedCorners.length,
12657
- lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$1), -1, 1),
12657
+ lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$2), -1, 1),
12658
12658
  fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
12659
12659
  outlineColor,
12660
12660
  });
@@ -12843,7 +12843,7 @@ function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
12843
12843
  *
12844
12844
  * @private helper of `octopus3d2AvatarVisual`
12845
12845
  */
12846
- const LIGHT_DIRECTION = normalizeVector3({
12846
+ const LIGHT_DIRECTION$1 = normalizeVector3({
12847
12847
  x: 0.38,
12848
12848
  y: -0.6,
12849
12849
  z: 0.98,
@@ -12992,7 +12992,7 @@ function resolveVisibleBlobbyOctopusPatches(options) {
12992
12992
  corners: projectedCorners,
12993
12993
  averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
12994
12994
  transformedCorners.length,
12995
- lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
12995
+ lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$1), -1, 1),
12996
12996
  fillStyle: resolveBlobbySurfacePatchFillStyle(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), resolveLowerLobeWave(centerLongitude, morphologyProfile, animationPhase, timeMs)),
12997
12997
  outlineColor: verticalProgress < 0.58 ? `${palette.highlight}73` : `${palette.shadow}8a`,
12998
12998
  });
@@ -13092,6 +13092,516 @@ function drawBlobbySurfacePatch(context, surfacePatch) {
13092
13092
  context.restore();
13093
13093
  }
13094
13094
 
13095
+ /* eslint-disable no-magic-numbers */
13096
+ /**
13097
+ * Light direction used by the continuous octopus mesh shading.
13098
+ *
13099
+ * @private helper of `octopus3d3AvatarVisual`
13100
+ */
13101
+ const LIGHT_DIRECTION = normalizeVector3({
13102
+ x: 0.34,
13103
+ y: -0.62,
13104
+ z: 1,
13105
+ });
13106
+ /**
13107
+ * Real-octopus tentacle count used by the continuous lower mesh.
13108
+ *
13109
+ * @private helper of `octopus3d3AvatarVisual`
13110
+ */
13111
+ const OCTOPUS_TENTACLE_COUNT = 8;
13112
+ /**
13113
+ * Octopus 3D 3 avatar visual.
13114
+ *
13115
+ * @private built-in avatar visual
13116
+ */
13117
+ const octopus3d3AvatarVisual = {
13118
+ id: 'octopus3d3',
13119
+ title: 'Octopus 3D 3',
13120
+ description: 'Cute continuous 3D octopus with a blobby single mesh, waving tentacle lobes, rich shading, and cursor-aware eyes.',
13121
+ isAnimated: true,
13122
+ supportsPointerTracking: true,
13123
+ render({ context, size, palette, createRandom, timeMs, interaction }) {
13124
+ const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
13125
+ const animationRandom = createRandom('octopus3d3-animation-profile');
13126
+ const eyeRandom = createRandom('octopus3d3-eye-profile');
13127
+ const animationPhase = animationRandom() * Math.PI * 2;
13128
+ const tentacleProfiles = createContinuousTentacleProfiles(createRandom, morphologyProfile);
13129
+ const sceneCenterX = size * 0.5;
13130
+ const sceneCenterY = size * 0.535;
13131
+ const bob = Math.sin(timeMs / 960 + animationPhase) * size * 0.012;
13132
+ const meshCenter = {
13133
+ x: interaction.bodyOffsetX * size * 0.048 + size * morphologyProfile.body.centerXJitterRatio * 0.44,
13134
+ y: -size * 0.07 + interaction.bodyOffsetY * size * 0.026 + bob,
13135
+ z: interaction.intensity * size * 0.018,
13136
+ };
13137
+ const rotationY = -0.1 +
13138
+ Math.sin(timeMs / 2700 + animationPhase) * 0.035 +
13139
+ interaction.bodyOffsetX * 0.22 +
13140
+ interaction.gazeX * 0.88;
13141
+ const rotationX = -0.07 +
13142
+ Math.cos(timeMs / 3100 + animationPhase * 0.7) * 0.018 -
13143
+ interaction.bodyOffsetY * 0.08 -
13144
+ interaction.gazeY * 0.38;
13145
+ const surfaceOptions = {
13146
+ radiusX: size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch * 1.1,
13147
+ radiusY: size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.08,
13148
+ radiusZ: size *
13149
+ morphologyProfile.body.bodyRadiusRatio *
13150
+ (1.02 + (morphologyProfile.body.horizontalStretch - 1) * 0.18),
13151
+ morphologyProfile,
13152
+ timeMs,
13153
+ animationPhase,
13154
+ tentacleProfiles,
13155
+ };
13156
+ const surfacePatches = resolveVisibleContinuousOctopusPatches({
13157
+ ...surfaceOptions,
13158
+ center: meshCenter,
13159
+ rotationX,
13160
+ rotationY,
13161
+ sceneCenterX,
13162
+ sceneCenterY,
13163
+ size,
13164
+ palette,
13165
+ });
13166
+ const eyeLatitude = clampNumber$1(morphologyProfile.face.eyeCenterYOffsetRatio * 4.2 - 0.03, -0.22, 0.08);
13167
+ const eyeLongitude = clampNumber$1(morphologyProfile.face.eyeSpacingRatio * 3.1, 0.18, 0.32);
13168
+ const mouthLatitude = clampNumber$1(eyeLatitude + 0.2 + morphologyProfile.face.mouthYOffsetRatio, 0.08, 0.34);
13169
+ const mouthCenterLongitude = clampNumber$1(morphologyProfile.face.mouthCenterOffsetRatio * 5.6, -0.08, 0.08);
13170
+ const mouthHalfLongitude = clampNumber$1(eyeLongitude * 0.78, 0.15, 0.28);
13171
+ const mouthCurveLatitude = clampNumber$1(mouthLatitude + morphologyProfile.face.mouthCurveDepthRatio * 0.78, mouthLatitude + 0.03, 0.42);
13172
+ const eyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.76;
13173
+ const eyeRadiusY = eyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.9;
13174
+ drawAvatarFrame(context, size, palette);
13175
+ drawContinuousOctopusAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
13176
+ drawContinuousOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile);
13177
+ for (const surfacePatch of surfacePatches.sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
13178
+ drawContinuousSurfacePatch(context, surfacePatch);
13179
+ }
13180
+ drawProjectedSurfaceCurrents({
13181
+ context,
13182
+ surfaceOptions,
13183
+ center: meshCenter,
13184
+ rotationX,
13185
+ rotationY,
13186
+ sceneCenterX,
13187
+ sceneCenterY,
13188
+ size,
13189
+ palette,
13190
+ morphologyProfile,
13191
+ timeMs,
13192
+ animationPhase,
13193
+ });
13194
+ drawProjectedTentacleSuckers({
13195
+ context,
13196
+ surfaceOptions,
13197
+ center: meshCenter,
13198
+ rotationX,
13199
+ rotationY,
13200
+ sceneCenterX,
13201
+ sceneCenterY,
13202
+ size,
13203
+ palette,
13204
+ });
13205
+ drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
13206
+ 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);
13207
+ drawProjectedOrganicMouth(context, [
13208
+ sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
13209
+ sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
13210
+ sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude + mouthHalfLongitude),
13211
+ ], meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, palette, size);
13212
+ },
13213
+ };
13214
+ /**
13215
+ * Creates seeded tentacle-lobe profiles around the visible lower octopus body.
13216
+ *
13217
+ * @private helper of `octopus3d3AvatarVisual`
13218
+ */
13219
+ function createContinuousTentacleProfiles(createRandom, morphologyProfile) {
13220
+ return Array.from({ length: OCTOPUS_TENTACLE_COUNT }, (_, tentacleIndex) => {
13221
+ const tentacleRandom = createRandom(`octopus3d3-tentacle-${tentacleIndex}`);
13222
+ const progress = tentacleIndex / (OCTOPUS_TENTACLE_COUNT - 1);
13223
+ return {
13224
+ centerLongitude: -Math.PI * 0.86 +
13225
+ progress * Math.PI * 1.72 +
13226
+ (tentacleRandom() - 0.5) * (0.08 + morphologyProfile.tentacles.rootSpreadScale * 0.03),
13227
+ widthScale: 0.86 + tentacleRandom() * 0.34 + (morphologyProfile.tentacles.baseWidthScale - 1) * 0.16,
13228
+ lengthScale: 0.86 + tentacleRandom() * 0.36 + (morphologyProfile.tentacles.flowLengthScale - 1) * 0.22,
13229
+ swayScale: 0.82 + tentacleRandom() * 0.38 + (morphologyProfile.tentacles.swayScale - 1) * 0.2,
13230
+ depthScale: 0.86 + tentacleRandom() * 0.32 + (morphologyProfile.tentacles.tipReachScale - 1) * 0.2,
13231
+ phase: tentacleRandom() * Math.PI * 2,
13232
+ suckerSide: tentacleRandom() > 0.5 ? 1 : -1,
13233
+ };
13234
+ });
13235
+ }
13236
+ /**
13237
+ * Draws the soft underwater atmosphere behind the continuous octopus mesh.
13238
+ *
13239
+ * @private helper of `octopus3d3AvatarVisual`
13240
+ */
13241
+ function drawContinuousOctopusAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
13242
+ const glowGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.11, sceneCenterY - size * 0.17 + interaction.gazeY * size * 0.05, size * 0.04, sceneCenterX, sceneCenterY, size * (0.66 + interaction.intensity * 0.02));
13243
+ glowGradient.addColorStop(0, `${palette.highlight}66`);
13244
+ glowGradient.addColorStop(0.34, `${palette.accent}2e`);
13245
+ glowGradient.addColorStop(1, `${palette.highlight}00`);
13246
+ context.fillStyle = glowGradient;
13247
+ context.fillRect(0, 0, size, size);
13248
+ const lowerGradient = context.createRadialGradient(sceneCenterX + Math.sin(timeMs / 1550) * size * 0.05, sceneCenterY + size * 0.29, size * 0.06, sceneCenterX, sceneCenterY + size * 0.3, size * 0.54);
13249
+ lowerGradient.addColorStop(0, `${palette.secondary}25`);
13250
+ lowerGradient.addColorStop(1, `${palette.secondary}00`);
13251
+ context.fillStyle = lowerGradient;
13252
+ context.fillRect(0, 0, size, size);
13253
+ }
13254
+ /**
13255
+ * Draws the soft lower shadow that anchors the octopus in the avatar frame.
13256
+ *
13257
+ * @private helper of `octopus3d3AvatarVisual`
13258
+ */
13259
+ function drawContinuousOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
13260
+ context.save();
13261
+ context.fillStyle = `${palette.shadow}66`;
13262
+ context.filter = `blur(${size * 0.025}px)`;
13263
+ context.beginPath();
13264
+ 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);
13265
+ context.fill();
13266
+ context.restore();
13267
+ }
13268
+ /**
13269
+ * Resolves visible projected patches for the continuous octopus mesh.
13270
+ *
13271
+ * @private helper of `octopus3d3AvatarVisual`
13272
+ */
13273
+ function resolveVisibleContinuousOctopusPatches(options) {
13274
+ const { center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette } = options;
13275
+ const latitudePatchCount = 16;
13276
+ const longitudePatchCount = 40;
13277
+ const surfacePatches = [];
13278
+ for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
13279
+ const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
13280
+ const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
13281
+ const centerLatitude = (startLatitude + endLatitude) / 2;
13282
+ const verticalProgress = (Math.sin(centerLatitude) + 1) / 2;
13283
+ for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
13284
+ const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
13285
+ const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
13286
+ const centerLongitude = (startLongitude + endLongitude) / 2;
13287
+ const localCorners = [
13288
+ sampleContinuousOctopusSurfacePoint(options, startLatitude, startLongitude),
13289
+ sampleContinuousOctopusSurfacePoint(options, startLatitude, endLongitude),
13290
+ sampleContinuousOctopusSurfacePoint(options, endLatitude, endLongitude),
13291
+ sampleContinuousOctopusSurfacePoint(options, endLatitude, startLongitude),
13292
+ ];
13293
+ const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
13294
+ const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
13295
+ if (surfaceNormal.z <= 0.008) {
13296
+ continue;
13297
+ }
13298
+ const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
13299
+ const tentacleInfluence = resolveContinuousTentacleInfluence(options, centerLongitude);
13300
+ const lowerLobeWave = resolveContinuousLobeWave(options, centerLongitude);
13301
+ surfacePatches.push({
13302
+ corners: projectedCorners,
13303
+ averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
13304
+ transformedCorners.length,
13305
+ lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
13306
+ fillStyle: resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), tentacleInfluence.core, lowerLobeWave),
13307
+ outlineColor: verticalProgress < 0.54 ? `${palette.highlight}69` : `${palette.shadow}78`,
13308
+ });
13309
+ }
13310
+ }
13311
+ return surfacePatches;
13312
+ }
13313
+ /**
13314
+ * Samples one point on the continuous Octopus 3D 3 surface.
13315
+ *
13316
+ * The lower hemisphere is pulled into eight seeded waving lobes, so the portrait reads as
13317
+ * tentacled while still being rendered as one connected blobby mesh.
13318
+ *
13319
+ * @private helper of `octopus3d3AvatarVisual`
13320
+ */
13321
+ function sampleContinuousOctopusSurfacePoint(options, latitude, longitude) {
13322
+ const { radiusX, radiusY, radiusZ, morphologyProfile, timeMs, animationPhase } = options;
13323
+ const cosineLatitude = Math.max(0, Math.cos(latitude));
13324
+ const verticalProgress = (Math.sin(latitude) + 1) / 2;
13325
+ const upperBlend = Math.pow(1 - verticalProgress, 1.28);
13326
+ const lowerBlend = smoothStep(0.38, 1, verticalProgress);
13327
+ const tipBlend = smoothStep(0.68, 1, verticalProgress);
13328
+ const tentacleInfluence = resolveContinuousTentacleInfluence(options, longitude);
13329
+ const centerPull = resolveSignedAngularDistance(longitude, tentacleInfluence.centerLongitude);
13330
+ const effectiveLongitude = longitude + centerPull * lowerBlend * tentacleInfluence.core * (0.24 + tipBlend * 0.2);
13331
+ const lowerLobeWave = resolveContinuousLobeWave(options, longitude);
13332
+ const mantleRipple = Math.sin(longitude * morphologyProfile.body.lobeCount +
13333
+ animationPhase * 0.6 +
13334
+ timeMs / (1750 + morphologyProfile.body.lobeCount * 30)) *
13335
+ (0.018 + morphologyProfile.body.wobbleAmplitudeRatio * 0.8) *
13336
+ (0.3 + lowerBlend * 0.7);
13337
+ const tentacleWave = Math.sin(timeMs / 760 + tentacleInfluence.phase + verticalProgress * 2.4) *
13338
+ lowerBlend *
13339
+ tentacleInfluence.core *
13340
+ tentacleInfluence.swayScale;
13341
+ const horizontalScale = 1.04 +
13342
+ mantleRipple +
13343
+ lowerBlend * (0.16 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.1) +
13344
+ lowerBlend * tentacleInfluence.core * (0.2 + lowerLobeWave * 0.12) -
13345
+ upperBlend * 0.08;
13346
+ const depthScale = 1.06 +
13347
+ upperBlend * 0.16 +
13348
+ Math.max(0, Math.cos(effectiveLongitude)) * 0.1 +
13349
+ lowerBlend * tentacleInfluence.core * (0.1 + tentacleInfluence.depthScale * 0.06) -
13350
+ Math.max(0, -Math.cos(effectiveLongitude)) * 0.05;
13351
+ const tentacleTubeRadius = lowerBlend *
13352
+ tentacleInfluence.core *
13353
+ (0.11 + tipBlend * 0.06 + tentacleInfluence.widthScale * 0.025) *
13354
+ radiusX;
13355
+ const planarRadiusX = cosineLatitude * radiusX * horizontalScale + tentacleTubeRadius;
13356
+ const planarRadiusZ = cosineLatitude * radiusZ * depthScale + tentacleTubeRadius * 0.72;
13357
+ const lowerDrop = lowerBlend *
13358
+ radiusY *
13359
+ (0.18 +
13360
+ tentacleInfluence.core *
13361
+ (0.38 +
13362
+ tentacleInfluence.lengthScale * 0.22 +
13363
+ (morphologyProfile.tentacles.flowLengthScale - 1) * 0.08));
13364
+ return {
13365
+ x: Math.sin(effectiveLongitude) * planarRadiusX +
13366
+ tentacleWave * radiusX * (0.052 + tipBlend * 0.05),
13367
+ y: Math.sin(latitude) * radiusY * (1 + upperBlend * 0.12) -
13368
+ upperBlend * radiusY * 0.1 +
13369
+ lowerDrop +
13370
+ Math.sin(timeMs / 1420 + animationPhase + latitude * 1.6) * lowerBlend * radiusY * 0.018 +
13371
+ Math.cos(timeMs / 880 + tentacleInfluence.phase) *
13372
+ lowerBlend *
13373
+ tipBlend *
13374
+ tentacleInfluence.core *
13375
+ radiusY *
13376
+ 0.034,
13377
+ z: Math.cos(effectiveLongitude) * planarRadiusZ +
13378
+ Math.cos(timeMs / 980 + tentacleInfluence.phase + verticalProgress) *
13379
+ lowerBlend *
13380
+ tentacleInfluence.core *
13381
+ radiusZ *
13382
+ 0.04,
13383
+ };
13384
+ }
13385
+ /**
13386
+ * Blends nearby seeded tentacle profiles at one mesh longitude.
13387
+ *
13388
+ * @private helper of `octopus3d3AvatarVisual`
13389
+ */
13390
+ function resolveContinuousTentacleInfluence(options, longitude) {
13391
+ let totalWeight = 0;
13392
+ let weightedSin = 0;
13393
+ let weightedCos = 0;
13394
+ let weightedWidthScale = 0;
13395
+ let weightedLengthScale = 0;
13396
+ let weightedSwayScale = 0;
13397
+ let weightedDepthScale = 0;
13398
+ let weightedPhase = 0;
13399
+ for (const tentacleProfile of options.tentacleProfiles) {
13400
+ const distance = Math.abs(resolveSignedAngularDistance(longitude, tentacleProfile.centerLongitude));
13401
+ const width = 0.2 * tentacleProfile.widthScale;
13402
+ const weight = Math.exp(-(distance * distance) / (width * width));
13403
+ totalWeight += weight;
13404
+ weightedSin += Math.sin(tentacleProfile.centerLongitude) * weight;
13405
+ weightedCos += Math.cos(tentacleProfile.centerLongitude) * weight;
13406
+ weightedWidthScale += tentacleProfile.widthScale * weight;
13407
+ weightedLengthScale += tentacleProfile.lengthScale * weight;
13408
+ weightedSwayScale += tentacleProfile.swayScale * weight;
13409
+ weightedDepthScale += tentacleProfile.depthScale * weight;
13410
+ weightedPhase += tentacleProfile.phase * weight;
13411
+ }
13412
+ if (totalWeight < 0.0001) {
13413
+ return {
13414
+ core: 0,
13415
+ centerLongitude: longitude,
13416
+ widthScale: 1,
13417
+ lengthScale: 1,
13418
+ swayScale: 1,
13419
+ depthScale: 1,
13420
+ phase: 0,
13421
+ };
13422
+ }
13423
+ return {
13424
+ core: clampNumber$1(totalWeight, 0, 1),
13425
+ centerLongitude: Math.atan2(weightedSin / totalWeight, weightedCos / totalWeight),
13426
+ widthScale: weightedWidthScale / totalWeight,
13427
+ lengthScale: weightedLengthScale / totalWeight,
13428
+ swayScale: weightedSwayScale / totalWeight,
13429
+ depthScale: weightedDepthScale / totalWeight,
13430
+ phase: weightedPhase / totalWeight,
13431
+ };
13432
+ }
13433
+ /**
13434
+ * Resolves the soft lower wave that makes the continuous mesh read as a set of tentacles.
13435
+ *
13436
+ * @private helper of `octopus3d3AvatarVisual`
13437
+ */
13438
+ function resolveContinuousLobeWave(options, longitude) {
13439
+ const { morphologyProfile, animationPhase, timeMs } = options;
13440
+ return (Math.cos(longitude * OCTOPUS_TENTACLE_COUNT + animationPhase + timeMs / (980 + morphologyProfile.body.lobeCount * 18)) +
13441
+ 1) / 2;
13442
+ }
13443
+ /**
13444
+ * Resolves one base fill tone for a patch on the continuous octopus mesh.
13445
+ *
13446
+ * @private helper of `octopus3d3AvatarVisual`
13447
+ */
13448
+ function resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, forwardness, tentacleCore, lowerLobeWave) {
13449
+ const tonalProgress = clampNumber$1(verticalProgress + lowerLobeWave * 0.1 + tentacleCore * 0.08 - forwardness * 0.08, 0, 1);
13450
+ if (tonalProgress < 0.14) {
13451
+ return palette.highlight;
13452
+ }
13453
+ if (tonalProgress < 0.32) {
13454
+ return palette.secondary;
13455
+ }
13456
+ if (tonalProgress < 0.72) {
13457
+ return forwardness > 0.55 ? palette.secondary : palette.primary;
13458
+ }
13459
+ return tentacleCore > 0.44 ? `${palette.primary}f4` : `${palette.shadow}ee`;
13460
+ }
13461
+ /**
13462
+ * Draws one projected mesh patch with soft shading and a subtle edge.
13463
+ *
13464
+ * @private helper of `octopus3d3AvatarVisual`
13465
+ */
13466
+ function drawContinuousSurfacePatch(context, surfacePatch) {
13467
+ drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
13468
+ if (surfacePatch.lightIntensity > 0) {
13469
+ drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.18 * surfacePatch.lightIntensity})`);
13470
+ }
13471
+ else if (surfacePatch.lightIntensity < 0) {
13472
+ drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.25 * Math.abs(surfacePatch.lightIntensity)})`);
13473
+ }
13474
+ context.save();
13475
+ context.beginPath();
13476
+ context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
13477
+ for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
13478
+ context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
13479
+ }
13480
+ context.closePath();
13481
+ context.strokeStyle = surfacePatch.outlineColor;
13482
+ context.lineWidth = Math.max(0.7, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0032);
13483
+ context.lineJoin = 'round';
13484
+ context.stroke();
13485
+ context.restore();
13486
+ }
13487
+ /**
13488
+ * Draws projected mantle-current lines on the front of the mesh.
13489
+ *
13490
+ * @private helper of `octopus3d3AvatarVisual`
13491
+ */
13492
+ function drawProjectedSurfaceCurrents(options) {
13493
+ const { context, surfaceOptions, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, morphologyProfile, timeMs, animationPhase, } = options;
13494
+ const currentCount = Math.min(6, morphologyProfile.details.mantleCurrentCount);
13495
+ const centerIndex = (currentCount - 1) / 2;
13496
+ context.save();
13497
+ context.lineCap = 'round';
13498
+ context.lineJoin = 'round';
13499
+ for (let currentIndex = 0; currentIndex < currentCount; currentIndex++) {
13500
+ const baseLongitude = (currentIndex - centerIndex) * 0.15;
13501
+ const projectedPoints = [];
13502
+ for (let sampleIndex = 0; sampleIndex < 8; sampleIndex++) {
13503
+ const progress = sampleIndex / 7;
13504
+ const latitude = -0.46 + progress * 0.74;
13505
+ const longitude = baseLongitude +
13506
+ Math.sin(timeMs / 1160 + animationPhase + currentIndex * 0.7 + progress * 2) * 0.035;
13507
+ const scenePoint = transformScenePoint(sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude, longitude), center, rotationX, rotationY);
13508
+ if (scenePoint.z > center.z - size * 0.016) {
13509
+ projectedPoints.push(projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
13510
+ }
13511
+ }
13512
+ if (projectedPoints.length < 3) {
13513
+ continue;
13514
+ }
13515
+ context.beginPath();
13516
+ context.moveTo(projectedPoints[0].x, projectedPoints[0].y);
13517
+ for (const projectedPoint of projectedPoints.slice(1)) {
13518
+ context.lineTo(projectedPoint.x, projectedPoint.y);
13519
+ }
13520
+ context.strokeStyle = currentIndex % 2 === 0 ? `${palette.highlight}3d` : `${palette.accent}33`;
13521
+ context.lineWidth = size * (0.0055 + currentIndex * 0.00045);
13522
+ context.stroke();
13523
+ }
13524
+ context.restore();
13525
+ }
13526
+ /**
13527
+ * Draws small projected sucker highlights on the waving lower mesh lobes.
13528
+ *
13529
+ * @private helper of `octopus3d3AvatarVisual`
13530
+ */
13531
+ function drawProjectedTentacleSuckers(options) {
13532
+ const { surfaceOptions, size } = options;
13533
+ const { timeMs } = surfaceOptions;
13534
+ for (const tentacleProfile of surfaceOptions.tentacleProfiles) {
13535
+ if (Math.cos(tentacleProfile.centerLongitude) < -0.12) {
13536
+ continue;
13537
+ }
13538
+ for (let suckerIndex = 0; suckerIndex < 3; suckerIndex++) {
13539
+ const latitude = 0.52 + suckerIndex * 0.14;
13540
+ const sideOffset = tentacleProfile.suckerSide * (0.035 + suckerIndex * 0.012) * tentacleProfile.widthScale;
13541
+ const waveOffset = Math.sin(timeMs / 900 + tentacleProfile.phase + suckerIndex * 0.8) * 0.018;
13542
+ drawProjectedSurfaceSpot({
13543
+ ...options,
13544
+ latitude,
13545
+ longitude: tentacleProfile.centerLongitude + sideOffset + waveOffset,
13546
+ radiusScale: size * (0.0065 - suckerIndex * 0.0007),
13547
+ });
13548
+ }
13549
+ }
13550
+ }
13551
+ /**
13552
+ * Draws one tiny projected surface spot by sampling local mesh tangents.
13553
+ *
13554
+ * @private helper of `octopus3d3AvatarVisual`
13555
+ */
13556
+ function drawProjectedSurfaceSpot(options) {
13557
+ const { context, surfaceOptions, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, latitude, longitude, radiusScale, } = options;
13558
+ const localCenter = sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude, longitude);
13559
+ const localHorizontal = sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude, longitude + 0.018);
13560
+ const localVertical = sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude + 0.018, longitude);
13561
+ const sceneCenterPoint = transformScenePoint(localCenter, center, rotationX, rotationY);
13562
+ if (sceneCenterPoint.z <= center.z - size * 0.012) {
13563
+ return;
13564
+ }
13565
+ const projectedCenterPoint = projectScenePoint(sceneCenterPoint, size, sceneCenterX, sceneCenterY);
13566
+ const projectedHorizontalPoint = projectScenePoint(transformScenePoint(localHorizontal, center, rotationX, rotationY), size, sceneCenterX, sceneCenterY);
13567
+ const projectedVerticalPoint = projectScenePoint(transformScenePoint(localVertical, center, rotationX, rotationY), size, sceneCenterX, sceneCenterY);
13568
+ const horizontalRadius = clampNumber$1(Math.hypot(projectedHorizontalPoint.x - projectedCenterPoint.x, projectedHorizontalPoint.y - projectedCenterPoint.y) *
13569
+ radiusScale *
13570
+ 0.74, size * 0.003, size * 0.018);
13571
+ const verticalRadius = clampNumber$1(Math.hypot(projectedVerticalPoint.x - projectedCenterPoint.x, projectedVerticalPoint.y - projectedCenterPoint.y) *
13572
+ radiusScale *
13573
+ 0.52, size * 0.0024, size * 0.014);
13574
+ const rotation = Math.atan2(projectedHorizontalPoint.y - projectedCenterPoint.y, projectedHorizontalPoint.x - projectedCenterPoint.x);
13575
+ context.save();
13576
+ context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
13577
+ context.rotate(rotation);
13578
+ context.beginPath();
13579
+ context.ellipse(0, 0, horizontalRadius, verticalRadius, 0, 0, Math.PI * 2);
13580
+ context.fillStyle = `${palette.highlight}73`;
13581
+ context.fill();
13582
+ context.strokeStyle = `${palette.highlight}99`;
13583
+ context.lineWidth = Math.max(0.7, size * 0.0028);
13584
+ context.stroke();
13585
+ context.restore();
13586
+ }
13587
+ /**
13588
+ * Resolves a signed angular distance from the source longitude to the target longitude.
13589
+ *
13590
+ * @private helper of `octopus3d3AvatarVisual`
13591
+ */
13592
+ function resolveSignedAngularDistance(sourceLongitude, targetLongitude) {
13593
+ return Math.atan2(Math.sin(targetLongitude - sourceLongitude), Math.cos(targetLongitude - sourceLongitude));
13594
+ }
13595
+ /**
13596
+ * Smoothly maps a value between two bounds into `[0, 1]`.
13597
+ *
13598
+ * @private helper of `octopus3d3AvatarVisual`
13599
+ */
13600
+ function smoothStep(edgeStart, edgeEnd, value) {
13601
+ const progress = clampNumber$1((value - edgeStart) / (edgeEnd - edgeStart), 0, 1);
13602
+ return progress * progress * (3 - 2 * progress);
13603
+ }
13604
+
13095
13605
  /* eslint-disable no-magic-numbers */
13096
13606
  /**
13097
13607
  * Octopus avatar visual.
@@ -13862,6 +14372,7 @@ const AVATAR_VISUALS = [
13862
14372
  octopus3AvatarVisual,
13863
14373
  octopus3dAvatarVisual,
13864
14374
  octopus3d2AvatarVisual,
14375
+ octopus3d3AvatarVisual,
13865
14376
  asciiOctopusAvatarVisual,
13866
14377
  minecraftAvatarVisual,
13867
14378
  minecraft2AvatarVisual,