@promptbook/node 0.112.0-69 → 0.112.0-70

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 (27) hide show
  1. package/esm/index.es.js +753 -221
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  4. package/esm/src/avatars/visuals/avatar3dProjectionShared.d.ts +141 -0
  5. package/esm/src/avatars/visuals/octopus3dAvatarVisual.d.ts +7 -0
  6. package/esm/src/cli/cli-commands/agent/agentProjectPaths.d.ts +2 -2
  7. package/esm/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +22 -0
  8. package/esm/src/cli/cli-commands/agent/runMultiple.d.ts +10 -0
  9. package/esm/src/cli/cli-commands/agent.d.ts +3 -2
  10. package/esm/src/cli/other/install.test.d.ts +1 -0
  11. package/esm/src/commitments/USE_TIMEOUT/USE_TIMEOUT.d.ts +1 -1
  12. package/esm/src/commitments/WALLET/WALLET.d.ts +1 -1
  13. package/esm/src/version.d.ts +1 -1
  14. package/package.json +2 -2
  15. package/umd/index.umd.js +753 -221
  16. package/umd/index.umd.js.map +1 -1
  17. package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  18. package/umd/src/avatars/visuals/avatar3dProjectionShared.d.ts +141 -0
  19. package/umd/src/avatars/visuals/octopus3dAvatarVisual.d.ts +7 -0
  20. package/umd/src/cli/cli-commands/agent/agentProjectPaths.d.ts +2 -2
  21. package/umd/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +22 -0
  22. package/umd/src/cli/cli-commands/agent/runMultiple.d.ts +10 -0
  23. package/umd/src/cli/cli-commands/agent.d.ts +3 -2
  24. package/umd/src/cli/other/install.test.d.ts +1 -0
  25. package/umd/src/commitments/USE_TIMEOUT/USE_TIMEOUT.d.ts +1 -1
  26. package/umd/src/commitments/WALLET/WALLET.d.ts +1 -1
  27. package/umd/src/version.d.ts +1 -1
package/umd/index.umd.js CHANGED
@@ -48,7 +48,7 @@
48
48
  * @generated
49
49
  * @see https://github.com/webgptorg/promptbook
50
50
  */
51
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-69';
51
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-70';
52
52
  /**
53
53
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
54
54
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -2402,11 +2402,11 @@
2402
2402
  */
2403
2403
  function pipelineJsonToString(pipelineJson) {
2404
2404
  const { title, pipelineUrl, bookVersion, description, parameters, tasks } = pipelineJson;
2405
- let pipelineString = `# ${title}`;
2406
- if (description) {
2407
- pipelineString += '\n\n';
2408
- pipelineString += description;
2409
- }
2405
+ let pipelineString = _spaceTrim.spaceTrim((block) => `
2406
+ # ${title}
2407
+
2408
+ ${block(description || '')}
2409
+ `);
2410
2410
  const commands = [];
2411
2411
  if (pipelineUrl) {
2412
2412
  commands.push(`PIPELINE URL ${pipelineUrl}`);
@@ -2422,20 +2422,17 @@
2422
2422
  for (const parameter of parameters.filter(({ isOutput }) => isOutput)) {
2423
2423
  commands.push(`OUTPUT PARAMETER ${taskParameterJsonToString(parameter)}`);
2424
2424
  }
2425
- pipelineString += '\n\n';
2426
- pipelineString += commands.map((command) => `- ${command}`).join('\n');
2425
+ pipelineString = _spaceTrim.spaceTrim((block) => `
2426
+ ${block(pipelineString)}
2427
+
2428
+ ${block(commands.map((command) => `- ${command}`).join('\n'))}
2429
+ `);
2427
2430
  for (const task of tasks) {
2428
2431
  const {
2429
2432
  /* Note: Not using:> name, */
2430
2433
  title, description,
2431
2434
  /* Note: dependentParameterNames, */
2432
2435
  jokerParameterNames: jokers, taskType, content, postprocessingFunctionNames: postprocessing, expectations, format, resultingParameterName, } = task;
2433
- pipelineString += '\n\n';
2434
- pipelineString += `## ${title}`;
2435
- if (description) {
2436
- pipelineString += '\n\n';
2437
- pipelineString += description;
2438
- }
2439
2436
  const commands = [];
2440
2437
  let contentLanguage = 'text';
2441
2438
  if (taskType === 'PROMPT_TASK') {
@@ -2498,18 +2495,23 @@
2498
2495
  commands.push(`FORMAT JSON`);
2499
2496
  }
2500
2497
  } /* not else */
2501
- pipelineString += '\n\n';
2502
- pipelineString += commands.map((command) => `- ${command}`).join('\n');
2503
- pipelineString += '\n\n';
2504
- pipelineString += '```' + contentLanguage;
2505
- pipelineString += '\n';
2506
- pipelineString += _spaceTrim.spaceTrim(content);
2507
- // <- TODO: [main] !!3 Escape
2508
- // <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
2509
- pipelineString += '\n';
2510
- pipelineString += '```';
2511
- pipelineString += '\n\n';
2512
- pipelineString += `\`-> {${resultingParameterName}}\``; // <- TODO: [main] !!3 If the parameter here has description, add it and use taskParameterJsonToString
2498
+ pipelineString = _spaceTrim.spaceTrim((block) => `
2499
+ ${block(pipelineString)}
2500
+
2501
+ ## ${title}
2502
+
2503
+ ${block(description || '')}
2504
+
2505
+ ${block(commands.map((command) => `- ${command}`).join('\n'))}
2506
+
2507
+ \`\`\`${contentLanguage}
2508
+ ${block(_spaceTrim.spaceTrim(content))}
2509
+ \`\`\`
2510
+
2511
+ \`-> {${resultingParameterName}}\`
2512
+ `); // <- TODO: [main] !!3 If the parameter here has description, add it and use taskParameterJsonToString
2513
+ // <- TODO: [main] !!3 Escape
2514
+ // <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
2513
2515
  }
2514
2516
  return validatePipelineString(pipelineString);
2515
2517
  }
@@ -16470,6 +16472,184 @@
16470
16472
  context.restore();
16471
16473
  }
16472
16474
 
