@promptbook/core 0.112.0-69 → 0.112.0-71
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 +847 -302
- package/esm/index.es.js.map +1 -1
- package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/esm/src/avatars/visuals/avatar3dProjectionShared.d.ts +141 -0
- package/esm/src/avatars/visuals/octopus3dAvatarVisual.d.ts +7 -0
- package/esm/src/cli/cli-commands/agent/agentProjectPaths.d.ts +2 -2
- package/esm/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +22 -0
- package/esm/src/cli/cli-commands/agent/runMultiple.d.ts +10 -0
- package/esm/src/cli/cli-commands/agent.d.ts +3 -2
- package/esm/src/cli/other/install.test.d.ts +1 -0
- package/esm/src/commitments/USE_TIMEOUT/USE_TIMEOUT.d.ts +1 -1
- package/esm/src/commitments/WALLET/WALLET.d.ts +1 -1
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +847 -302
- package/umd/index.umd.js.map +1 -1
- package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/umd/src/avatars/visuals/avatar3dProjectionShared.d.ts +141 -0
- package/umd/src/avatars/visuals/octopus3dAvatarVisual.d.ts +7 -0
- package/umd/src/cli/cli-commands/agent/agentProjectPaths.d.ts +2 -2
- package/umd/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +22 -0
- package/umd/src/cli/cli-commands/agent/runMultiple.d.ts +10 -0
- package/umd/src/cli/cli-commands/agent.d.ts +3 -2
- package/umd/src/cli/other/install.test.d.ts +1 -0
- package/umd/src/commitments/USE_TIMEOUT/USE_TIMEOUT.d.ts +1 -1
- package/umd/src/commitments/WALLET/WALLET.d.ts +1 -1
- package/umd/src/version.d.ts +1 -1
package/umd/index.umd.js
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* @generated
|
|
28
28
|
* @see https://github.com/webgptorg/promptbook
|
|
29
29
|
*/
|
|
30
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
30
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-71';
|
|
31
31
|
/**
|
|
32
32
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
33
33
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -1826,11 +1826,11 @@
|
|
|
1826
1826
|
*/
|
|
1827
1827
|
function pipelineJsonToString(pipelineJson) {
|
|
1828
1828
|
const { title, pipelineUrl, bookVersion, description, parameters, tasks } = pipelineJson;
|
|
1829
|
-
let pipelineString =
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1829
|
+
let pipelineString = spacetrim.spaceTrim((block) => `
|
|
1830
|
+
# ${title}
|
|
1831
|
+
|
|
1832
|
+
${block(description || '')}
|
|
1833
|
+
`);
|
|
1834
1834
|
const commands = [];
|
|
1835
1835
|
if (pipelineUrl) {
|
|
1836
1836
|
commands.push(`PIPELINE URL ${pipelineUrl}`);
|
|
@@ -1846,20 +1846,17 @@
|
|
|
1846
1846
|
for (const parameter of parameters.filter(({ isOutput }) => isOutput)) {
|
|
1847
1847
|
commands.push(`OUTPUT PARAMETER ${taskParameterJsonToString(parameter)}`);
|
|
1848
1848
|
}
|
|
1849
|
-
pipelineString
|
|
1850
|
-
|
|
1849
|
+
pipelineString = spacetrim.spaceTrim((block) => `
|
|
1850
|
+
${block(pipelineString)}
|
|
1851
|
+
|
|
1852
|
+
${block(commands.map((command) => `- ${command}`).join('\n'))}
|
|
1853
|
+
`);
|
|
1851
1854
|
for (const task of tasks) {
|
|
1852
1855
|
const {
|
|
1853
1856
|
/* Note: Not using:> name, */
|
|
1854
1857
|
title, description,
|
|
1855
1858
|
/* Note: dependentParameterNames, */
|
|
1856
1859
|
jokerParameterNames: jokers, taskType, content, postprocessingFunctionNames: postprocessing, expectations, format, resultingParameterName, } = task;
|
|
1857
|
-
pipelineString += '\n\n';
|
|
1858
|
-
pipelineString += `## ${title}`;
|
|
1859
|
-
if (description) {
|
|
1860
|
-
pipelineString += '\n\n';
|
|
1861
|
-
pipelineString += description;
|
|
1862
|
-
}
|
|
1863
1860
|
const commands = [];
|
|
1864
1861
|
let contentLanguage = 'text';
|
|
1865
1862
|
if (taskType === 'PROMPT_TASK') {
|
|
@@ -1922,18 +1919,23 @@
|
|
|
1922
1919
|
commands.push(`FORMAT JSON`);
|
|
1923
1920
|
}
|
|
1924
1921
|
} /* not else */
|
|
1925
|
-
pipelineString
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1922
|
+
pipelineString = spacetrim.spaceTrim((block) => `
|
|
1923
|
+
${block(pipelineString)}
|
|
1924
|
+
|
|
1925
|
+
## ${title}
|
|
1926
|
+
|
|
1927
|
+
${block(description || '')}
|
|
1928
|
+
|
|
1929
|
+
${block(commands.map((command) => `- ${command}`).join('\n'))}
|
|
1930
|
+
|
|
1931
|
+
\`\`\`${contentLanguage}
|
|
1932
|
+
${block(spacetrim.spaceTrim(content))}
|
|
1933
|
+
\`\`\`
|
|
1934
|
+
|
|
1935
|
+
\`-> {${resultingParameterName}}\`
|
|
1936
|
+
`); // <- TODO: [main] !!3 If the parameter here has description, add it and use taskParameterJsonToString
|
|
1937
|
+
// <- TODO: [main] !!3 Escape
|
|
1938
|
+
// <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
|
|
1937
1939
|
}
|
|
1938
1940
|
return validatePipelineString(pipelineString);
|
|
1939
1941
|
}
|
|
@@ -12452,6 +12454,184 @@
|
|
|
12452
12454
|
context.restore();
|
|
12453
12455
|
}
|
|
12454
12456
|
|
|
12457
|
+
/* eslint-disable no-magic-numbers */
|
|
12458
|
+
/**
|
|
12459
|
+
* Default camera distance ratio shared by the proper-3D avatar visuals.
|
|
12460
|
+
*
|
|
12461
|
+
* @private helper of the 3D avatar visuals
|
|
12462
|
+
*/
|
|
12463
|
+
const DEFAULT_3D_CAMERA_DISTANCE_RATIO = 1.4;
|
|
12464
|
+
/**
|
|
12465
|
+
* Clamps one number into the provided range.
|
|
12466
|
+
*
|
|
12467
|
+
* @param value Input value.
|
|
12468
|
+
* @param minimumValue Inclusive lower bound.
|
|
12469
|
+
* @param maximumValue Inclusive upper bound.
|
|
12470
|
+
* @returns Clamped value.
|
|
12471
|
+
*
|
|
12472
|
+
* @private helper of the 3D avatar visuals
|
|
12473
|
+
*/
|
|
12474
|
+
function clampNumber$1(value, minimumValue, maximumValue) {
|
|
12475
|
+
return Math.min(maximumValue, Math.max(minimumValue, value));
|
|
12476
|
+
}
|
|
12477
|
+
/**
|
|
12478
|
+
* Rotates one point around the local Y axis.
|
|
12479
|
+
*
|
|
12480
|
+
* @param point Source point.
|
|
12481
|
+
* @param angle Rotation angle in radians.
|
|
12482
|
+
* @returns Rotated point.
|
|
12483
|
+
*
|
|
12484
|
+
* @private helper of the 3D avatar visuals
|
|
12485
|
+
*/
|
|
12486
|
+
function rotatePointAroundY(point, angle) {
|
|
12487
|
+
const cosine = Math.cos(angle);
|
|
12488
|
+
const sine = Math.sin(angle);
|
|
12489
|
+
return {
|
|
12490
|
+
x: point.x * cosine + point.z * sine,
|
|
12491
|
+
y: point.y,
|
|
12492
|
+
z: -point.x * sine + point.z * cosine,
|
|
12493
|
+
};
|
|
12494
|
+
}
|
|
12495
|
+
/**
|
|
12496
|
+
* Rotates one point around the local X axis.
|
|
12497
|
+
*
|
|
12498
|
+
* @param point Source point.
|
|
12499
|
+
* @param angle Rotation angle in radians.
|
|
12500
|
+
* @returns Rotated point.
|
|
12501
|
+
*
|
|
12502
|
+
* @private helper of the 3D avatar visuals
|
|
12503
|
+
*/
|
|
12504
|
+
function rotatePointAroundX(point, angle) {
|
|
12505
|
+
const cosine = Math.cos(angle);
|
|
12506
|
+
const sine = Math.sin(angle);
|
|
12507
|
+
return {
|
|
12508
|
+
x: point.x,
|
|
12509
|
+
y: point.y * cosine - point.z * sine,
|
|
12510
|
+
z: point.y * sine + point.z * cosine,
|
|
12511
|
+
};
|
|
12512
|
+
}
|
|
12513
|
+
/**
|
|
12514
|
+
* Applies the local rotations and translation to one scene point.
|
|
12515
|
+
*
|
|
12516
|
+
* @param localPoint Point in local object space.
|
|
12517
|
+
* @param center Object center in scene space.
|
|
12518
|
+
* @param rotationX Object pitch in radians.
|
|
12519
|
+
* @param rotationY Object yaw in radians.
|
|
12520
|
+
* @returns Transformed scene-space point.
|
|
12521
|
+
*
|
|
12522
|
+
* @private helper of the 3D avatar visuals
|
|
12523
|
+
*/
|
|
12524
|
+
function transformScenePoint(localPoint, center, rotationX, rotationY) {
|
|
12525
|
+
const yawedPoint = rotatePointAroundY(localPoint, rotationY);
|
|
12526
|
+
const pitchedPoint = rotatePointAroundX(yawedPoint, rotationX);
|
|
12527
|
+
return {
|
|
12528
|
+
x: center.x + pitchedPoint.x,
|
|
12529
|
+
y: center.y + pitchedPoint.y,
|
|
12530
|
+
z: center.z + pitchedPoint.z,
|
|
12531
|
+
};
|
|
12532
|
+
}
|
|
12533
|
+
/**
|
|
12534
|
+
* Projects one scene point into canvas coordinates.
|
|
12535
|
+
*
|
|
12536
|
+
* @param point Scene-space point.
|
|
12537
|
+
* @param size Canvas size in CSS pixels.
|
|
12538
|
+
* @param sceneCenterX Horizontal scene center.
|
|
12539
|
+
* @param sceneCenterY Vertical scene center.
|
|
12540
|
+
* @param cameraDistanceRatio Optional camera distance ratio.
|
|
12541
|
+
* @returns Projected point.
|
|
12542
|
+
*
|
|
12543
|
+
* @private helper of the 3D avatar visuals
|
|
12544
|
+
*/
|
|
12545
|
+
function projectScenePoint(point, size, sceneCenterX, sceneCenterY, cameraDistanceRatio = DEFAULT_3D_CAMERA_DISTANCE_RATIO) {
|
|
12546
|
+
const cameraDistance = size * cameraDistanceRatio;
|
|
12547
|
+
const perspectiveScale = cameraDistance / Math.max(cameraDistance - point.z, cameraDistance * 0.35);
|
|
12548
|
+
return {
|
|
12549
|
+
x: sceneCenterX + point.x * perspectiveScale,
|
|
12550
|
+
y: sceneCenterY + point.y * perspectiveScale,
|
|
12551
|
+
z: point.z,
|
|
12552
|
+
};
|
|
12553
|
+
}
|
|
12554
|
+
/**
|
|
12555
|
+
* Subtracts one 3D point from another.
|
|
12556
|
+
*
|
|
12557
|
+
* @param leftPoint Left point.
|
|
12558
|
+
* @param rightPoint Right point.
|
|
12559
|
+
* @returns Difference vector.
|
|
12560
|
+
*
|
|
12561
|
+
* @private helper of the 3D avatar visuals
|
|
12562
|
+
*/
|
|
12563
|
+
function subtractPoint3D(leftPoint, rightPoint) {
|
|
12564
|
+
return {
|
|
12565
|
+
x: leftPoint.x - rightPoint.x,
|
|
12566
|
+
y: leftPoint.y - rightPoint.y,
|
|
12567
|
+
z: leftPoint.z - rightPoint.z,
|
|
12568
|
+
};
|
|
12569
|
+
}
|
|
12570
|
+
/**
|
|
12571
|
+
* Computes the 3D cross product of two vectors.
|
|
12572
|
+
*
|
|
12573
|
+
* @param leftVector Left vector.
|
|
12574
|
+
* @param rightVector Right vector.
|
|
12575
|
+
* @returns Cross product.
|
|
12576
|
+
*
|
|
12577
|
+
* @private helper of the 3D avatar visuals
|
|
12578
|
+
*/
|
|
12579
|
+
function crossProduct3D(leftVector, rightVector) {
|
|
12580
|
+
return {
|
|
12581
|
+
x: leftVector.y * rightVector.z - leftVector.z * rightVector.y,
|
|
12582
|
+
y: leftVector.z * rightVector.x - leftVector.x * rightVector.z,
|
|
12583
|
+
z: leftVector.x * rightVector.y - leftVector.y * rightVector.x,
|
|
12584
|
+
};
|
|
12585
|
+
}
|
|
12586
|
+
/**
|
|
12587
|
+
* Computes the 3D dot product of two vectors.
|
|
12588
|
+
*
|
|
12589
|
+
* @param leftVector Left vector.
|
|
12590
|
+
* @param rightVector Right vector.
|
|
12591
|
+
* @returns Dot product.
|
|
12592
|
+
*
|
|
12593
|
+
* @private helper of the 3D avatar visuals
|
|
12594
|
+
*/
|
|
12595
|
+
function dotProduct3D(leftVector, rightVector) {
|
|
12596
|
+
return leftVector.x * rightVector.x + leftVector.y * rightVector.y + leftVector.z * rightVector.z;
|
|
12597
|
+
}
|
|
12598
|
+
/**
|
|
12599
|
+
* Normalizes one 3D vector while keeping zero vectors stable.
|
|
12600
|
+
*
|
|
12601
|
+
* @param vector Source vector.
|
|
12602
|
+
* @returns Normalized vector.
|
|
12603
|
+
*
|
|
12604
|
+
* @private helper of the 3D avatar visuals
|
|
12605
|
+
*/
|
|
12606
|
+
function normalizeVector3(vector) {
|
|
12607
|
+
const length = Math.hypot(vector.x, vector.y, vector.z);
|
|
12608
|
+
if (length === 0) {
|
|
12609
|
+
return vector;
|
|
12610
|
+
}
|
|
12611
|
+
return {
|
|
12612
|
+
x: vector.x / length,
|
|
12613
|
+
y: vector.y / length,
|
|
12614
|
+
z: vector.z / length,
|
|
12615
|
+
};
|
|
12616
|
+
}
|
|
12617
|
+
/**
|
|
12618
|
+
* Measures the perimeter of one projected quad.
|
|
12619
|
+
*
|
|
12620
|
+
* @param corners Quad corners.
|
|
12621
|
+
* @returns Perimeter length.
|
|
12622
|
+
*
|
|
12623
|
+
* @private helper of the 3D avatar visuals
|
|
12624
|
+
*/
|
|
12625
|
+
function getProjectedQuadPerimeter(corners) {
|
|
12626
|
+
let perimeter = 0;
|
|
12627
|
+
for (let cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
|
|
12628
|
+
const currentCorner = corners[cornerIndex];
|
|
12629
|
+
const nextCorner = corners[(cornerIndex + 1) % corners.length];
|
|
12630
|
+
perimeter += Math.hypot(nextCorner.x - currentCorner.x, nextCorner.y - currentCorner.y);
|
|
12631
|
+
}
|
|
12632
|
+
return perimeter;
|
|
12633
|
+
}
|
|
12634
|
+
|
|
12455
12635
|
/* eslint-disable no-magic-numbers */
|
|
12456
12636
|
/**
|
|
12457
12637
|
* Builds the seeded six-face texture pack used by the Minecraft-style head cuboid.
|
|
@@ -12624,18 +12804,12 @@
|
|
|
12624
12804
|
}
|
|
12625
12805
|
|
|
12626
12806
|
/* eslint-disable no-magic-numbers */
|
|
12627
|
-
/**
|
|
12628
|
-
* Fixed scene camera distance used for the proper-3D projection.
|
|
12629
|
-
*
|
|
12630
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
12631
|
-
*/
|
|
12632
|
-
const CAMERA_DISTANCE_RATIO = 1.4;
|
|
12633
12807
|
/**
|
|
12634
12808
|
* Shared light direction used to shade projected cuboid faces.
|
|
12635
12809
|
*
|
|
12636
12810
|
* @private helper of `minecraft2AvatarVisual`
|
|
12637
12811
|
*/
|
|
12638
|
-
const LIGHT_DIRECTION = normalizeVector3({
|
|
12812
|
+
const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
12639
12813
|
x: 0.4,
|
|
12640
12814
|
y: -0.65,
|
|
12641
12815
|
z: 0.92,
|
|
@@ -12847,7 +13021,7 @@
|
|
|
12847
13021
|
corners: projectedCorners,
|
|
12848
13022
|
texture: faceDefinition.texture,
|
|
12849
13023
|
averageDepth: transformedCorners.reduce((depthSum, corner) => depthSum + corner.z, 0) / transformedCorners.length,
|
|
12850
|
-
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION), -1, 1),
|
|
13024
|
+
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$1), -1, 1),
|
|
12851
13025
|
outlineColor: cuboid.outlineColor,
|
|
12852
13026
|
};
|
|
12853
13027
|
});
|
|
@@ -12874,7 +13048,7 @@
|
|
|
12874
13048
|
const endX = (columnIndex + 1) / columns;
|
|
12875
13049
|
const startY = rowIndex / rows;
|
|
12876
13050
|
const endY = (rowIndex + 1) / rows;
|
|
12877
|
-
drawProjectedQuad(context, [
|
|
13051
|
+
drawProjectedQuad$1(context, [
|
|
12878
13052
|
interpolateProjectedQuad(face.corners, startX, startY),
|
|
12879
13053
|
interpolateProjectedQuad(face.corners, endX, startY),
|
|
12880
13054
|
interpolateProjectedQuad(face.corners, endX, endY),
|
|
@@ -12883,10 +13057,10 @@
|
|
|
12883
13057
|
}
|
|
12884
13058
|
}
|
|
12885
13059
|
if (face.lightIntensity > 0) {
|
|
12886
|
-
drawProjectedQuad(context, face.corners, `rgba(255, 255, 255, ${0.15 * face.lightIntensity})`);
|
|
13060
|
+
drawProjectedQuad$1(context, face.corners, `rgba(255, 255, 255, ${0.15 * face.lightIntensity})`);
|
|
12887
13061
|
}
|
|
12888
13062
|
else if (face.lightIntensity < 0) {
|
|
12889
|
-
drawProjectedQuad(context, face.corners, `rgba(0, 0, 0, ${0.22 * Math.abs(face.lightIntensity)})`);
|
|
13063
|
+
drawProjectedQuad$1(context, face.corners, `rgba(0, 0, 0, ${0.22 * Math.abs(face.lightIntensity)})`);
|
|
12890
13064
|
}
|
|
12891
13065
|
context.save();
|
|
12892
13066
|
context.beginPath();
|
|
@@ -12910,7 +13084,7 @@
|
|
|
12910
13084
|
*
|
|
12911
13085
|
* @private helper of `minecraft2AvatarVisual`
|
|
12912
13086
|
*/
|
|
12913
|
-
function drawProjectedQuad(context, corners, fillStyle) {
|
|
13087
|
+
function drawProjectedQuad$1(context, corners, fillStyle) {
|
|
12914
13088
|
context.beginPath();
|
|
12915
13089
|
context.moveTo(corners[0].x, corners[0].y);
|
|
12916
13090
|
context.lineTo(corners[1].x, corners[1].y);
|
|
@@ -12952,175 +13126,6 @@
|
|
|
12952
13126
|
z: startPoint.z + (endPoint.z - startPoint.z) * ratio,
|
|
12953
13127
|
};
|
|
12954
13128
|
}
|
|
12955
|
-
/**
|
|
12956
|
-
* Projects one rotated scene point into canvas coordinates.
|
|
12957
|
-
*
|
|
12958
|
-
* @param point Scene point.
|
|
12959
|
-
* @param size Canvas size in CSS pixels.
|
|
12960
|
-
* @param sceneCenterX Horizontal scene center.
|
|
12961
|
-
* @param sceneCenterY Vertical scene center.
|
|
12962
|
-
* @returns Projected point.
|
|
12963
|
-
*
|
|
12964
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
12965
|
-
*/
|
|
12966
|
-
function projectScenePoint(point, size, sceneCenterX, sceneCenterY) {
|
|
12967
|
-
const cameraDistance = size * CAMERA_DISTANCE_RATIO;
|
|
12968
|
-
const perspectiveScale = cameraDistance / Math.max(cameraDistance - point.z, cameraDistance * 0.35);
|
|
12969
|
-
return {
|
|
12970
|
-
x: sceneCenterX + point.x * perspectiveScale,
|
|
12971
|
-
y: sceneCenterY + point.y * perspectiveScale,
|
|
12972
|
-
z: point.z,
|
|
12973
|
-
};
|
|
12974
|
-
}
|
|
12975
|
-
/**
|
|
12976
|
-
* Applies the local cuboid rotations and translation to one scene point.
|
|
12977
|
-
*
|
|
12978
|
-
* @param localPoint Point in cuboid-local space.
|
|
12979
|
-
* @param center Cuboid center in scene space.
|
|
12980
|
-
* @param rotationX Cuboid pitch in radians.
|
|
12981
|
-
* @param rotationY Cuboid yaw in radians.
|
|
12982
|
-
* @returns Transformed scene-space point.
|
|
12983
|
-
*
|
|
12984
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
12985
|
-
*/
|
|
12986
|
-
function transformScenePoint(localPoint, center, rotationX, rotationY) {
|
|
12987
|
-
const yawedPoint = rotatePointAroundY(localPoint, rotationY);
|
|
12988
|
-
const pitchedPoint = rotatePointAroundX(yawedPoint, rotationX);
|
|
12989
|
-
return {
|
|
12990
|
-
x: center.x + pitchedPoint.x,
|
|
12991
|
-
y: center.y + pitchedPoint.y,
|
|
12992
|
-
z: center.z + pitchedPoint.z,
|
|
12993
|
-
};
|
|
12994
|
-
}
|
|
12995
|
-
/**
|
|
12996
|
-
* Rotates one point around the local Y axis.
|
|
12997
|
-
*
|
|
12998
|
-
* @param point Source point.
|
|
12999
|
-
* @param angle Rotation angle in radians.
|
|
13000
|
-
* @returns Rotated point.
|
|
13001
|
-
*
|
|
13002
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
13003
|
-
*/
|
|
13004
|
-
function rotatePointAroundY(point, angle) {
|
|
13005
|
-
const cosine = Math.cos(angle);
|
|
13006
|
-
const sine = Math.sin(angle);
|
|
13007
|
-
return {
|
|
13008
|
-
x: point.x * cosine + point.z * sine,
|
|
13009
|
-
y: point.y,
|
|
13010
|
-
z: -point.x * sine + point.z * cosine,
|
|
13011
|
-
};
|
|
13012
|
-
}
|
|
13013
|
-
/**
|
|
13014
|
-
* Rotates one point around the local X axis.
|
|
13015
|
-
*
|
|
13016
|
-
* @param point Source point.
|
|
13017
|
-
* @param angle Rotation angle in radians.
|
|
13018
|
-
* @returns Rotated point.
|
|
13019
|
-
*
|
|
13020
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
13021
|
-
*/
|
|
13022
|
-
function rotatePointAroundX(point, angle) {
|
|
13023
|
-
const cosine = Math.cos(angle);
|
|
13024
|
-
const sine = Math.sin(angle);
|
|
13025
|
-
return {
|
|
13026
|
-
x: point.x,
|
|
13027
|
-
y: point.y * cosine - point.z * sine,
|
|
13028
|
-
z: point.y * sine + point.z * cosine,
|
|
13029
|
-
};
|
|
13030
|
-
}
|
|
13031
|
-
/**
|
|
13032
|
-
* Subtracts one 3D point from another.
|
|
13033
|
-
*
|
|
13034
|
-
* @param leftPoint Left point.
|
|
13035
|
-
* @param rightPoint Right point.
|
|
13036
|
-
* @returns Difference vector.
|
|
13037
|
-
*
|
|
13038
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
13039
|
-
*/
|
|
13040
|
-
function subtractPoint3D(leftPoint, rightPoint) {
|
|
13041
|
-
return {
|
|
13042
|
-
x: leftPoint.x - rightPoint.x,
|
|
13043
|
-
y: leftPoint.y - rightPoint.y,
|
|
13044
|
-
z: leftPoint.z - rightPoint.z,
|
|
13045
|
-
};
|
|
13046
|
-
}
|
|
13047
|
-
/**
|
|
13048
|
-
* Computes the 3D cross product of two vectors.
|
|
13049
|
-
*
|
|
13050
|
-
* @param leftVector Left vector.
|
|
13051
|
-
* @param rightVector Right vector.
|
|
13052
|
-
* @returns Cross product.
|
|
13053
|
-
*
|
|
13054
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
13055
|
-
*/
|
|
13056
|
-
function crossProduct3D(leftVector, rightVector) {
|
|
13057
|
-
return {
|
|
13058
|
-
x: leftVector.y * rightVector.z - leftVector.z * rightVector.y,
|
|
13059
|
-
y: leftVector.z * rightVector.x - leftVector.x * rightVector.z,
|
|
13060
|
-
z: leftVector.x * rightVector.y - leftVector.y * rightVector.x,
|
|
13061
|
-
};
|
|
13062
|
-
}
|
|
13063
|
-
/**
|
|
13064
|
-
* Computes the 3D dot product of two vectors.
|
|
13065
|
-
*
|
|
13066
|
-
* @param leftVector Left vector.
|
|
13067
|
-
* @param rightVector Right vector.
|
|
13068
|
-
* @returns Dot product.
|
|
13069
|
-
*
|
|
13070
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
13071
|
-
*/
|
|
13072
|
-
function dotProduct3D(leftVector, rightVector) {
|
|
13073
|
-
return leftVector.x * rightVector.x + leftVector.y * rightVector.y + leftVector.z * rightVector.z;
|
|
13074
|
-
}
|
|
13075
|
-
/**
|
|
13076
|
-
* Normalizes one 3D vector while keeping zero vectors stable.
|
|
13077
|
-
*
|
|
13078
|
-
* @param vector Source vector.
|
|
13079
|
-
* @returns Normalized vector.
|
|
13080
|
-
*
|
|
13081
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
13082
|
-
*/
|
|
13083
|
-
function normalizeVector3(vector) {
|
|
13084
|
-
const length = Math.hypot(vector.x, vector.y, vector.z);
|
|
13085
|
-
if (length === 0) {
|
|
13086
|
-
return vector;
|
|
13087
|
-
}
|
|
13088
|
-
return {
|
|
13089
|
-
x: vector.x / length,
|
|
13090
|
-
y: vector.y / length,
|
|
13091
|
-
z: vector.z / length,
|
|
13092
|
-
};
|
|
13093
|
-
}
|
|
13094
|
-
/**
|
|
13095
|
-
* Clamps one number into the provided range.
|
|
13096
|
-
*
|
|
13097
|
-
* @param value Input value.
|
|
13098
|
-
* @param minimumValue Inclusive lower bound.
|
|
13099
|
-
* @param maximumValue Inclusive upper bound.
|
|
13100
|
-
* @returns Clamped value.
|
|
13101
|
-
*
|
|
13102
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
13103
|
-
*/
|
|
13104
|
-
function clampNumber$1(value, minimumValue, maximumValue) {
|
|
13105
|
-
return Math.min(maximumValue, Math.max(minimumValue, value));
|
|
13106
|
-
}
|
|
13107
|
-
/**
|
|
13108
|
-
* Measures the perimeter of one projected quad.
|
|
13109
|
-
*
|
|
13110
|
-
* @param corners Quad corners.
|
|
13111
|
-
* @returns Perimeter length.
|
|
13112
|
-
*
|
|
13113
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
13114
|
-
*/
|
|
13115
|
-
function getProjectedQuadPerimeter(corners) {
|
|
13116
|
-
let perimeter = 0;
|
|
13117
|
-
for (let cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
|
|
13118
|
-
const currentCorner = corners[cornerIndex];
|
|
13119
|
-
const nextCorner = corners[(cornerIndex + 1) % corners.length];
|
|
13120
|
-
perimeter += Math.hypot(nextCorner.x - currentCorner.x, nextCorner.y - currentCorner.y);
|
|
13121
|
-
}
|
|
13122
|
-
return perimeter;
|
|
13123
|
-
}
|
|
13124
13129
|
|
|
13125
13130
|
/* eslint-disable no-magic-numbers */
|
|
13126
13131
|
/**
|
|
@@ -13689,7 +13694,7 @@
|
|
|
13689
13694
|
*
|
|
13690
13695
|
* @private helper of `octopus3AvatarVisual`
|
|
13691
13696
|
*/
|
|
13692
|
-
function formatAlphaHex(opacity) {
|
|
13697
|
+
function formatAlphaHex$1(opacity) {
|
|
13693
13698
|
return Math.round(Math.min(1, Math.max(0, opacity)) * 255)
|
|
13694
13699
|
.toString(16)
|
|
13695
13700
|
.padStart(2, '0');
|
|
@@ -14068,7 +14073,7 @@
|
|
|
14068
14073
|
context.beginPath();
|
|
14069
14074
|
context.moveTo(-radiusX * 0.74, radiusY * 0.2);
|
|
14070
14075
|
context.quadraticCurveTo(0, radiusY * 0.38, radiusX * 0.74, radiusY * 0.2);
|
|
14071
|
-
context.strokeStyle = `${palette.highlight}${formatAlphaHex(eyeStyle.lowerLidOpacity)}`;
|
|
14076
|
+
context.strokeStyle = `${palette.highlight}${formatAlphaHex$1(eyeStyle.lowerLidOpacity)}`;
|
|
14072
14077
|
context.lineWidth = radiusX * 0.08;
|
|
14073
14078
|
context.lineCap = 'round';
|
|
14074
14079
|
context.stroke();
|
|
@@ -14076,6 +14081,518 @@
|
|
|
14076
14081
|
context.restore();
|
|
14077
14082
|
}
|
|
14078
14083
|
|
|
14084
|
+
/* eslint-disable no-magic-numbers */
|
|
14085
|
+
/**
|
|
14086
|
+
* Light direction used by the organic 3D octopus shading.
|
|
14087
|
+
*
|
|
14088
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14089
|
+
*/
|
|
14090
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
14091
|
+
x: 0.48,
|
|
14092
|
+
y: -0.62,
|
|
14093
|
+
z: 0.94,
|
|
14094
|
+
});
|
|
14095
|
+
/**
|
|
14096
|
+
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
14097
|
+
*
|
|
14098
|
+
* @private built-in avatar visual
|
|
14099
|
+
*/
|
|
14100
|
+
const octopus3dAvatarVisual = {
|
|
14101
|
+
id: 'octopus3d',
|
|
14102
|
+
title: 'Octopus 3D',
|
|
14103
|
+
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
14104
|
+
isAnimated: true,
|
|
14105
|
+
supportsPointerTracking: true,
|
|
14106
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
14107
|
+
const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
|
|
14108
|
+
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
14109
|
+
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
14110
|
+
const animationPhase = animationRandom() * Math.PI * 2;
|
|
14111
|
+
const sceneCenterX = size * 0.5;
|
|
14112
|
+
const sceneCenterY = size * 0.56;
|
|
14113
|
+
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
14114
|
+
const mantleCenter = {
|
|
14115
|
+
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
14116
|
+
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
14117
|
+
z: interaction.intensity * size * 0.012,
|
|
14118
|
+
};
|
|
14119
|
+
const underbodyCenter = {
|
|
14120
|
+
x: mantleCenter.x * 0.86,
|
|
14121
|
+
y: mantleCenter.y + size * 0.168,
|
|
14122
|
+
z: mantleCenter.z - size * 0.018,
|
|
14123
|
+
};
|
|
14124
|
+
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
14125
|
+
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
14126
|
+
const mantleRadiusZ = size * morphologyProfile.body.bodyRadiusRatio * (0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
14127
|
+
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
14128
|
+
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
14129
|
+
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
14130
|
+
const bodyYaw = -0.18 +
|
|
14131
|
+
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
14132
|
+
interaction.bodyOffsetX * 0.18 +
|
|
14133
|
+
interaction.gazeX * 0.22;
|
|
14134
|
+
const bodyPitch = -0.08 +
|
|
14135
|
+
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
14136
|
+
interaction.bodyOffsetY * 0.08 -
|
|
14137
|
+
interaction.gazeY * 0.08;
|
|
14138
|
+
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
14139
|
+
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
14140
|
+
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
14141
|
+
center: mantleCenter,
|
|
14142
|
+
radiusX: mantleRadiusX,
|
|
14143
|
+
radiusY: mantleRadiusY,
|
|
14144
|
+
radiusZ: mantleRadiusZ,
|
|
14145
|
+
rotationX: headPitch,
|
|
14146
|
+
rotationY: headYaw,
|
|
14147
|
+
sceneCenterX,
|
|
14148
|
+
sceneCenterY,
|
|
14149
|
+
size,
|
|
14150
|
+
palette,
|
|
14151
|
+
verticalColorBias: 0,
|
|
14152
|
+
outlineColor: `${palette.highlight}7a`,
|
|
14153
|
+
});
|
|
14154
|
+
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
14155
|
+
center: underbodyCenter,
|
|
14156
|
+
radiusX: underbodyRadiusX,
|
|
14157
|
+
radiusY: underbodyRadiusY,
|
|
14158
|
+
radiusZ: underbodyRadiusZ,
|
|
14159
|
+
rotationX: bodyPitch,
|
|
14160
|
+
rotationY: bodyYaw,
|
|
14161
|
+
sceneCenterX,
|
|
14162
|
+
sceneCenterY,
|
|
14163
|
+
size,
|
|
14164
|
+
palette,
|
|
14165
|
+
verticalColorBias: 0.18,
|
|
14166
|
+
outlineColor: `${palette.shadow}8f`,
|
|
14167
|
+
});
|
|
14168
|
+
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
14169
|
+
createRandom,
|
|
14170
|
+
morphologyProfile,
|
|
14171
|
+
timeMs,
|
|
14172
|
+
size,
|
|
14173
|
+
center: underbodyCenter,
|
|
14174
|
+
radiusX: underbodyRadiusX,
|
|
14175
|
+
radiusY: underbodyRadiusY,
|
|
14176
|
+
radiusZ: underbodyRadiusZ,
|
|
14177
|
+
rotationX: bodyPitch,
|
|
14178
|
+
rotationY: bodyYaw,
|
|
14179
|
+
sceneCenterX,
|
|
14180
|
+
sceneCenterY,
|
|
14181
|
+
animationPhase,
|
|
14182
|
+
});
|
|
14183
|
+
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
14184
|
+
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
14185
|
+
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
14186
|
+
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
14187
|
+
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
14188
|
+
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
14189
|
+
drawAvatarFrame(context, size, palette);
|
|
14190
|
+
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
14191
|
+
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
14192
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
14193
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
14194
|
+
}
|
|
14195
|
+
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
14196
|
+
drawSurfacePatch(context, surfacePatch);
|
|
14197
|
+
}
|
|
14198
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
14199
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
14200
|
+
}
|
|
14201
|
+
drawProjectedEye(context, {
|
|
14202
|
+
x: -faceEyeSpacing,
|
|
14203
|
+
y: faceEyeYOffset,
|
|
14204
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
14205
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
|
|
14206
|
+
drawProjectedEye(context, {
|
|
14207
|
+
x: faceEyeSpacing,
|
|
14208
|
+
y: faceEyeYOffset,
|
|
14209
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
14210
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
|
|
14211
|
+
drawProjectedMouth(context, [
|
|
14212
|
+
{ x: -mouthHalfWidth, y: mouthY, z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY) },
|
|
14213
|
+
{
|
|
14214
|
+
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
14215
|
+
y: mouthY +
|
|
14216
|
+
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
14217
|
+
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
14218
|
+
interaction.gazeY * size * 0.01,
|
|
14219
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
14220
|
+
},
|
|
14221
|
+
{ x: mouthHalfWidth, y: mouthY, z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY) },
|
|
14222
|
+
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
14223
|
+
},
|
|
14224
|
+
};
|
|
14225
|
+
/**
|
|
14226
|
+
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
14227
|
+
*
|
|
14228
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14229
|
+
*/
|
|
14230
|
+
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
14231
|
+
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);
|
|
14232
|
+
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
14233
|
+
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
14234
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
14235
|
+
context.fillStyle = glowGradient;
|
|
14236
|
+
context.fillRect(0, 0, size, size);
|
|
14237
|
+
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);
|
|
14238
|
+
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
14239
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
14240
|
+
context.fillStyle = lowerGradient;
|
|
14241
|
+
context.fillRect(0, 0, size, size);
|
|
14242
|
+
}
|
|
14243
|
+
/**
|
|
14244
|
+
* Draws the soft ground shadow below the octopus.
|
|
14245
|
+
*
|
|
14246
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14247
|
+
*/
|
|
14248
|
+
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
14249
|
+
context.save();
|
|
14250
|
+
context.fillStyle = `${palette.shadow}66`;
|
|
14251
|
+
context.filter = `blur(${size * 0.022}px)`;
|
|
14252
|
+
context.beginPath();
|
|
14253
|
+
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);
|
|
14254
|
+
context.fill();
|
|
14255
|
+
context.restore();
|
|
14256
|
+
}
|
|
14257
|
+
/**
|
|
14258
|
+
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
14259
|
+
*
|
|
14260
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14261
|
+
*/
|
|
14262
|
+
function resolveVisibleEllipsoidPatches(options) {
|
|
14263
|
+
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
14264
|
+
const latitudePatchCount = 10;
|
|
14265
|
+
const longitudePatchCount = 18;
|
|
14266
|
+
const surfacePatches = [];
|
|
14267
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
14268
|
+
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
14269
|
+
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
14270
|
+
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
14271
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
14272
|
+
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
14273
|
+
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
14274
|
+
const localCorners = [
|
|
14275
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
14276
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
14277
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
14278
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
14279
|
+
];
|
|
14280
|
+
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
14281
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
14282
|
+
if (surfaceNormal.z <= 0.01) {
|
|
14283
|
+
continue;
|
|
14284
|
+
}
|
|
14285
|
+
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
14286
|
+
surfacePatches.push({
|
|
14287
|
+
corners: projectedCorners,
|
|
14288
|
+
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
14289
|
+
transformedCorners.length,
|
|
14290
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
14291
|
+
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
14292
|
+
outlineColor,
|
|
14293
|
+
});
|
|
14294
|
+
}
|
|
14295
|
+
}
|
|
14296
|
+
return surfacePatches;
|
|
14297
|
+
}
|
|
14298
|
+
/**
|
|
14299
|
+
* Samples one point on an ellipsoid aligned to the local axes.
|
|
14300
|
+
*
|
|
14301
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14302
|
+
*/
|
|
14303
|
+
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
14304
|
+
const cosineLatitude = Math.cos(latitude);
|
|
14305
|
+
return {
|
|
14306
|
+
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
14307
|
+
y: Math.sin(latitude) * radiusY,
|
|
14308
|
+
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
14309
|
+
};
|
|
14310
|
+
}
|
|
14311
|
+
/**
|
|
14312
|
+
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
14313
|
+
*
|
|
14314
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14315
|
+
*/
|
|
14316
|
+
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
14317
|
+
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
14318
|
+
if (clampedVerticalProgress < 0.2) {
|
|
14319
|
+
return palette.highlight;
|
|
14320
|
+
}
|
|
14321
|
+
if (clampedVerticalProgress < 0.45) {
|
|
14322
|
+
return palette.secondary;
|
|
14323
|
+
}
|
|
14324
|
+
if (clampedVerticalProgress < 0.8) {
|
|
14325
|
+
return palette.primary;
|
|
14326
|
+
}
|
|
14327
|
+
return `${palette.shadow}f2`;
|
|
14328
|
+
}
|
|
14329
|
+
/**
|
|
14330
|
+
* Draws one projected mesh patch with organic shading.
|
|
14331
|
+
*
|
|
14332
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14333
|
+
*/
|
|
14334
|
+
function drawSurfacePatch(context, surfacePatch) {
|
|
14335
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
14336
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
14337
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
14338
|
+
}
|
|
14339
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
14340
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
14341
|
+
}
|
|
14342
|
+
context.save();
|
|
14343
|
+
context.beginPath();
|
|
14344
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
14345
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
14346
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
14347
|
+
}
|
|
14348
|
+
context.closePath();
|
|
14349
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
14350
|
+
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
14351
|
+
context.lineJoin = 'round';
|
|
14352
|
+
context.stroke();
|
|
14353
|
+
context.restore();
|
|
14354
|
+
}
|
|
14355
|
+
/**
|
|
14356
|
+
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
14357
|
+
*
|
|
14358
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14359
|
+
*/
|
|
14360
|
+
function createOctopusTentacleStrokes(options) {
|
|
14361
|
+
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
14362
|
+
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
14363
|
+
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
14364
|
+
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
14365
|
+
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
14366
|
+
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
14367
|
+
const lateralReach = size *
|
|
14368
|
+
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
14369
|
+
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
14370
|
+
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
14371
|
+
const anchorPoint = {
|
|
14372
|
+
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
14373
|
+
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
14374
|
+
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
14375
|
+
};
|
|
14376
|
+
const controlPointOne = {
|
|
14377
|
+
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
14378
|
+
y: anchorPoint.y + flowLength * 0.26,
|
|
14379
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
14380
|
+
};
|
|
14381
|
+
const controlPointTwo = {
|
|
14382
|
+
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
14383
|
+
y: anchorPoint.y + flowLength * 0.66,
|
|
14384
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
14385
|
+
};
|
|
14386
|
+
const endPoint = {
|
|
14387
|
+
x: anchorPoint.x +
|
|
14388
|
+
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
14389
|
+
sway * size * 0.028,
|
|
14390
|
+
y: anchorPoint.y + flowLength,
|
|
14391
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
14392
|
+
};
|
|
14393
|
+
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
14394
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
14395
|
+
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
14396
|
+
return {
|
|
14397
|
+
projectedPoints,
|
|
14398
|
+
averageDepth,
|
|
14399
|
+
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
14400
|
+
baseWidth: size *
|
|
14401
|
+
(0.019 +
|
|
14402
|
+
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
14403
|
+
tentacleRandom() * 0.003 +
|
|
14404
|
+
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
14405
|
+
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
14406
|
+
colorBias: tentacleRandom(),
|
|
14407
|
+
};
|
|
14408
|
+
});
|
|
14409
|
+
}
|
|
14410
|
+
/**
|
|
14411
|
+
* Samples one point on a cubic Bezier curve in 3D.
|
|
14412
|
+
*
|
|
14413
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14414
|
+
*/
|
|
14415
|
+
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
14416
|
+
const inverseProgress = 1 - progress;
|
|
14417
|
+
return {
|
|
14418
|
+
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
14419
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
14420
|
+
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
14421
|
+
progress * progress * progress * endPoint.x,
|
|
14422
|
+
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
14423
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
14424
|
+
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
14425
|
+
progress * progress * progress * endPoint.y,
|
|
14426
|
+
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
14427
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
14428
|
+
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
14429
|
+
progress * progress * progress * endPoint.z,
|
|
14430
|
+
};
|
|
14431
|
+
}
|
|
14432
|
+
/**
|
|
14433
|
+
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
14434
|
+
*
|
|
14435
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14436
|
+
*/
|
|
14437
|
+
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
14438
|
+
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
14439
|
+
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
14440
|
+
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
14441
|
+
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
14442
|
+
const progress = segmentIndex / projectedSegments;
|
|
14443
|
+
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
14444
|
+
context.beginPath();
|
|
14445
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
14446
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
14447
|
+
context.strokeStyle =
|
|
14448
|
+
tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
14449
|
+
context.lineWidth = width;
|
|
14450
|
+
context.lineCap = 'round';
|
|
14451
|
+
context.stroke();
|
|
14452
|
+
context.beginPath();
|
|
14453
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
14454
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
14455
|
+
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
14456
|
+
context.lineWidth = Math.max(1, width * 0.34);
|
|
14457
|
+
context.lineCap = 'round';
|
|
14458
|
+
context.stroke();
|
|
14459
|
+
}
|
|
14460
|
+
}
|
|
14461
|
+
/**
|
|
14462
|
+
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
14463
|
+
*
|
|
14464
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14465
|
+
*/
|
|
14466
|
+
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
14467
|
+
const normalizedX = x / radiusX;
|
|
14468
|
+
const normalizedY = y / radiusY;
|
|
14469
|
+
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
14470
|
+
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
14471
|
+
}
|
|
14472
|
+
/**
|
|
14473
|
+
* Draws one projected eye on the turned octopus mantle.
|
|
14474
|
+
*
|
|
14475
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14476
|
+
*/
|
|
14477
|
+
function drawProjectedEye(context, localCenter, radiusX, radiusY, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, phase, interaction, eyeStyle) {
|
|
14478
|
+
const centerScenePoint = transformScenePoint(localCenter, center, rotationX, rotationY);
|
|
14479
|
+
if (centerScenePoint.z <= center.z) {
|
|
14480
|
+
return;
|
|
14481
|
+
}
|
|
14482
|
+
const horizontalScenePoint = transformScenePoint({ x: localCenter.x + radiusX, y: localCenter.y, z: localCenter.z }, center, rotationX, rotationY);
|
|
14483
|
+
const verticalScenePoint = transformScenePoint({ x: localCenter.x, y: localCenter.y + radiusY, z: localCenter.z }, center, rotationX, rotationY);
|
|
14484
|
+
const projectedCenterPoint = projectScenePoint(centerScenePoint, size, sceneCenterX, sceneCenterY);
|
|
14485
|
+
const projectedHorizontalPoint = projectScenePoint(horizontalScenePoint, size, sceneCenterX, sceneCenterY);
|
|
14486
|
+
const projectedVerticalPoint = projectScenePoint(verticalScenePoint, size, sceneCenterX, sceneCenterY);
|
|
14487
|
+
const projectedRadiusX = Math.hypot(projectedHorizontalPoint.x - projectedCenterPoint.x, projectedHorizontalPoint.y - projectedCenterPoint.y);
|
|
14488
|
+
const projectedRadiusY = Math.hypot(projectedVerticalPoint.x - projectedCenterPoint.x, projectedVerticalPoint.y - projectedCenterPoint.y);
|
|
14489
|
+
if (projectedRadiusX < size * 0.008 || projectedRadiusY < size * 0.008) {
|
|
14490
|
+
return;
|
|
14491
|
+
}
|
|
14492
|
+
const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
|
|
14493
|
+
radiusX: projectedRadiusX,
|
|
14494
|
+
radiusY: projectedRadiusY,
|
|
14495
|
+
timeMs,
|
|
14496
|
+
phase,
|
|
14497
|
+
interaction,
|
|
14498
|
+
});
|
|
14499
|
+
const rotation = Math.atan2(projectedHorizontalPoint.y - projectedCenterPoint.y, projectedHorizontalPoint.x - projectedCenterPoint.x);
|
|
14500
|
+
context.save();
|
|
14501
|
+
context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
|
|
14502
|
+
context.rotate(rotation);
|
|
14503
|
+
context.beginPath();
|
|
14504
|
+
context.ellipse(0, 0, projectedRadiusX, projectedRadiusY, 0, 0, Math.PI * 2);
|
|
14505
|
+
context.fillStyle = '#f8fbff';
|
|
14506
|
+
context.fill();
|
|
14507
|
+
context.clip();
|
|
14508
|
+
const irisGradient = context.createRadialGradient(-projectedRadiusX * 0.2, -projectedRadiusY * 0.26, projectedRadiusX * 0.05, 0, 0, projectedRadiusX * 0.92);
|
|
14509
|
+
irisGradient.addColorStop(0, palette.highlight);
|
|
14510
|
+
irisGradient.addColorStop(0.56, palette.secondary);
|
|
14511
|
+
irisGradient.addColorStop(1, palette.shadow);
|
|
14512
|
+
context.beginPath();
|
|
14513
|
+
context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.62 * eyeStyle.irisScale, projectedRadiusY * 0.72 * eyeStyle.irisScale, 0, 0, Math.PI * 2);
|
|
14514
|
+
context.fillStyle = irisGradient;
|
|
14515
|
+
context.fill();
|
|
14516
|
+
context.beginPath();
|
|
14517
|
+
context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.15 * eyeStyle.pupilWidthScale, projectedRadiusY * 0.48 * eyeStyle.pupilHeightScale, 0, 0, Math.PI * 2);
|
|
14518
|
+
context.fillStyle = palette.ink;
|
|
14519
|
+
context.fill();
|
|
14520
|
+
context.beginPath();
|
|
14521
|
+
context.ellipse(pupilOffsetX - projectedRadiusX * 0.22, pupilOffsetY - projectedRadiusY * 0.24, projectedRadiusX * 0.12, projectedRadiusY * 0.14, 0, 0, Math.PI * 2);
|
|
14522
|
+
context.fillStyle = '#ffffff';
|
|
14523
|
+
context.fill();
|
|
14524
|
+
context.restore();
|
|
14525
|
+
context.save();
|
|
14526
|
+
context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
|
|
14527
|
+
context.rotate(rotation);
|
|
14528
|
+
context.beginPath();
|
|
14529
|
+
context.ellipse(0, 0, projectedRadiusX, projectedRadiusY, 0, 0, Math.PI * 2);
|
|
14530
|
+
context.strokeStyle = `${palette.shadow}cc`;
|
|
14531
|
+
context.lineWidth = projectedRadiusX * 0.16;
|
|
14532
|
+
context.stroke();
|
|
14533
|
+
context.beginPath();
|
|
14534
|
+
context.moveTo(-projectedRadiusX * 0.88, -projectedRadiusY * eyeStyle.upperLidInsetRatio);
|
|
14535
|
+
context.quadraticCurveTo(0, -projectedRadiusY * (eyeStyle.upperLidArchRatio - interaction.gazeY * 0.16 + interaction.intensity * 0.08), projectedRadiusX * 0.88, -projectedRadiusY * eyeStyle.upperLidInsetRatio);
|
|
14536
|
+
context.strokeStyle = `${palette.shadow}73`;
|
|
14537
|
+
context.lineWidth = projectedRadiusX * 0.14;
|
|
14538
|
+
context.lineCap = 'round';
|
|
14539
|
+
context.stroke();
|
|
14540
|
+
if (eyeStyle.lowerLidOpacity > 0) {
|
|
14541
|
+
context.beginPath();
|
|
14542
|
+
context.moveTo(-projectedRadiusX * 0.74, projectedRadiusY * 0.2);
|
|
14543
|
+
context.quadraticCurveTo(0, projectedRadiusY * 0.38, projectedRadiusX * 0.74, projectedRadiusY * 0.2);
|
|
14544
|
+
context.strokeStyle = `${palette.highlight}${formatAlphaHex(eyeStyle.lowerLidOpacity)}`;
|
|
14545
|
+
context.lineWidth = projectedRadiusX * 0.08;
|
|
14546
|
+
context.lineCap = 'round';
|
|
14547
|
+
context.stroke();
|
|
14548
|
+
}
|
|
14549
|
+
context.restore();
|
|
14550
|
+
}
|
|
14551
|
+
/**
|
|
14552
|
+
* Draws a subtle projected mouth arc across the front of the mantle.
|
|
14553
|
+
*
|
|
14554
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14555
|
+
*/
|
|
14556
|
+
function drawProjectedMouth(context, localPoints, center, rotationX, rotationY, sceneCenterX, sceneCenterY, palette, size) {
|
|
14557
|
+
const scenePoints = localPoints.map((localPoint) => transformScenePoint(localPoint, center, rotationX, rotationY));
|
|
14558
|
+
if (scenePoints.some((scenePoint) => scenePoint.z <= center.z)) {
|
|
14559
|
+
return;
|
|
14560
|
+
}
|
|
14561
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
14562
|
+
context.beginPath();
|
|
14563
|
+
context.moveTo(projectedPoints[0].x, projectedPoints[0].y);
|
|
14564
|
+
context.quadraticCurveTo(projectedPoints[1].x, projectedPoints[1].y, projectedPoints[2].x, projectedPoints[2].y);
|
|
14565
|
+
context.strokeStyle = `${palette.ink}b8`;
|
|
14566
|
+
context.lineWidth = Math.max(1.1, size * 0.009);
|
|
14567
|
+
context.lineCap = 'round';
|
|
14568
|
+
context.stroke();
|
|
14569
|
+
}
|
|
14570
|
+
/**
|
|
14571
|
+
* Draws one filled projected quad.
|
|
14572
|
+
*
|
|
14573
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14574
|
+
*/
|
|
14575
|
+
function drawProjectedQuad(context, corners, fillStyle) {
|
|
14576
|
+
context.beginPath();
|
|
14577
|
+
context.moveTo(corners[0].x, corners[0].y);
|
|
14578
|
+
context.lineTo(corners[1].x, corners[1].y);
|
|
14579
|
+
context.lineTo(corners[2].x, corners[2].y);
|
|
14580
|
+
context.lineTo(corners[3].x, corners[3].y);
|
|
14581
|
+
context.closePath();
|
|
14582
|
+
context.fillStyle = fillStyle;
|
|
14583
|
+
context.fill();
|
|
14584
|
+
}
|
|
14585
|
+
/**
|
|
14586
|
+
* Converts an opacity ratio into a two-digit hexadecimal alpha suffix.
|
|
14587
|
+
*
|
|
14588
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
14589
|
+
*/
|
|
14590
|
+
function formatAlphaHex(opacity) {
|
|
14591
|
+
return Math.round(clampNumber$1(opacity, 0, 1) * 255)
|
|
14592
|
+
.toString(16)
|
|
14593
|
+
.padStart(2, '0');
|
|
14594
|
+
}
|
|
14595
|
+
|
|
14079
14596
|
/* eslint-disable no-magic-numbers */
|
|
14080
14597
|
/**
|
|
14081
14598
|
* Octopus avatar visual.
|
|
@@ -14844,6 +15361,7 @@
|
|
|
14844
15361
|
octopusAvatarVisual,
|
|
14845
15362
|
octopus2AvatarVisual,
|
|
14846
15363
|
octopus3AvatarVisual,
|
|
15364
|
+
octopus3dAvatarVisual,
|
|
14847
15365
|
asciiOctopusAvatarVisual,
|
|
14848
15366
|
minecraftAvatarVisual,
|
|
14849
15367
|
minecraft2AvatarVisual,
|
|
@@ -17037,16 +17555,22 @@
|
|
|
17037
17555
|
* Each teammate is listed with its tool name, TEAM instructions, and optional profile hints.
|
|
17038
17556
|
*/
|
|
17039
17557
|
function buildTeamSystemMessageBody(teamEntries) {
|
|
17040
|
-
const
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17558
|
+
const teammateSections = teamEntries.map((entry, index) => {
|
|
17559
|
+
const toolLine = `${index + 1}) ${entry.teammate.label} tool \`${entry.toolName}\``;
|
|
17560
|
+
const detailLines = collectTeamEntryDetails(entry).map(formatTeamEntryDetailLine);
|
|
17561
|
+
if (detailLines.length === 0) {
|
|
17562
|
+
return toolLine;
|
|
17563
|
+
}
|
|
17564
|
+
return spacetrim.spaceTrim((block) => `
|
|
17565
|
+
${toolLine}
|
|
17566
|
+
${block(detailLines.join('\n'))}
|
|
17567
|
+
`);
|
|
17568
|
+
});
|
|
17569
|
+
return spacetrim.spaceTrim((block) => `
|
|
17570
|
+
${block(TEAM_SYSTEM_MESSAGE_GUIDANCE_LINES.join('\n'))}
|
|
17571
|
+
|
|
17572
|
+
${block(teammateSections.join('\n\n'))}
|
|
17573
|
+
`);
|
|
17050
17574
|
}
|
|
17051
17575
|
/**
|
|
17052
17576
|
* Builds the model-visible description for one teammate tool.
|
|
@@ -24554,7 +25078,11 @@
|
|
|
24554
25078
|
if (examples.length === 0) {
|
|
24555
25079
|
return null;
|
|
24556
25080
|
}
|
|
24557
|
-
return
|
|
25081
|
+
return spacetrim.spaceTrim((block) => `
|
|
25082
|
+
## Sample of communication with the agent:
|
|
25083
|
+
|
|
25084
|
+
${block(examples.join('\n\n'))}
|
|
25085
|
+
`);
|
|
24558
25086
|
}
|
|
24559
25087
|
/**
|
|
24560
25088
|
* Collects the individual lines used in the example interaction section.
|
|
@@ -24591,7 +25119,11 @@
|
|
|
24591
25119
|
function appendSystemMessageSection(requirements, section) {
|
|
24592
25120
|
return {
|
|
24593
25121
|
...requirements,
|
|
24594
|
-
systemMessage:
|
|
25122
|
+
systemMessage: spacetrim.spaceTrim((block) => `
|
|
25123
|
+
${block(requirements.systemMessage)}
|
|
25124
|
+
|
|
25125
|
+
${block(section)}
|
|
25126
|
+
`),
|
|
24595
25127
|
};
|
|
24596
25128
|
}
|
|
24597
25129
|
/**
|
|
@@ -26813,8 +27345,7 @@
|
|
|
26813
27345
|
});
|
|
26814
27346
|
}
|
|
26815
27347
|
}
|
|
26816
|
-
lineIndex =
|
|
26817
|
-
nextBlockLineIndex === -1 ? -1 : findNextNonEmptyLineIndex(lines, nextBlockLineIndex);
|
|
27348
|
+
lineIndex = nextBlockLineIndex === -1 ? -1 : findNextNonEmptyLineIndex(lines, nextBlockLineIndex);
|
|
26818
27349
|
}
|
|
26819
27350
|
return new Book(agentName, commitments, messageBlocks);
|
|
26820
27351
|
}
|
|
@@ -26841,18 +27372,12 @@
|
|
|
26841
27372
|
sections.push(this.agentName.trim());
|
|
26842
27373
|
}
|
|
26843
27374
|
for (const commitment of this.commitments) {
|
|
26844
|
-
sections.push([
|
|
26845
|
-
[commitment.type, commitment.subject].filter(Boolean).join(' ').trim(),
|
|
26846
|
-
commitment.content.trim(),
|
|
26847
|
-
]
|
|
27375
|
+
sections.push([[commitment.type, commitment.subject].filter(Boolean).join(' ').trim(), commitment.content.trim()]
|
|
26848
27376
|
.filter(Boolean)
|
|
26849
27377
|
.join('\n'));
|
|
26850
27378
|
}
|
|
26851
27379
|
for (const messageBlock of this.messageBlocks) {
|
|
26852
|
-
sections.push([
|
|
26853
|
-
`${messageBlock.marker} @${messageBlock.sender}`,
|
|
26854
|
-
messageBlock.content.trim(),
|
|
26855
|
-
]
|
|
27380
|
+
sections.push([`${messageBlock.marker} @${messageBlock.sender}`, messageBlock.content.trim()]
|
|
26856
27381
|
.filter(Boolean)
|
|
26857
27382
|
.join('\n'));
|
|
26858
27383
|
}
|
|
@@ -31786,50 +32311,55 @@
|
|
|
31786
32311
|
? ''
|
|
31787
32312
|
: ` *(Some cost is unknown)*`) +
|
|
31788
32313
|
(taxRate !== 0 ? ` *(with tax ${taxRate * 100}%)*` : ''));
|
|
31789
|
-
executionReportString
|
|
31790
|
-
|
|
31791
|
-
|
|
31792
|
-
|
|
31793
|
-
|
|
31794
|
-
|
|
31795
|
-
|
|
31796
|
-
|
|
31797
|
-
|
|
31798
|
-
|
|
31799
|
-
|
|
31800
|
-
|
|
31801
|
-
|
|
31802
|
-
|
|
31803
|
-
|
|
31804
|
-
|
|
31805
|
-
|
|
31806
|
-
|
|
31807
|
-
|
|
31808
|
-
|
|
31809
|
-
|
|
31810
|
-
|
|
31811
|
-
|
|
31812
|
-
|
|
31813
|
-
|
|
31814
|
-
|
|
31815
|
-
|
|
31816
|
-
|
|
31817
|
-
|
|
31818
|
-
|
|
31819
|
-
|
|
31820
|
-
|
|
31821
|
-
|
|
31822
|
-
|
|
31823
|
-
|
|
31824
|
-
|
|
31825
|
-
|
|
31826
|
-
|
|
32314
|
+
executionReportString = spacetrim.spaceTrim((block) => `
|
|
32315
|
+
${block(executionReportString)}
|
|
32316
|
+
|
|
32317
|
+
${block(headerList.map((header) => `- ${header}`).join('\n'))}
|
|
32318
|
+
|
|
32319
|
+
## 🗃 Index
|
|
32320
|
+
|
|
32321
|
+
${block(executionReportJson.promptExecutions
|
|
32322
|
+
.map((promptExecution) => {
|
|
32323
|
+
// TODO: [💩] Make some better system to convert headings to links
|
|
32324
|
+
let hash = normalizeToKebabCase(promptExecution.prompt.title);
|
|
32325
|
+
if (/^\s*\p{Extended_Pictographic}/u.test(promptExecution.prompt.title)) {
|
|
32326
|
+
hash = '-' + hash;
|
|
32327
|
+
}
|
|
32328
|
+
// TODO: Make working hash link for the task in md + pdf
|
|
32329
|
+
return `- [${promptExecution.prompt.title}](#${hash})`;
|
|
32330
|
+
})
|
|
32331
|
+
.join('\n'))}
|
|
32332
|
+
|
|
32333
|
+
## ⌚ Time chart
|
|
32334
|
+
|
|
32335
|
+
${block(createMarkdownChart({
|
|
32336
|
+
nameHeader: 'Task',
|
|
32337
|
+
valueHeader: 'Timeline',
|
|
32338
|
+
items: timingItems,
|
|
32339
|
+
width: chartsWidth,
|
|
32340
|
+
unitName: 'seconds',
|
|
32341
|
+
}))}
|
|
32342
|
+
|
|
32343
|
+
## 💸 Cost chart
|
|
32344
|
+
|
|
32345
|
+
${block(createMarkdownChart({
|
|
32346
|
+
nameHeader: 'Task',
|
|
32347
|
+
valueHeader: 'Cost',
|
|
32348
|
+
items: costItems,
|
|
32349
|
+
width: chartsWidth,
|
|
32350
|
+
unitName: 'USD',
|
|
32351
|
+
}))}
|
|
32352
|
+
`);
|
|
31827
32353
|
}
|
|
31828
32354
|
else {
|
|
31829
32355
|
headerList.push(`TOTAL COST $0 *(Nothing executed)*`);
|
|
31830
32356
|
}
|
|
31831
32357
|
for (const promptExecution of executionReportJson.promptExecutions) {
|
|
31832
|
-
executionReportString
|
|
32358
|
+
executionReportString = spacetrim.spaceTrim((block) => `
|
|
32359
|
+
${block(executionReportString)}
|
|
32360
|
+
|
|
32361
|
+
## ${promptExecution.prompt.title}
|
|
32362
|
+
`);
|
|
31833
32363
|
const taskList = [];
|
|
31834
32364
|
// TODO: What if startedAt OR/AND completedAt is not defined?
|
|
31835
32365
|
const startedAt = moment__default["default"]((_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.timing) === null || _b === void 0 ? void 0 : _b.start);
|
|
@@ -31845,7 +32375,11 @@
|
|
|
31845
32375
|
else {
|
|
31846
32376
|
taskList.push(`COST UNKNOWN`);
|
|
31847
32377
|
}
|
|
31848
|
-
executionReportString
|
|
32378
|
+
executionReportString = spacetrim.spaceTrim((block) => `
|
|
32379
|
+
${block(executionReportString)}
|
|
32380
|
+
|
|
32381
|
+
${block(taskList.map((header) => `- ${header}`).join('\n'))}
|
|
32382
|
+
`);
|
|
31849
32383
|
/*
|
|
31850
32384
|
- MODEL VARIANT ${promptExecution.prompt.modelRequirements.modelVariant}
|
|
31851
32385
|
- MODEL NAME \`${promptExecution.result?.model}\` (requested \`${
|
|
@@ -31853,49 +32387,60 @@
|
|
|
31853
32387
|
|
|
31854
32388
|
*/
|
|
31855
32389
|
if (just(true)) {
|
|
31856
|
-
executionReportString
|
|
31857
|
-
|
|
31858
|
-
|
|
31859
|
-
|
|
31860
|
-
return `
|
|
32390
|
+
executionReportString = spacetrim.spaceTrim((block) => {
|
|
32391
|
+
var _a;
|
|
32392
|
+
return `
|
|
32393
|
+
${block(executionReportString)}
|
|
31861
32394
|
|
|
31862
|
-
|
|
32395
|
+
### Prompt
|
|
31863
32396
|
|
|
31864
|
-
|
|
31865
|
-
|
|
31866
|
-
|
|
31867
|
-
|
|
31868
|
-
|
|
31869
|
-
});
|
|
32397
|
+
\`\`\`
|
|
32398
|
+
${block(escapeMarkdownBlock(((_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.rawPromptContent) || promptExecution.prompt.content))}
|
|
32399
|
+
\`\`\`
|
|
32400
|
+
`;
|
|
32401
|
+
});
|
|
31870
32402
|
}
|
|
31871
32403
|
if (promptExecution.result && promptExecution.result.content) {
|
|
31872
|
-
|
|
32404
|
+
const resultContent = promptExecution.result.content;
|
|
32405
|
+
executionReportString = spacetrim.spaceTrim((block) => `
|
|
32406
|
+
${block(executionReportString)}
|
|
32407
|
+
|
|
32408
|
+
### Result
|
|
32409
|
+
`);
|
|
31873
32410
|
if (promptExecution.result === undefined) {
|
|
31874
|
-
executionReportString
|
|
32411
|
+
executionReportString = spacetrim.spaceTrim((block) => `
|
|
32412
|
+
${block(executionReportString)}
|
|
32413
|
+
|
|
32414
|
+
*No result*
|
|
32415
|
+
`);
|
|
31875
32416
|
}
|
|
31876
|
-
else if (typeof
|
|
31877
|
-
executionReportString
|
|
31878
|
-
|
|
31879
|
-
|
|
31880
|
-
|
|
31881
|
-
|
|
32417
|
+
else if (typeof resultContent === 'string') {
|
|
32418
|
+
executionReportString = spacetrim.spaceTrim((block) => `
|
|
32419
|
+
${block(executionReportString)}
|
|
32420
|
+
|
|
32421
|
+
\`\`\`
|
|
32422
|
+
${block(escapeMarkdownBlock(resultContent))}
|
|
32423
|
+
\`\`\`
|
|
32424
|
+
`);
|
|
31882
32425
|
}
|
|
31883
32426
|
else {
|
|
31884
|
-
executionReportString
|
|
32427
|
+
executionReportString = spacetrim.spaceTrim((block) => `
|
|
32428
|
+
${block(executionReportString)}
|
|
32429
|
+
|
|
32430
|
+
${block(embeddingVectorToString(resultContent))}
|
|
32431
|
+
`);
|
|
31885
32432
|
}
|
|
31886
32433
|
}
|
|
31887
32434
|
if (promptExecution.error && promptExecution.error.message) {
|
|
31888
|
-
executionReportString
|
|
31889
|
-
|
|
31890
|
-
spacetrim.spaceTrim((block) => `
|
|
32435
|
+
executionReportString = spacetrim.spaceTrim((block) => `
|
|
32436
|
+
${block(executionReportString)}
|
|
31891
32437
|
|
|
31892
|
-
|
|
32438
|
+
### Error
|
|
31893
32439
|
|
|
31894
|
-
|
|
31895
|
-
|
|
31896
|
-
|
|
31897
|
-
|
|
31898
|
-
`);
|
|
32440
|
+
\`\`\`
|
|
32441
|
+
${block(escapeMarkdownBlock(promptExecution.error.message))}
|
|
32442
|
+
\`\`\`
|
|
32443
|
+
`);
|
|
31899
32444
|
}
|
|
31900
32445
|
}
|
|
31901
32446
|
executionReportString = prettifyMarkdown(executionReportString);
|
|
@@ -45883,7 +46428,7 @@
|
|
|
45883
46428
|
lines = lines.map((line) => `${line}<br/>`);
|
|
45884
46429
|
return lines.join('\n');
|
|
45885
46430
|
},
|
|
45886
|
-
} /* <- Note: [🤛]
|
|
46431
|
+
}; /* <- Note: [🤛] */
|
|
45887
46432
|
|
|
45888
46433
|
/**
|
|
45889
46434
|
* Transpiler to JavaScript code using the OpenAI Agents SDK.
|