16475
+ /* eslint-disable no-magic-numbers */
16476
+ /**
16477
+ * Default camera distance ratio shared by the proper-3D avatar visuals.
16478
+ *
16479
+ * @private helper of the 3D avatar visuals
16480
+ */
16481
+ const DEFAULT_3D_CAMERA_DISTANCE_RATIO = 1.4;
16482
+ /**
16483
+ * Clamps one number into the provided range.
16484
+ *
16485
+ * @param value Input value.
16486
+ * @param minimumValue Inclusive lower bound.
16487
+ * @param maximumValue Inclusive upper bound.
16488
+ * @returns Clamped value.
16489
+ *
16490
+ * @private helper of the 3D avatar visuals
16491
+ */
16492
+ function clampNumber$1(value, minimumValue, maximumValue) {
16493
+ return Math.min(maximumValue, Math.max(minimumValue, value));
16494
+ }
16495
+ /**
16496
+ * Rotates one point around the local Y axis.
16497
+ *
16498
+ * @param point Source point.
16499
+ * @param angle Rotation angle in radians.
16500
+ * @returns Rotated point.
16501
+ *
16502
+ * @private helper of the 3D avatar visuals
16503
+ */
16504
+ function rotatePointAroundY(point, angle) {
16505
+ const cosine = Math.cos(angle);
16506
+ const sine = Math.sin(angle);
16507
+ return {
16508
+ x: point.x * cosine + point.z * sine,
16509
+ y: point.y,
16510
+ z: -point.x * sine + point.z * cosine,
16511
+ };
16512
+ }
16513
+ /**
16514
+ * Rotates one point around the local X axis.
16515
+ *
16516
+ * @param point Source point.
16517
+ * @param angle Rotation angle in radians.
16518
+ * @returns Rotated point.
16519
+ *
16520
+ * @private helper of the 3D avatar visuals
16521
+ */
16522
+ function rotatePointAroundX(point, angle) {
16523
+ const cosine = Math.cos(angle);
16524
+ const sine = Math.sin(angle);
16525
+ return {
16526
+ x: point.x,
16527
+ y: point.y * cosine - point.z * sine,
16528
+ z: point.y * sine + point.z * cosine,
16529
+ };
16530
+ }
16531
+ /**
16532
+ * Applies the local rotations and translation to one scene point.
16533
+ *
16534
+ * @param localPoint Point in local object space.
16535
+ * @param center Object center in scene space.
16536
+ * @param rotationX Object pitch in radians.
16537
+ * @param rotationY Object yaw in radians.
16538
+ * @returns Transformed scene-space point.
16539
+ *
16540
+ * @private helper of the 3D avatar visuals
16541
+ */
16542
+ function transformScenePoint(localPoint, center, rotationX, rotationY) {
16543
+ const yawedPoint = rotatePointAroundY(localPoint, rotationY);
16544
+ const pitchedPoint = rotatePointAroundX(yawedPoint, rotationX);
16545
+ return {
16546
+ x: center.x + pitchedPoint.x,
16547
+ y: center.y + pitchedPoint.y,
16548
+ z: center.z + pitchedPoint.z,
16549
+ };
16550
+ }
16551
+ /**
16552
+ * Projects one scene point into canvas coordinates.
16553
+ *
16554
+ * @param point Scene-space point.
16555
+ * @param size Canvas size in CSS pixels.
16556
+ * @param sceneCenterX Horizontal scene center.
16557
+ * @param sceneCenterY Vertical scene center.
16558
+ * @param cameraDistanceRatio Optional camera distance ratio.
16559
+ * @returns Projected point.
16560
+ *
16561
+ * @private helper of the 3D avatar visuals
16562
+ */
16563
+ function projectScenePoint(point, size, sceneCenterX, sceneCenterY, cameraDistanceRatio = DEFAULT_3D_CAMERA_DISTANCE_RATIO) {
16564
+ const cameraDistance = size * cameraDistanceRatio;
16565
+ const perspectiveScale = cameraDistance / Math.max(cameraDistance - point.z, cameraDistance * 0.35);
16566
+ return {
16567
+ x: sceneCenterX + point.x * perspectiveScale,
16568
+ y: sceneCenterY + point.y * perspectiveScale,
16569
+ z: point.z,
16570
+ };
16571
+ }
16572
+ /**
16573
+ * Subtracts one 3D point from another.
16574
+ *
16575
+ * @param leftPoint Left point.
16576
+ * @param rightPoint Right point.
16577
+ * @returns Difference vector.
16578
+ *
16579
+ * @private helper of the 3D avatar visuals
16580
+ */
16581
+ function subtractPoint3D(leftPoint, rightPoint) {
16582
+ return {
16583
+ x: leftPoint.x - rightPoint.x,
16584
+ y: leftPoint.y - rightPoint.y,
16585
+ z: leftPoint.z - rightPoint.z,
16586
+ };
16587
+ }
16588
+ /**
16589
+ * Computes the 3D cross product of two vectors.
16590
+ *
16591
+ * @param leftVector Left vector.
16592
+ * @param rightVector Right vector.
16593
+ * @returns Cross product.
16594
+ *
16595
+ * @private helper of the 3D avatar visuals
16596
+ */
16597
+ function crossProduct3D(leftVector, rightVector) {
16598
+ return {
16599
+ x: leftVector.y * rightVector.z - leftVector.z * rightVector.y,
16600
+ y: leftVector.z * rightVector.x - leftVector.x * rightVector.z,
16601
+ z: leftVector.x * rightVector.y - leftVector.y * rightVector.x,
16602
+ };
16603
+ }
16604
+ /**
16605
+ * Computes the 3D dot product of two vectors.
16606
+ *
16607
+ * @param leftVector Left vector.
16608
+ * @param rightVector Right vector.
16609
+ * @returns Dot product.
16610
+ *
16611
+ * @private helper of the 3D avatar visuals
16612
+ */
16613
+ function dotProduct3D(leftVector, rightVector) {
16614
+ return leftVector.x * rightVector.x + leftVector.y * rightVector.y + leftVector.z * rightVector.z;
16615
+ }
16616
+ /**
16617
+ * Normalizes one 3D vector while keeping zero vectors stable.
16618
+ *
16619
+ * @param vector Source vector.
16620
+ * @returns Normalized vector.
16621
+ *
16622
+ * @private helper of the 3D avatar visuals
16623
+ */
16624
+ function normalizeVector3(vector) {
16625
+ const length = Math.hypot(vector.x, vector.y, vector.z);
16626
+ if (length === 0) {
16627
+ return vector;
16628
+ }
16629
+ return {
16630
+ x: vector.x / length,
16631
+ y: vector.y / length,
16632
+ z: vector.z / length,
16633
+ };
16634
+ }
16635
+ /**
16636
+ * Measures the perimeter of one projected quad.
16637
+ *
16638
+ * @param corners Quad corners.
16639
+ * @returns Perimeter length.
16640
+ *
16641
+ * @private helper of the 3D avatar visuals
16642
+ */
16643
+ function getProjectedQuadPerimeter(corners) {
16644
+ let perimeter = 0;
16645
+ for (let cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
16646
+ const currentCorner = corners[cornerIndex];
16647
+ const nextCorner = corners[(cornerIndex + 1) % corners.length];
16648
+ perimeter += Math.hypot(nextCorner.x - currentCorner.x, nextCorner.y - currentCorner.y);
16649
+ }
16650
+ return perimeter;
16651
+ }
16652
+
16473
16653
  /* eslint-disable no-magic-numbers */
16474
16654
  /**
16475
16655
  * Builds the seeded six-face texture pack used by the Minecraft-style head cuboid.
@@ -16642,18 +16822,12 @@
16642
16822
  }
16643
16823
 
16644
16824
  /* eslint-disable no-magic-numbers */
16645
- /**
16646
- * Fixed scene camera distance used for the proper-3D projection.
16647
- *
16648
- * @private helper of `minecraft2AvatarVisual`
16649
- */
16650
- const CAMERA_DISTANCE_RATIO = 1.4;
16651
16825
  /**
16652
16826
  * Shared light direction used to shade projected cuboid faces.
16653
16827
  *
16654
16828
  * @private helper of `minecraft2AvatarVisual`
16655
16829
  */
16656
- const LIGHT_DIRECTION = normalizeVector3({
16830
+ const LIGHT_DIRECTION$1 = normalizeVector3({
16657
16831
  x: 0.4,
16658
16832
  y: -0.65,
16659
16833
  z: 0.92,
@@ -16865,7 +17039,7 @@
16865
17039
  corners: projectedCorners,
16866
17040
  texture: faceDefinition.texture,
16867
17041
  averageDepth: transformedCorners.reduce((depthSum, corner) => depthSum + corner.z, 0) / transformedCorners.length,
16868
- lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION), -1, 1),
17042
+ lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$1), -1, 1),
16869
17043
  outlineColor: cuboid.outlineColor,
16870
17044
  };
16871
17045
  });
@@ -16892,7 +17066,7 @@
16892
17066
  const endX = (columnIndex + 1) / columns;
16893
17067
  const startY = rowIndex / rows;
16894
17068
  const endY = (rowIndex + 1) / rows;
16895
- drawProjectedQuad(context, [
17069
+ drawProjectedQuad$1(context, [
16896
17070
  interpolateProjectedQuad(face.corners, startX, startY),
16897
17071
  interpolateProjectedQuad(face.corners, endX, startY),
16898
17072
  interpolateProjectedQuad(face.corners, endX, endY),
@@ -16901,10 +17075,10 @@
16901
17075
  }
16902
17076
  }
16903
17077
  if (face.lightIntensity > 0) {
16904
- drawProjectedQuad(context, face.corners, `rgba(255, 255, 255, ${0.15 * face.lightIntensity})`);
17078
+ drawProjectedQuad$1(context, face.corners, `rgba(255, 255, 255, ${0.15 * face.lightIntensity})`);
16905
17079
  }
16906
17080
  else if (face.lightIntensity < 0) {
16907
- drawProjectedQuad(context, face.corners, `rgba(0, 0, 0, ${0.22 * Math.abs(face.lightIntensity)})`);
17081
+ drawProjectedQuad$1(context, face.corners, `rgba(0, 0, 0, ${0.22 * Math.abs(face.lightIntensity)})`);
16908
17082
  }
16909
17083
  context.save();
16910
17084
  context.beginPath();
@@ -16928,7 +17102,7 @@
16928
17102
  *
16929
17103
  * @private helper of `minecraft2AvatarVisual`
16930
17104
  */
16931
- function drawProjectedQuad(context, corners, fillStyle) {
17105
+ function drawProjectedQuad$1(context, corners, fillStyle) {
16932
17106
  context.beginPath();
16933
17107
  context.moveTo(corners[0].x, corners[0].y);
16934
17108
  context.lineTo(corners[1].x, corners[1].y);
@@ -16970,175 +17144,6 @@
16970
17144
  z: startPoint.z + (endPoint.z - startPoint.z) * ratio,
16971
17145
  };
16972
17146
  }
16973
- /**
16974
- * Projects one rotated scene point into canvas coordinates.
16975
- *
16976
- * @param point Scene point.
16977
- * @param size Canvas size in CSS pixels.
16978
- * @param sceneCenterX Horizontal scene center.
16979
- * @param sceneCenterY Vertical scene center.
16980
- * @returns Projected point.
16981
- *
16982
- * @private helper of `minecraft2AvatarVisual`
16983
- */
16984
- function projectScenePoint(point, size, sceneCenterX, sceneCenterY) {
16985
- const cameraDistance = size * CAMERA_DISTANCE_RATIO;
16986
- const perspectiveScale = cameraDistance / Math.max(cameraDistance - point.z, cameraDistance * 0.35);
16987
- return {
16988
- x: sceneCenterX + point.x * perspectiveScale,
16989
- y: sceneCenterY + point.y * perspectiveScale,
16990
- z: point.z,
16991
- };
16992
- }
16993
- /**
16994
- * Applies the local cuboid rotations and translation to one scene point.
16995
- *
16996
- * @param localPoint Point in cuboid-local space.
16997
- * @param center Cuboid center in scene space.
16998
- * @param rotationX Cuboid pitch in radians.
16999
- * @param rotationY Cuboid yaw in radians.
17000
- * @returns Transformed scene-space point.
17001
- *
17002
- * @private helper of `minecraft2AvatarVisual`
17003
- */
17004
- function transformScenePoint(localPoint, center, rotationX, rotationY) {
17005
- const yawedPoint = rotatePointAroundY(localPoint, rotationY);
17006
- const pitchedPoint = rotatePointAroundX(yawedPoint, rotationX);
17007
- return {
17008
- x: center.x + pitchedPoint.x,
17009
- y: center.y + pitchedPoint.y,
17010
- z: center.z + pitchedPoint.z,
17011
- };
17012
- }
17013
- /**
17014
- * Rotates one point around the local Y axis.
17015
- *
17016
- * @param point Source point.
17017
- * @param angle Rotation angle in radians.
17018
- * @returns Rotated point.
17019
- *
17020
- * @private helper of `minecraft2AvatarVisual`
17021
- */
17022
- function rotatePointAroundY(point, angle) {
17023
- const cosine = Math.cos(angle);
17024
- const sine = Math.sin(angle);
17025
- return {
17026
- x: point.x * cosine + point.z * sine,
17027
- y: point.y,
17028
- z: -point.x * sine + point.z * cosine,
17029
- };
17030
- }
17031
- /**
17032
- * Rotates one point around the local X axis.
17033
- *
17034
- * @param point Source point.
17035
- * @param angle Rotation angle in radians.
17036
- * @returns Rotated point.
17037
- *
17038
- * @private helper of `minecraft2AvatarVisual`
17039
- */
17040
- function rotatePointAroundX(point, angle) {
17041
- const cosine = Math.cos(angle);
17042
- const sine = Math.sin(angle);
17043
- return {
17044
- x: point.x,
17045
- y: point.y * cosine - point.z * sine,
17046
- z: point.y * sine + point.z * cosine,
17047
- };
17048
- }
17049
- /**
17050
- * Subtracts one 3D point from another.
17051
- *
17052
- * @param leftPoint Left point.
17053
- * @param rightPoint Right point.
17054
- * @returns Difference vector.
17055
- *
17056
- * @private helper of `minecraft2AvatarVisual`
17057
- */
17058
- function subtractPoint3D(leftPoint, rightPoint) {
17059
- return {
17060
- x: leftPoint.x - rightPoint.x,
17061
- y: leftPoint.y - rightPoint.y,
17062
- z: leftPoint.z - rightPoint.z,
17063
- };
17064
- }
17065
- /**
17066
- * Computes the 3D cross product of two vectors.
17067
- *
17068
- * @param leftVector Left vector.
17069
- * @param rightVector Right vector.
17070
- * @returns Cross product.
17071
- *
17072
- * @private helper of `minecraft2AvatarVisual`
17073
- */
17074
- function crossProduct3D(leftVector, rightVector) {
17075
- return {
17076
- x: leftVector.y * rightVector.z - leftVector.z * rightVector.y,
17077
- y: leftVector.z * rightVector.x - leftVector.x * rightVector.z,
17078
- z: leftVector.x * rightVector.y - leftVector.y * rightVector.x,
17079
- };
17080
- }
17081
- /**
17082
- * Computes the 3D dot product of two vectors.
17083
- *
17084
- * @param leftVector Left vector.
17085
- * @param rightVector Right vector.
17086
- * @returns Dot product.
17087
- *
17088
- * @private helper of `minecraft2AvatarVisual`
17089
- */
17090
- function dotProduct3D(leftVector, rightVector) {
17091
- return leftVector.x * rightVector.x + leftVector.y * rightVector.y + leftVector.z * rightVector.z;
17092
- }
17093
- /**
17094
- * Normalizes one 3D vector while keeping zero vectors stable.
17095
- *
17096
- * @param vector Source vector.
17097
- * @returns Normalized vector.
17098
- *
17099
- * @private helper of `minecraft2AvatarVisual`
17100
- */
17101
- function normalizeVector3(vector) {
17102
- const length = Math.hypot(vector.x, vector.y, vector.z);
17103
- if (length === 0) {
17104
- return vector;
17105
- }
17106
- return {
17107
- x: vector.x / length,
17108
- y: vector.y / length,
17109
- z: vector.z / length,
17110
- };
17111
- }
17112
- /**
17113
- * Clamps one number into the provided range.
17114
- *
17115
- * @param value Input value.
17116
- * @param minimumValue Inclusive lower bound.
17117
- * @param maximumValue Inclusive upper bound.
17118
- * @returns Clamped value.
17119
- *
17120
- * @private helper of `minecraft2AvatarVisual`
17121
- */
17122
- function clampNumber$1(value, minimumValue, maximumValue) {
17123
- return Math.min(maximumValue, Math.max(minimumValue, value));
17124
- }
17125
- /**
17126
- * Measures the perimeter of one projected quad.
17127
- *
17128
- * @param corners Quad corners.
17129
- * @returns Perimeter length.
17130
- *
17131
- * @private helper of `minecraft2AvatarVisual`
17132
- */
17133
- function getProjectedQuadPerimeter(corners) {
17134
- let perimeter = 0;
17135
- for (let cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
17136
- const currentCorner = corners[cornerIndex];
17137
- const nextCorner = corners[(cornerIndex + 1) % corners.length];
17138
- perimeter += Math.hypot(nextCorner.x - currentCorner.x, nextCorner.y - currentCorner.y);
17139
- }
17140
- return perimeter;
17141
- }
17142
17147
 
17143
17148
  /* eslint-disable no-magic-numbers */
17144
17149
  /**
@@ -17707,7 +17712,7 @@
17707
17712
  *
17708
17713
  * @private helper of `octopus3AvatarVisual`
17709
17714
  */
17710
- function formatAlphaHex(opacity) {
17715
+ function formatAlphaHex$1(opacity) {
17711
17716
  return Math.round(Math.min(1, Math.max(0, opacity)) * 255)
17712
17717
  .toString(16)
17713
17718
  .padStart(2, '0');
@@ -18086,7 +18091,7 @@
18086
18091
  context.beginPath();
18087
18092
  context.moveTo(-radiusX * 0.74, radiusY * 0.2);
18088
18093
  context.quadraticCurveTo(0, radiusY * 0.38, radiusX * 0.74, radiusY * 0.2);
18089
- context.strokeStyle = `${palette.highlight}${formatAlphaHex(eyeStyle.lowerLidOpacity)}`;
18094
+ context.strokeStyle = `${palette.highlight}${formatAlphaHex$1(eyeStyle.lowerLidOpacity)}`;
18090
18095
  context.lineWidth = radiusX * 0.08;
18091
18096
  context.lineCap = 'round';
18092
18097
  context.stroke();
@@ -18094,6 +18099,518 @@
18094
18099
  context.restore();
18095
18100
  }
18096
18101
 
18102
+ /* eslint-disable no-magic-numbers */
18103
+ /**
18104
+ * Light direction used by the organic 3D octopus shading.
18105
+ *
18106
+ * @private helper of `octopus3dAvatarVisual`
18107
+ */
18108
+ const LIGHT_DIRECTION = normalizeVector3({
18109
+ x: 0.48,
18110
+ y: -0.62,
18111
+ z: 0.94,
18112
+ });
18113
+ /**
18114
+ * Proper 3D Octopus visual built from projected organic meshes and tentacles.
18115
+ *
18116
+ * @private built-in avatar visual
18117
+ */
18118
+ const octopus3dAvatarVisual = {
18119
+ id: 'octopus3d',
18120
+ title: 'Octopus 3D',
18121
+ description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
18122
+ isAnimated: true,
18123
+ supportsPointerTracking: true,
18124
+ render({ context, size, palette, createRandom, timeMs, interaction }) {
18125
+ const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
18126
+ const animationRandom = createRandom('octopus3d-animation-profile');
18127
+ const eyeRandom = createRandom('octopus3d-eye-profile');
18128
+ const animationPhase = animationRandom() * Math.PI * 2;
18129
+ const sceneCenterX = size * 0.5;
18130
+ const sceneCenterY = size * 0.56;
18131
+ const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
18132
+ const mantleCenter = {
18133
+ x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
18134
+ y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
18135
+ z: interaction.intensity * size * 0.012,
18136
+ };
18137
+ const underbodyCenter = {
18138
+ x: mantleCenter.x * 0.86,
18139
+ y: mantleCenter.y + size * 0.168,
18140
+ z: mantleCenter.z - size * 0.018,
18141
+ };
18142
+ const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
18143
+ const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
18144
+ const mantleRadiusZ = size * morphologyProfile.body.bodyRadiusRatio * (0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
18145
+ const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
18146
+ const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
18147
+ const underbodyRadiusZ = mantleRadiusZ * 0.78;
18148
+ const bodyYaw = -0.18 +
18149
+ Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
18150
+ interaction.bodyOffsetX * 0.18 +
18151
+ interaction.gazeX * 0.22;
18152
+ const bodyPitch = -0.08 +
18153
+ Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
18154
+ interaction.bodyOffsetY * 0.08 -
18155
+ interaction.gazeY * 0.08;
18156
+ const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
18157
+ const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
18158
+ const mantlePatches = resolveVisibleEllipsoidPatches({
18159
+ center: mantleCenter,
18160
+ radiusX: mantleRadiusX,
18161
+ radiusY: mantleRadiusY,
18162
+ radiusZ: mantleRadiusZ,
18163
+ rotationX: headPitch,
18164
+ rotationY: headYaw,
18165
+ sceneCenterX,
18166
+ sceneCenterY,
18167
+ size,
18168
+ palette,
18169
+ verticalColorBias: 0,
18170
+ outlineColor: `${palette.highlight}7a`,
18171
+ });
18172
+ const underbodyPatches = resolveVisibleEllipsoidPatches({
18173
+ center: underbodyCenter,
18174
+ radiusX: underbodyRadiusX,
18175
+ radiusY: underbodyRadiusY,
18176
+ radiusZ: underbodyRadiusZ,
18177
+ rotationX: bodyPitch,
18178
+ rotationY: bodyYaw,
18179
+ sceneCenterX,
18180
+ sceneCenterY,
18181
+ size,
18182
+ palette,
18183
+ verticalColorBias: 0.18,
18184
+ outlineColor: `${palette.shadow}8f`,
18185
+ });
18186
+ const tentacleStrokes = createOctopusTentacleStrokes({
18187
+ createRandom,
18188
+ morphologyProfile,
18189
+ timeMs,
18190
+ size,
18191
+ center: underbodyCenter,
18192
+ radiusX: underbodyRadiusX,
18193
+ radiusY: underbodyRadiusY,
18194
+ radiusZ: underbodyRadiusZ,
18195
+ rotationX: bodyPitch,
18196
+ rotationY: bodyYaw,
18197
+ sceneCenterX,
18198
+ sceneCenterY,
18199
+ animationPhase,
18200
+ });
18201
+ const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
18202
+ const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
18203
+ const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
18204
+ const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
18205
+ const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
18206
+ const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
18207
+ drawAvatarFrame(context, size, palette);
18208
+ drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
18209
+ drawOctopus3dShadow(context, size, palette, interaction, timeMs);
18210
+ for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
18211
+ drawTentacleStroke(context, tentacleStroke, palette);
18212
+ }
18213
+ for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
18214
+ drawSurfacePatch(context, surfacePatch);
18215
+ }
18216
+ for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
18217
+ drawTentacleStroke(context, tentacleStroke, palette);
18218
+ }
18219
+ drawProjectedEye(context, {
18220
+ x: -faceEyeSpacing,
18221
+ y: faceEyeYOffset,
18222
+ z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
18223
+ }, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
18224
+ drawProjectedEye(context, {
18225
+ x: faceEyeSpacing,
18226
+ y: faceEyeYOffset,
18227
+ z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
18228
+ }, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
18229
+ drawProjectedMouth(context, [
18230
+ { x: -mouthHalfWidth, y: mouthY, z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY) },
18231
+ {
18232
+ x: size * morphologyProfile.face.mouthCenterOffsetRatio,
18233
+ y: mouthY +
18234
+ size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
18235
+ Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
18236
+ interaction.gazeY * size * 0.01,
18237
+ z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
18238
+ },
18239
+ { x: mouthHalfWidth, y: mouthY, z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY) },
18240
+ ], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
18241
+ },
18242
+ };
18243
+ /**
18244
+ * Draws the atmospheric underwater glow behind the octopus mesh.
18245
+ *
18246
+ * @private helper of `octopus3dAvatarVisual`
18247
+ */
18248
+ function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
18249
+ const glowGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.1, sceneCenterY - size * 0.2 + interaction.gazeY * size * 0.05, size * 0.04, sceneCenterX, sceneCenterY - size * 0.04, size * 0.62);
18250
+ glowGradient.addColorStop(0, `${palette.highlight}5c`);
18251
+ glowGradient.addColorStop(0.36, `${palette.accent}24`);
18252
+ glowGradient.addColorStop(1, `${palette.highlight}00`);
18253
+ context.fillStyle = glowGradient;
18254
+ context.fillRect(0, 0, size, size);
18255
+ const lowerGradient = context.createRadialGradient(sceneCenterX + Math.sin(timeMs / 1700) * size * 0.05, sceneCenterY + size * 0.23, size * 0.08, sceneCenterX, sceneCenterY + size * 0.28, size * 0.5);
18256
+ lowerGradient.addColorStop(0, `${palette.secondary}1d`);
18257
+ lowerGradient.addColorStop(1, `${palette.secondary}00`);
18258
+ context.fillStyle = lowerGradient;
18259
+ context.fillRect(0, 0, size, size);
18260
+ }
18261
+ /**
18262
+ * Draws the soft ground shadow below the octopus.
18263
+ *
18264
+ * @private helper of `octopus3dAvatarVisual`
18265
+ */
18266
+ function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
18267
+ context.save();
18268
+ context.fillStyle = `${palette.shadow}66`;
18269
+ context.filter = `blur(${size * 0.022}px)`;
18270
+ context.beginPath();
18271
+ 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);
18272
+ context.fill();
18273
+ context.restore();
18274
+ }
18275
+ /**
18276
+ * Resolves visible projected patches for one rotated ellipsoid mesh.
18277
+ *
18278
+ * @private helper of `octopus3dAvatarVisual`
18279
+ */
18280
+ function resolveVisibleEllipsoidPatches(options) {
18281
+ const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
18282
+ const latitudePatchCount = 10;
18283
+ const longitudePatchCount = 18;
18284
+ const surfacePatches = [];
18285
+ for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
18286
+ const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
18287
+ const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
18288
+ const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
18289
+ for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
18290
+ const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
18291
+ const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
18292
+ const localCorners = [
18293
+ sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
18294
+ sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
18295
+ sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
18296
+ sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
18297
+ ];
18298
+ const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
18299
+ const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
18300
+ if (surfaceNormal.z <= 0.01) {
18301
+ continue;
18302
+ }
18303
+ const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
18304
+ surfacePatches.push({
18305
+ corners: projectedCorners,
18306
+ averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
18307
+ transformedCorners.length,
18308
+ lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
18309
+ fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
18310
+ outlineColor,
18311
+ });
18312
+ }
18313
+ }
18314
+ return surfacePatches;
18315
+ }
18316
+ /**
18317
+ * Samples one point on an ellipsoid aligned to the local axes.
18318
+ *
18319
+ * @private helper of `octopus3dAvatarVisual`
18320
+ */
18321
+ function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
18322
+ const cosineLatitude = Math.cos(latitude);
18323
+ return {
18324
+ x: Math.sin(longitude) * cosineLatitude * radiusX,
18325
+ y: Math.sin(latitude) * radiusY,
18326
+ z: Math.cos(longitude) * cosineLatitude * radiusZ,
18327
+ };
18328
+ }
18329
+ /**
18330
+ * Resolves one base fill tone for a surface patch across the octopus body.
18331
+ *
18332
+ * @private helper of `octopus3dAvatarVisual`
18333
+ */
18334
+ function resolveSurfacePatchFillStyle(palette, verticalProgress) {
18335
+ const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
18336
+ if (clampedVerticalProgress < 0.2) {
18337
+ return palette.highlight;
18338
+ }
18339
+ if (clampedVerticalProgress < 0.45) {
18340
+ return palette.secondary;
18341
+ }
18342
+ if (clampedVerticalProgress < 0.8) {
18343
+ return palette.primary;
18344
+ }
18345
+ return `${palette.shadow}f2`;
18346
+ }
18347
+ /**
18348
+ * Draws one projected mesh patch with organic shading.
18349
+ *
18350
+ * @private helper of `octopus3dAvatarVisual`
18351
+ */
18352
+ function drawSurfacePatch(context, surfacePatch) {
18353
+ drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
18354
+ if (surfacePatch.lightIntensity > 0) {
18355
+ drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
18356
+ }
18357
+ else if (surfacePatch.lightIntensity < 0) {
18358
+ drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
18359
+ }
18360
+ context.save();
18361
+ context.beginPath();
18362
+ context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
18363
+ for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
18364
+ context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
18365
+ }
18366
+ context.closePath();
18367
+ context.strokeStyle = surfacePatch.outlineColor;
18368
+ context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
18369
+ context.lineJoin = 'round';
18370
+ context.stroke();
18371
+ context.restore();
18372
+ }
18373
+ /**
18374
+ * Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
18375
+ *
18376
+ * @private helper of `octopus3dAvatarVisual`
18377
+ */
18378
+ function createOctopusTentacleStrokes(options) {
18379
+ const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
18380
+ return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
18381
+ const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
18382
+ const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
18383
+ const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
18384
+ const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
18385
+ const lateralReach = size *
18386
+ (0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
18387
+ const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
18388
+ const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
18389
+ const anchorPoint = {
18390
+ x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
18391
+ y: radiusY * (0.22 + tentacleRandom() * 0.18),
18392
+ z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
18393
+ };
18394
+ const controlPointOne = {
18395
+ x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
18396
+ y: anchorPoint.y + flowLength * 0.26,
18397
+ z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
18398
+ };
18399
+ const controlPointTwo = {
18400
+ x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
18401
+ y: anchorPoint.y + flowLength * 0.66,
18402
+ z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
18403
+ };
18404
+ const endPoint = {
18405
+ x: anchorPoint.x +
18406
+ Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
18407
+ sway * size * 0.028,
18408
+ y: anchorPoint.y + flowLength,
18409
+ z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
18410
+ };
18411
+ const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
18412
+ const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
18413
+ const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
18414
+ return {
18415
+ projectedPoints,
18416
+ averageDepth,
18417
+ isFrontFacing: averageDepth >= center.z - size * 0.006,
18418
+ baseWidth: size *
18419
+ (0.019 +
18420
+ morphologyProfile.tentacles.baseWidthScale * 0.007 +
18421
+ tentacleRandom() * 0.003 +
18422
+ Math.abs(Math.sin(orbitAngle)) * 0.002),
18423
+ tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
18424
+ colorBias: tentacleRandom(),
18425
+ };
18426
+ });
18427
+ }
18428
+ /**
18429
+ * Samples one point on a cubic Bezier curve in 3D.
18430
+ *
18431
+ * @private helper of `octopus3dAvatarVisual`
18432
+ */
18433
+ function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
18434
+ const inverseProgress = 1 - progress;
18435
+ return {
18436
+ x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
18437
+ 3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
18438
+ 3 * inverseProgress * progress * progress * controlPointTwo.x +
18439
+ progress * progress * progress * endPoint.x,
18440
+ y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
18441
+ 3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
18442
+ 3 * inverseProgress * progress * progress * controlPointTwo.y +
18443
+ progress * progress * progress * endPoint.y,
18444
+ z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
18445
+ 3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
18446
+ 3 * inverseProgress * progress * progress * controlPointTwo.z +
18447
+ progress * progress * progress * endPoint.z,
18448
+ };
18449
+ }
18450
+ /**
18451
+ * Draws one projected tentacle stroke with a slim highlight ridge.
18452
+ *
18453
+ * @private helper of `octopus3dAvatarVisual`
18454
+ */
18455
+ function drawTentacleStroke(context, tentacleStroke, palette) {
18456
+ const projectedSegments = tentacleStroke.projectedPoints.length - 1;
18457
+ for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
18458
+ const startPoint = tentacleStroke.projectedPoints[segmentIndex];
18459
+ const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
18460
+ const progress = segmentIndex / projectedSegments;
18461
+ const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
18462
+ context.beginPath();
18463
+ context.moveTo(startPoint.x, startPoint.y);
18464
+ context.lineTo(endPoint.x, endPoint.y);
18465
+ context.strokeStyle =
18466
+ tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
18467
+ context.lineWidth = width;
18468
+ context.lineCap = 'round';
18469
+ context.stroke();
18470
+ context.beginPath();
18471
+ context.moveTo(startPoint.x, startPoint.y);
18472
+ context.lineTo(endPoint.x, endPoint.y);
18473
+ context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
18474
+ context.lineWidth = Math.max(1, width * 0.34);
18475
+ context.lineCap = 'round';
18476
+ context.stroke();
18477
+ }
18478
+ }
18479
+ /**
18480
+ * Resolves the front surface depth on an ellipsoid for one local face point.
18481
+ *
18482
+ * @private helper of `octopus3dAvatarVisual`
18483
+ */
18484
+ function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
18485
+ const normalizedX = x / radiusX;
18486
+ const normalizedY = y / radiusY;
18487
+ const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
18488
+ return Math.sqrt(remainingDepthRatio) * radiusZ;
18489
+ }
18490
+ /**
18491
+ * Draws one projected eye on the turned octopus mantle.
18492
+ *
18493
+ * @private helper of `octopus3dAvatarVisual`
18494
+ */
18495
+ function drawProjectedEye(context, localCenter, radiusX, radiusY, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, phase, interaction, eyeStyle) {
18496
+ const centerScenePoint = transformScenePoint(localCenter, center, rotationX, rotationY);
18497
+ if (centerScenePoint.z <= center.z) {
18498
+ return;
18499
+ }
18500
+ const horizontalScenePoint = transformScenePoint({ x: localCenter.x + radiusX, y: localCenter.y, z: localCenter.z }, center, rotationX, rotationY);
18501
+ const verticalScenePoint = transformScenePoint({ x: localCenter.x, y: localCenter.y + radiusY, z: localCenter.z }, center, rotationX, rotationY);
18502
+ const projectedCenterPoint = projectScenePoint(centerScenePoint, size, sceneCenterX, sceneCenterY);
18503
+ const projectedHorizontalPoint = projectScenePoint(horizontalScenePoint, size, sceneCenterX, sceneCenterY);
18504
+ const projectedVerticalPoint = projectScenePoint(verticalScenePoint, size, sceneCenterX, sceneCenterY);
18505
+ const projectedRadiusX = Math.hypot(projectedHorizontalPoint.x - projectedCenterPoint.x, projectedHorizontalPoint.y - projectedCenterPoint.y);
18506
+ const projectedRadiusY = Math.hypot(projectedVerticalPoint.x - projectedCenterPoint.x, projectedVerticalPoint.y - projectedCenterPoint.y);
18507
+ if (projectedRadiusX < size * 0.008 || projectedRadiusY < size * 0.008) {
18508
+ return;
18509
+ }
18510
+ const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
18511
+ radiusX: projectedRadiusX,
18512
+ radiusY: projectedRadiusY,
18513
+ timeMs,
18514
+ phase,
18515
+ interaction,
18516
+ });
18517
+ const rotation = Math.atan2(projectedHorizontalPoint.y - projectedCenterPoint.y, projectedHorizontalPoint.x - projectedCenterPoint.x);
18518
+ context.save();
18519
+ context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
18520
+ context.rotate(rotation);
18521
+ context.beginPath();
18522
+ context.ellipse(0, 0, projectedRadiusX, projectedRadiusY, 0, 0, Math.PI * 2);
18523
+ context.fillStyle = '#f8fbff';
18524
+ context.fill();
18525
+ context.clip();
18526
+ const irisGradient = context.createRadialGradient(-projectedRadiusX * 0.2, -projectedRadiusY * 0.26, projectedRadiusX * 0.05, 0, 0, projectedRadiusX * 0.92);
18527
+ irisGradient.addColorStop(0, palette.highlight);
18528
+ irisGradient.addColorStop(0.56, palette.secondary);
18529
+ irisGradient.addColorStop(1, palette.shadow);
18530
+ context.beginPath();
18531
+ context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.62 * eyeStyle.irisScale, projectedRadiusY * 0.72 * eyeStyle.irisScale, 0, 0, Math.PI * 2);
18532
+ context.fillStyle = irisGradient;
18533
+ context.fill();
18534
+ context.beginPath();
18535
+ context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.15 * eyeStyle.pupilWidthScale, projectedRadiusY * 0.48 * eyeStyle.pupilHeightScale, 0, 0, Math.PI * 2);
18536
+ context.fillStyle = palette.ink;
18537
+ context.fill();
18538
+ context.beginPath();
18539
+ context.ellipse(pupilOffsetX - projectedRadiusX * 0.22, pupilOffsetY - projectedRadiusY * 0.24, projectedRadiusX * 0.12, projectedRadiusY * 0.14, 0, 0, Math.PI * 2);
18540
+ context.fillStyle = '#ffffff';
18541
+ context.fill();
18542
+ context.restore();
18543
+ context.save();
18544
+ context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
18545
+ context.rotate(rotation);
18546
+ context.beginPath();
18547
+ context.ellipse(0, 0, projectedRadiusX, projectedRadiusY, 0, 0, Math.PI * 2);
18548
+ context.strokeStyle = `${palette.shadow}cc`;
18549
+ context.lineWidth = projectedRadiusX * 0.16;
18550
+ context.stroke();
18551
+ context.beginPath();
18552
+ context.moveTo(-projectedRadiusX * 0.88, -projectedRadiusY * eyeStyle.upperLidInsetRatio);
18553
+ context.quadraticCurveTo(0, -projectedRadiusY * (eyeStyle.upperLidArchRatio - interaction.gazeY * 0.16 + interaction.intensity * 0.08), projectedRadiusX * 0.88, -projectedRadiusY * eyeStyle.upperLidInsetRatio);
18554
+ context.strokeStyle = `${palette.shadow}73`;
18555
+ context.lineWidth = projectedRadiusX * 0.14;
18556
+ context.lineCap = 'round';
18557
+ context.stroke();
18558
+ if (eyeStyle.lowerLidOpacity > 0) {
18559
+ context.beginPath();
18560
+ context.moveTo(-projectedRadiusX * 0.74, projectedRadiusY * 0.2);
18561
+ context.quadraticCurveTo(0, projectedRadiusY * 0.38, projectedRadiusX * 0.74, projectedRadiusY * 0.2);
18562
+ context.strokeStyle = `${palette.highlight}${formatAlphaHex(eyeStyle.lowerLidOpacity)}`;
18563
+ context.lineWidth = projectedRadiusX * 0.08;
18564
+ context.lineCap = 'round';
18565
+ context.stroke();
18566
+ }
18567
+ context.restore();
18568
+ }
18569
+ /**
18570
+ * Draws a subtle projected mouth arc across the front of the mantle.
18571
+ *
18572
+ * @private helper of `octopus3dAvatarVisual`
18573
+ */
18574
+ function drawProjectedMouth(context, localPoints, center, rotationX, rotationY, sceneCenterX, sceneCenterY, palette, size) {
18575
+ const scenePoints = localPoints.map((localPoint) => transformScenePoint(localPoint, center, rotationX, rotationY));
18576
+ if (scenePoints.some((scenePoint) => scenePoint.z <= center.z)) {
18577
+ return;
18578
+ }
18579
+ const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
18580
+ context.beginPath();
18581
+ context.moveTo(projectedPoints[0].x, projectedPoints[0].y);
18582
+ context.quadraticCurveTo(projectedPoints[1].x, projectedPoints[1].y, projectedPoints[2].x, projectedPoints[2].y);
18583
+ context.strokeStyle = `${palette.ink}b8`;
18584
+ context.lineWidth = Math.max(1.1, size * 0.009);
18585
+ context.lineCap = 'round';
18586
+ context.stroke();
18587
+ }
18588
+ /**
18589
+ * Draws one filled projected quad.
18590
+ *
18591
+ * @private helper of `octopus3dAvatarVisual`
18592
+ */
18593
+ function drawProjectedQuad(context, corners, fillStyle) {
18594
+ context.beginPath();
18595
+ context.moveTo(corners[0].x, corners[0].y);
18596
+ context.lineTo(corners[1].x, corners[1].y);
18597
+ context.lineTo(corners[2].x, corners[2].y);
18598
+ context.lineTo(corners[3].x, corners[3].y);
18599
+ context.closePath();
18600
+ context.fillStyle = fillStyle;
18601
+ context.fill();
18602
+ }
18603
+ /**
18604
+ * Converts an opacity ratio into a two-digit hexadecimal alpha suffix.
18605
+ *
18606
+ * @private helper of `octopus3dAvatarVisual`
18607
+ */
18608
+ function formatAlphaHex(opacity) {
18609
+ return Math.round(clampNumber$1(opacity, 0, 1) * 255)
18610
+ .toString(16)
18611
+ .padStart(2, '0');
18612
+ }
18613
+
18097
18614
  /* eslint-disable no-magic-numbers */
18098
18615
  /**
18099
18616
  * Octopus avatar visual.
@@ -18862,6 +19379,7 @@
18862
19379
  octopusAvatarVisual,
18863
19380
  octopus2AvatarVisual,
18864
19381
  octopus3AvatarVisual,
19382
+ octopus3dAvatarVisual,
18865
19383
  asciiOctopusAvatarVisual,
18866
19384
  minecraftAvatarVisual,
18867
19385
  minecraft2AvatarVisual,
@@ -21055,16 +21573,22 @@
21055
21573
  * Each teammate is listed with its tool name, TEAM instructions, and optional profile hints.
21056
21574
  */
21057
21575
  function buildTeamSystemMessageBody(teamEntries) {
21058
- const lines = [
21059
- ...TEAM_SYSTEM_MESSAGE_GUIDANCE_LINES,
21060
- '',
21061
- ...teamEntries.map((entry, index) => {
21062
- const toolLine = `${index + 1}) ${entry.teammate.label} tool \`${entry.toolName}\``;
21063
- const detailLines = collectTeamEntryDetails(entry).map(formatTeamEntryDetailLine);
21064
- return [toolLine, ...detailLines].join('\n');
21065
- }),
21066
- ];
21067
- return lines.join('\n');
21576
+ const teammateSections = teamEntries.map((entry, index) => {
21577
+ const toolLine = `${index + 1}) ${entry.teammate.label} tool \`${entry.toolName}\``;
21578
+ const detailLines = collectTeamEntryDetails(entry).map(formatTeamEntryDetailLine);
21579
+ if (detailLines.length === 0) {
21580
+ return toolLine;
21581
+ }
21582
+ return _spaceTrim.spaceTrim((block) => `
21583
+ ${toolLine}
21584
+ ${block(detailLines.join('\n'))}
21585
+ `);
21586
+ });
21587
+ return _spaceTrim.spaceTrim((block) => `
21588
+ ${block(TEAM_SYSTEM_MESSAGE_GUIDANCE_LINES.join('\n'))}
21589
+
21590
+ ${block(teammateSections.join('\n\n'))}
21591
+ `);
21068
21592
  }
21069
21593
  /**
21070
21594
  * Builds the model-visible description for one teammate tool.
@@ -34057,7 +34581,11 @@
34057
34581
  if (examples.length === 0) {
34058
34582
  return null;
34059
34583
  }
34060
- return `## Sample of communication with the agent:\n\n${examples.join('\n\n')}`;
34584
+ return _spaceTrim.spaceTrim((block) => `
34585
+ ## Sample of communication with the agent:
34586
+
34587
+ ${block(examples.join('\n\n'))}
34588
+ `);
34061
34589
  }
34062
34590
  /**
34063
34591
  * Collects the individual lines used in the example interaction section.
@@ -34094,7 +34622,11 @@
34094
34622
  function appendSystemMessageSection(requirements, section) {
34095
34623
  return {
34096
34624
  ...requirements,
34097
- systemMessage: requirements.systemMessage + '\n\n' + section,
34625
+ systemMessage: _spaceTrim.spaceTrim((block) => `
34626
+ ${block(requirements.systemMessage)}
34627
+
34628
+ ${block(section)}
34629
+ `),
34098
34630
  };
34099
34631
  }
34100
34632
  /**