@promptbook/wizard 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.
- package/esm/index.es.js +757 -225
- 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 +2 -2
- package/umd/index.umd.js +757 -225
- 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
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
* @generated
|
|
50
50
|
* @see https://github.com/webgptorg/promptbook
|
|
51
51
|
*/
|
|
52
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
52
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-70';
|
|
53
53
|
/**
|
|
54
54
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
55
55
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -5308,7 +5308,7 @@
|
|
|
5308
5308
|
}, {
|
|
5309
5309
|
packageName: '@promptbook/deepseek',
|
|
5310
5310
|
className: 'DeepseekExecutionTools',
|
|
5311
|
-
}) /* <- Note: [🤛]
|
|
5311
|
+
}); /* <- Note: [🤛] */
|
|
5312
5312
|
// TODO: [🎶] Naming "constructor" vs "creator" vs "factory"
|
|
5313
5313
|
|
|
5314
5314
|
/**
|
|
@@ -5775,7 +5775,7 @@
|
|
|
5775
5775
|
}, {
|
|
5776
5776
|
packageName: '@promptbook/google',
|
|
5777
5777
|
className: 'GoogleExecutionTools',
|
|
5778
|
-
}) /* <- Note: [🤛]
|
|
5778
|
+
}); /* <- Note: [🤛] */
|
|
5779
5779
|
// TODO: !!!!! Rename to `createGoogleLlmExecutionTools`, `...GoogleLlmExecutionTools`
|
|
5780
5780
|
// TODO: [🎶] Naming "constructor" vs "creator" vs "factory"
|
|
5781
5781
|
|
|
@@ -10291,7 +10291,7 @@
|
|
|
10291
10291
|
}, {
|
|
10292
10292
|
packageName: '@promptbook/openai',
|
|
10293
10293
|
className: 'OpenAiCompatibleExecutionTools',
|
|
10294
|
-
}) /* <- Note: [🤛]
|
|
10294
|
+
}); /* <- Note: [🤛] */
|
|
10295
10295
|
/**
|
|
10296
10296
|
* Execution Tools for calling ONE SPECIFIC PRECONFIGURED OpenAI compatible provider
|
|
10297
10297
|
*
|
|
@@ -10813,11 +10813,11 @@
|
|
|
10813
10813
|
*/
|
|
10814
10814
|
function pipelineJsonToString(pipelineJson) {
|
|
10815
10815
|
const { title, pipelineUrl, bookVersion, description, parameters, tasks } = pipelineJson;
|
|
10816
|
-
let pipelineString =
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
|
|
10820
|
-
|
|
10816
|
+
let pipelineString = _spaceTrim.spaceTrim((block) => `
|
|
10817
|
+
# ${title}
|
|
10818
|
+
|
|
10819
|
+
${block(description || '')}
|
|
10820
|
+
`);
|
|
10821
10821
|
const commands = [];
|
|
10822
10822
|
if (pipelineUrl) {
|
|
10823
10823
|
commands.push(`PIPELINE URL ${pipelineUrl}`);
|
|
@@ -10833,20 +10833,17 @@
|
|
|
10833
10833
|
for (const parameter of parameters.filter(({ isOutput }) => isOutput)) {
|
|
10834
10834
|
commands.push(`OUTPUT PARAMETER ${taskParameterJsonToString(parameter)}`);
|
|
10835
10835
|
}
|
|
10836
|
-
pipelineString
|
|
10837
|
-
|
|
10836
|
+
pipelineString = _spaceTrim.spaceTrim((block) => `
|
|
10837
|
+
${block(pipelineString)}
|
|
10838
|
+
|
|
10839
|
+
${block(commands.map((command) => `- ${command}`).join('\n'))}
|
|
10840
|
+
`);
|
|
10838
10841
|
for (const task of tasks) {
|
|
10839
10842
|
const {
|
|
10840
10843
|
/* Note: Not using:> name, */
|
|
10841
10844
|
title, description,
|
|
10842
10845
|
/* Note: dependentParameterNames, */
|
|
10843
10846
|
jokerParameterNames: jokers, taskType, content, postprocessingFunctionNames: postprocessing, expectations, format, resultingParameterName, } = task;
|
|
10844
|
-
pipelineString += '\n\n';
|
|
10845
|
-
pipelineString += `## ${title}`;
|
|
10846
|
-
if (description) {
|
|
10847
|
-
pipelineString += '\n\n';
|
|
10848
|
-
pipelineString += description;
|
|
10849
|
-
}
|
|
10850
10847
|
const commands = [];
|
|
10851
10848
|
let contentLanguage = 'text';
|
|
10852
10849
|
if (taskType === 'PROMPT_TASK') {
|
|
@@ -10909,18 +10906,23 @@
|
|
|
10909
10906
|
commands.push(`FORMAT JSON`);
|
|
10910
10907
|
}
|
|
10911
10908
|
} /* not else */
|
|
10912
|
-
pipelineString
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
10909
|
+
pipelineString = _spaceTrim.spaceTrim((block) => `
|
|
10910
|
+
${block(pipelineString)}
|
|
10911
|
+
|
|
10912
|
+
## ${title}
|
|
10913
|
+
|
|
10914
|
+
${block(description || '')}
|
|
10915
|
+
|
|
10916
|
+
${block(commands.map((command) => `- ${command}`).join('\n'))}
|
|
10917
|
+
|
|
10918
|
+
\`\`\`${contentLanguage}
|
|
10919
|
+
${block(_spaceTrim.spaceTrim(content))}
|
|
10920
|
+
\`\`\`
|
|
10921
|
+
|
|
10922
|
+
\`-> {${resultingParameterName}}\`
|
|
10923
|
+
`); // <- TODO: [main] !!3 If the parameter here has description, add it and use taskParameterJsonToString
|
|
10924
|
+
// <- TODO: [main] !!3 Escape
|
|
10925
|
+
// <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
|
|
10924
10926
|
}
|
|
10925
10927
|
return validatePipelineString(pipelineString);
|
|
10926
10928
|
}
|
|
@@ -21199,6 +21201,184 @@
|
|
|
21199
21201
|
context.restore();
|
|
21200
21202
|
}
|
|
21201
21203
|
|
|
21204
|
+
/* eslint-disable no-magic-numbers */
|
|
21205
|
+
/**
|
|
21206
|
+
* Default camera distance ratio shared by the proper-3D avatar visuals.
|
|
21207
|
+
*
|
|
21208
|
+
* @private helper of the 3D avatar visuals
|
|
21209
|
+
*/
|
|
21210
|
+
const DEFAULT_3D_CAMERA_DISTANCE_RATIO = 1.4;
|
|
21211
|
+
/**
|
|
21212
|
+
* Clamps one number into the provided range.
|
|
21213
|
+
*
|
|
21214
|
+
* @param value Input value.
|
|
21215
|
+
* @param minimumValue Inclusive lower bound.
|
|
21216
|
+
* @param maximumValue Inclusive upper bound.
|
|
21217
|
+
* @returns Clamped value.
|
|
21218
|
+
*
|
|
21219
|
+
* @private helper of the 3D avatar visuals
|
|
21220
|
+
*/
|
|
21221
|
+
function clampNumber$1(value, minimumValue, maximumValue) {
|
|
21222
|
+
return Math.min(maximumValue, Math.max(minimumValue, value));
|
|
21223
|
+
}
|
|
21224
|
+
/**
|
|
21225
|
+
* Rotates one point around the local Y axis.
|
|
21226
|
+
*
|
|
21227
|
+
* @param point Source point.
|
|
21228
|
+
* @param angle Rotation angle in radians.
|
|
21229
|
+
* @returns Rotated point.
|
|
21230
|
+
*
|
|
21231
|
+
* @private helper of the 3D avatar visuals
|
|
21232
|
+
*/
|
|
21233
|
+
function rotatePointAroundY(point, angle) {
|
|
21234
|
+
const cosine = Math.cos(angle);
|
|
21235
|
+
const sine = Math.sin(angle);
|
|
21236
|
+
return {
|
|
21237
|
+
x: point.x * cosine + point.z * sine,
|
|
21238
|
+
y: point.y,
|
|
21239
|
+
z: -point.x * sine + point.z * cosine,
|
|
21240
|
+
};
|
|
21241
|
+
}
|
|
21242
|
+
/**
|
|
21243
|
+
* Rotates one point around the local X axis.
|
|
21244
|
+
*
|
|
21245
|
+
* @param point Source point.
|
|
21246
|
+
* @param angle Rotation angle in radians.
|
|
21247
|
+
* @returns Rotated point.
|
|
21248
|
+
*
|
|
21249
|
+
* @private helper of the 3D avatar visuals
|
|
21250
|
+
*/
|
|
21251
|
+
function rotatePointAroundX(point, angle) {
|
|
21252
|
+
const cosine = Math.cos(angle);
|
|
21253
|
+
const sine = Math.sin(angle);
|
|
21254
|
+
return {
|
|
21255
|
+
x: point.x,
|
|
21256
|
+
y: point.y * cosine - point.z * sine,
|
|
21257
|
+
z: point.y * sine + point.z * cosine,
|
|
21258
|
+
};
|
|
21259
|
+
}
|
|
21260
|
+
/**
|
|
21261
|
+
* Applies the local rotations and translation to one scene point.
|
|
21262
|
+
*
|
|
21263
|
+
* @param localPoint Point in local object space.
|
|
21264
|
+
* @param center Object center in scene space.
|
|
21265
|
+
* @param rotationX Object pitch in radians.
|
|
21266
|
+
* @param rotationY Object yaw in radians.
|
|
21267
|
+
* @returns Transformed scene-space point.
|
|
21268
|
+
*
|
|
21269
|
+
* @private helper of the 3D avatar visuals
|
|
21270
|
+
*/
|
|
21271
|
+
function transformScenePoint(localPoint, center, rotationX, rotationY) {
|
|
21272
|
+
const yawedPoint = rotatePointAroundY(localPoint, rotationY);
|
|
21273
|
+
const pitchedPoint = rotatePointAroundX(yawedPoint, rotationX);
|
|
21274
|
+
return {
|
|
21275
|
+
x: center.x + pitchedPoint.x,
|
|
21276
|
+
y: center.y + pitchedPoint.y,
|
|
21277
|
+
z: center.z + pitchedPoint.z,
|
|
21278
|
+
};
|
|
21279
|
+
}
|
|
21280
|
+
/**
|
|
21281
|
+
* Projects one scene point into canvas coordinates.
|
|
21282
|
+
*
|
|
21283
|
+
* @param point Scene-space point.
|
|
21284
|
+
* @param size Canvas size in CSS pixels.
|
|
21285
|
+
* @param sceneCenterX Horizontal scene center.
|
|
21286
|
+
* @param sceneCenterY Vertical scene center.
|
|
21287
|
+
* @param cameraDistanceRatio Optional camera distance ratio.
|
|
21288
|
+
* @returns Projected point.
|
|
21289
|
+
*
|
|
21290
|
+
* @private helper of the 3D avatar visuals
|
|
21291
|
+
*/
|
|
21292
|
+
function projectScenePoint(point, size, sceneCenterX, sceneCenterY, cameraDistanceRatio = DEFAULT_3D_CAMERA_DISTANCE_RATIO) {
|
|
21293
|
+
const cameraDistance = size * cameraDistanceRatio;
|
|
21294
|
+
const perspectiveScale = cameraDistance / Math.max(cameraDistance - point.z, cameraDistance * 0.35);
|
|
21295
|
+
return {
|
|
21296
|
+
x: sceneCenterX + point.x * perspectiveScale,
|
|
21297
|
+
y: sceneCenterY + point.y * perspectiveScale,
|
|
21298
|
+
z: point.z,
|
|
21299
|
+
};
|
|
21300
|
+
}
|
|
21301
|
+
/**
|
|
21302
|
+
* Subtracts one 3D point from another.
|
|
21303
|
+
*
|
|
21304
|
+
* @param leftPoint Left point.
|
|
21305
|
+
* @param rightPoint Right point.
|
|
21306
|
+
* @returns Difference vector.
|
|
21307
|
+
*
|
|
21308
|
+
* @private helper of the 3D avatar visuals
|
|
21309
|
+
*/
|
|
21310
|
+
function subtractPoint3D(leftPoint, rightPoint) {
|
|
21311
|
+
return {
|
|
21312
|
+
x: leftPoint.x - rightPoint.x,
|
|
21313
|
+
y: leftPoint.y - rightPoint.y,
|
|
21314
|
+
z: leftPoint.z - rightPoint.z,
|
|
21315
|
+
};
|
|
21316
|
+
}
|
|
21317
|
+
/**
|
|
21318
|
+
* Computes the 3D cross product of two vectors.
|
|
21319
|
+
*
|
|
21320
|
+
* @param leftVector Left vector.
|
|
21321
|
+
* @param rightVector Right vector.
|
|
21322
|
+
* @returns Cross product.
|
|
21323
|
+
*
|
|
21324
|
+
* @private helper of the 3D avatar visuals
|
|
21325
|
+
*/
|
|
21326
|
+
function crossProduct3D(leftVector, rightVector) {
|
|
21327
|
+
return {
|
|
21328
|
+
x: leftVector.y * rightVector.z - leftVector.z * rightVector.y,
|
|
21329
|
+
y: leftVector.z * rightVector.x - leftVector.x * rightVector.z,
|
|
21330
|
+
z: leftVector.x * rightVector.y - leftVector.y * rightVector.x,
|
|
21331
|
+
};
|
|
21332
|
+
}
|
|
21333
|
+
/**
|
|
21334
|
+
* Computes the 3D dot product of two vectors.
|
|
21335
|
+
*
|
|
21336
|
+
* @param leftVector Left vector.
|
|
21337
|
+
* @param rightVector Right vector.
|
|
21338
|
+
* @returns Dot product.
|
|
21339
|
+
*
|
|
21340
|
+
* @private helper of the 3D avatar visuals
|
|
21341
|
+
*/
|
|
21342
|
+
function dotProduct3D(leftVector, rightVector) {
|
|
21343
|
+
return leftVector.x * rightVector.x + leftVector.y * rightVector.y + leftVector.z * rightVector.z;
|
|
21344
|
+
}
|
|
21345
|
+
/**
|
|
21346
|
+
* Normalizes one 3D vector while keeping zero vectors stable.
|
|
21347
|
+
*
|
|
21348
|
+
* @param vector Source vector.
|
|
21349
|
+
* @returns Normalized vector.
|
|
21350
|
+
*
|
|
21351
|
+
* @private helper of the 3D avatar visuals
|
|
21352
|
+
*/
|
|
21353
|
+
function normalizeVector3(vector) {
|
|
21354
|
+
const length = Math.hypot(vector.x, vector.y, vector.z);
|
|
21355
|
+
if (length === 0) {
|
|
21356
|
+
return vector;
|
|
21357
|
+
}
|
|
21358
|
+
return {
|
|
21359
|
+
x: vector.x / length,
|
|
21360
|
+
y: vector.y / length,
|
|
21361
|
+
z: vector.z / length,
|
|
21362
|
+
};
|
|
21363
|
+
}
|
|
21364
|
+
/**
|
|
21365
|
+
* Measures the perimeter of one projected quad.
|
|
21366
|
+
*
|
|
21367
|
+
* @param corners Quad corners.
|
|
21368
|
+
* @returns Perimeter length.
|
|
21369
|
+
*
|
|
21370
|
+
* @private helper of the 3D avatar visuals
|
|
21371
|
+
*/
|
|
21372
|
+
function getProjectedQuadPerimeter(corners) {
|
|
21373
|
+
let perimeter = 0;
|
|
21374
|
+
for (let cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
|
|
21375
|
+
const currentCorner = corners[cornerIndex];
|
|
21376
|
+
const nextCorner = corners[(cornerIndex + 1) % corners.length];
|
|
21377
|
+
perimeter += Math.hypot(nextCorner.x - currentCorner.x, nextCorner.y - currentCorner.y);
|
|
21378
|
+
}
|
|
21379
|
+
return perimeter;
|
|
21380
|
+
}
|
|
21381
|
+
|
|
21202
21382
|
/* eslint-disable no-magic-numbers */
|
|
21203
21383
|
/**
|
|
21204
21384
|
* Builds the seeded six-face texture pack used by the Minecraft-style head cuboid.
|
|
@@ -21371,18 +21551,12 @@
|
|
|
21371
21551
|
}
|
|
21372
21552
|
|
|
21373
21553
|
/* eslint-disable no-magic-numbers */
|
|
21374
|
-
/**
|
|
21375
|
-
* Fixed scene camera distance used for the proper-3D projection.
|
|
21376
|
-
*
|
|
21377
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21378
|
-
*/
|
|
21379
|
-
const CAMERA_DISTANCE_RATIO = 1.4;
|
|
21380
21554
|
/**
|
|
21381
21555
|
* Shared light direction used to shade projected cuboid faces.
|
|
21382
21556
|
*
|
|
21383
21557
|
* @private helper of `minecraft2AvatarVisual`
|
|
21384
21558
|
*/
|
|
21385
|
-
const LIGHT_DIRECTION = normalizeVector3({
|
|
21559
|
+
const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
21386
21560
|
x: 0.4,
|
|
21387
21561
|
y: -0.65,
|
|
21388
21562
|
z: 0.92,
|
|
@@ -21594,7 +21768,7 @@
|
|
|
21594
21768
|
corners: projectedCorners,
|
|
21595
21769
|
texture: faceDefinition.texture,
|
|
21596
21770
|
averageDepth: transformedCorners.reduce((depthSum, corner) => depthSum + corner.z, 0) / transformedCorners.length,
|
|
21597
|
-
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION), -1, 1),
|
|
21771
|
+
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$1), -1, 1),
|
|
21598
21772
|
outlineColor: cuboid.outlineColor,
|
|
21599
21773
|
};
|
|
21600
21774
|
});
|
|
@@ -21621,7 +21795,7 @@
|
|
|
21621
21795
|
const endX = (columnIndex + 1) / columns;
|
|
21622
21796
|
const startY = rowIndex / rows;
|
|
21623
21797
|
const endY = (rowIndex + 1) / rows;
|
|
21624
|
-
drawProjectedQuad(context, [
|
|
21798
|
+
drawProjectedQuad$1(context, [
|
|
21625
21799
|
interpolateProjectedQuad(face.corners, startX, startY),
|
|
21626
21800
|
interpolateProjectedQuad(face.corners, endX, startY),
|
|
21627
21801
|
interpolateProjectedQuad(face.corners, endX, endY),
|
|
@@ -21630,10 +21804,10 @@
|
|
|
21630
21804
|
}
|
|
21631
21805
|
}
|
|
21632
21806
|
if (face.lightIntensity > 0) {
|
|
21633
|
-
drawProjectedQuad(context, face.corners, `rgba(255, 255, 255, ${0.15 * face.lightIntensity})`);
|
|
21807
|
+
drawProjectedQuad$1(context, face.corners, `rgba(255, 255, 255, ${0.15 * face.lightIntensity})`);
|
|
21634
21808
|
}
|
|
21635
21809
|
else if (face.lightIntensity < 0) {
|
|
21636
|
-
drawProjectedQuad(context, face.corners, `rgba(0, 0, 0, ${0.22 * Math.abs(face.lightIntensity)})`);
|
|
21810
|
+
drawProjectedQuad$1(context, face.corners, `rgba(0, 0, 0, ${0.22 * Math.abs(face.lightIntensity)})`);
|
|
21637
21811
|
}
|
|
21638
21812
|
context.save();
|
|
21639
21813
|
context.beginPath();
|
|
@@ -21657,7 +21831,7 @@
|
|
|
21657
21831
|
*
|
|
21658
21832
|
* @private helper of `minecraft2AvatarVisual`
|
|
21659
21833
|
*/
|
|
21660
|
-
function drawProjectedQuad(context, corners, fillStyle) {
|
|
21834
|
+
function drawProjectedQuad$1(context, corners, fillStyle) {
|
|
21661
21835
|
context.beginPath();
|
|
21662
21836
|
context.moveTo(corners[0].x, corners[0].y);
|
|
21663
21837
|
context.lineTo(corners[1].x, corners[1].y);
|
|
@@ -21699,175 +21873,6 @@
|
|
|
21699
21873
|
z: startPoint.z + (endPoint.z - startPoint.z) * ratio,
|
|
21700
21874
|
};
|
|
21701
21875
|
}
|
|
21702
|
-
/**
|
|
21703
|
-
* Projects one rotated scene point into canvas coordinates.
|
|
21704
|
-
*
|
|
21705
|
-
* @param point Scene point.
|
|
21706
|
-
* @param size Canvas size in CSS pixels.
|
|
21707
|
-
* @param sceneCenterX Horizontal scene center.
|
|
21708
|
-
* @param sceneCenterY Vertical scene center.
|
|
21709
|
-
* @returns Projected point.
|
|
21710
|
-
*
|
|
21711
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21712
|
-
*/
|
|
21713
|
-
function projectScenePoint(point, size, sceneCenterX, sceneCenterY) {
|
|
21714
|
-
const cameraDistance = size * CAMERA_DISTANCE_RATIO;
|
|
21715
|
-
const perspectiveScale = cameraDistance / Math.max(cameraDistance - point.z, cameraDistance * 0.35);
|
|
21716
|
-
return {
|
|
21717
|
-
x: sceneCenterX + point.x * perspectiveScale,
|
|
21718
|
-
y: sceneCenterY + point.y * perspectiveScale,
|
|
21719
|
-
z: point.z,
|
|
21720
|
-
};
|
|
21721
|
-
}
|
|
21722
|
-
/**
|
|
21723
|
-
* Applies the local cuboid rotations and translation to one scene point.
|
|
21724
|
-
*
|
|
21725
|
-
* @param localPoint Point in cuboid-local space.
|
|
21726
|
-
* @param center Cuboid center in scene space.
|
|
21727
|
-
* @param rotationX Cuboid pitch in radians.
|
|
21728
|
-
* @param rotationY Cuboid yaw in radians.
|
|
21729
|
-
* @returns Transformed scene-space point.
|
|
21730
|
-
*
|
|
21731
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21732
|
-
*/
|
|
21733
|
-
function transformScenePoint(localPoint, center, rotationX, rotationY) {
|
|
21734
|
-
const yawedPoint = rotatePointAroundY(localPoint, rotationY);
|
|
21735
|
-
const pitchedPoint = rotatePointAroundX(yawedPoint, rotationX);
|
|
21736
|
-
return {
|
|
21737
|
-
x: center.x + pitchedPoint.x,
|
|
21738
|
-
y: center.y + pitchedPoint.y,
|
|
21739
|
-
z: center.z + pitchedPoint.z,
|
|
21740
|
-
};
|
|
21741
|
-
}
|
|
21742
|
-
/**
|
|
21743
|
-
* Rotates one point around the local Y axis.
|
|
21744
|
-
*
|
|
21745
|
-
* @param point Source point.
|
|
21746
|
-
* @param angle Rotation angle in radians.
|
|
21747
|
-
* @returns Rotated point.
|
|
21748
|
-
*
|
|
21749
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21750
|
-
*/
|
|
21751
|
-
function rotatePointAroundY(point, angle) {
|
|
21752
|
-
const cosine = Math.cos(angle);
|
|
21753
|
-
const sine = Math.sin(angle);
|
|
21754
|
-
return {
|
|
21755
|
-
x: point.x * cosine + point.z * sine,
|
|
21756
|
-
y: point.y,
|
|
21757
|
-
z: -point.x * sine + point.z * cosine,
|
|
21758
|
-
};
|
|
21759
|
-
}
|
|
21760
|
-
/**
|
|
21761
|
-
* Rotates one point around the local X axis.
|
|
21762
|
-
*
|
|
21763
|
-
* @param point Source point.
|
|
21764
|
-
* @param angle Rotation angle in radians.
|
|
21765
|
-
* @returns Rotated point.
|
|
21766
|
-
*
|
|
21767
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21768
|
-
*/
|
|
21769
|
-
function rotatePointAroundX(point, angle) {
|
|
21770
|
-
const cosine = Math.cos(angle);
|
|
21771
|
-
const sine = Math.sin(angle);
|
|
21772
|
-
return {
|
|
21773
|
-
x: point.x,
|
|
21774
|
-
y: point.y * cosine - point.z * sine,
|
|
21775
|
-
z: point.y * sine + point.z * cosine,
|
|
21776
|
-
};
|
|
21777
|
-
}
|
|
21778
|
-
/**
|
|
21779
|
-
* Subtracts one 3D point from another.
|
|
21780
|
-
*
|
|
21781
|
-
* @param leftPoint Left point.
|
|
21782
|
-
* @param rightPoint Right point.
|
|
21783
|
-
* @returns Difference vector.
|
|
21784
|
-
*
|
|
21785
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21786
|
-
*/
|
|
21787
|
-
function subtractPoint3D(leftPoint, rightPoint) {
|
|
21788
|
-
return {
|
|
21789
|
-
x: leftPoint.x - rightPoint.x,
|
|
21790
|
-
y: leftPoint.y - rightPoint.y,
|
|
21791
|
-
z: leftPoint.z - rightPoint.z,
|
|
21792
|
-
};
|
|
21793
|
-
}
|
|
21794
|
-
/**
|
|
21795
|
-
* Computes the 3D cross product of two vectors.
|
|
21796
|
-
*
|
|
21797
|
-
* @param leftVector Left vector.
|
|
21798
|
-
* @param rightVector Right vector.
|
|
21799
|
-
* @returns Cross product.
|
|
21800
|
-
*
|
|
21801
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21802
|
-
*/
|
|
21803
|
-
function crossProduct3D(leftVector, rightVector) {
|
|
21804
|
-
return {
|
|
21805
|
-
x: leftVector.y * rightVector.z - leftVector.z * rightVector.y,
|
|
21806
|
-
y: leftVector.z * rightVector.x - leftVector.x * rightVector.z,
|
|
21807
|
-
z: leftVector.x * rightVector.y - leftVector.y * rightVector.x,
|
|
21808
|
-
};
|
|
21809
|
-
}
|
|
21810
|
-
/**
|
|
21811
|
-
* Computes the 3D dot product of two vectors.
|
|
21812
|
-
*
|
|
21813
|
-
* @param leftVector Left vector.
|
|
21814
|
-
* @param rightVector Right vector.
|
|
21815
|
-
* @returns Dot product.
|
|
21816
|
-
*
|
|
21817
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21818
|
-
*/
|
|
21819
|
-
function dotProduct3D(leftVector, rightVector) {
|
|
21820
|
-
return leftVector.x * rightVector.x + leftVector.y * rightVector.y + leftVector.z * rightVector.z;
|
|
21821
|
-
}
|
|
21822
|
-
/**
|
|
21823
|
-
* Normalizes one 3D vector while keeping zero vectors stable.
|
|
21824
|
-
*
|
|
21825
|
-
* @param vector Source vector.
|
|
21826
|
-
* @returns Normalized vector.
|
|
21827
|
-
*
|
|
21828
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21829
|
-
*/
|
|
21830
|
-
function normalizeVector3(vector) {
|
|
21831
|
-
const length = Math.hypot(vector.x, vector.y, vector.z);
|
|
21832
|
-
if (length === 0) {
|
|
21833
|
-
return vector;
|
|
21834
|
-
}
|
|
21835
|
-
return {
|
|
21836
|
-
x: vector.x / length,
|
|
21837
|
-
y: vector.y / length,
|
|
21838
|
-
z: vector.z / length,
|
|
21839
|
-
};
|
|
21840
|
-
}
|
|
21841
|
-
/**
|
|
21842
|
-
* Clamps one number into the provided range.
|
|
21843
|
-
*
|
|
21844
|
-
* @param value Input value.
|
|
21845
|
-
* @param minimumValue Inclusive lower bound.
|
|
21846
|
-
* @param maximumValue Inclusive upper bound.
|
|
21847
|
-
* @returns Clamped value.
|
|
21848
|
-
*
|
|
21849
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21850
|
-
*/
|
|
21851
|
-
function clampNumber$1(value, minimumValue, maximumValue) {
|
|
21852
|
-
return Math.min(maximumValue, Math.max(minimumValue, value));
|
|
21853
|
-
}
|
|
21854
|
-
/**
|
|
21855
|
-
* Measures the perimeter of one projected quad.
|
|
21856
|
-
*
|
|
21857
|
-
* @param corners Quad corners.
|
|
21858
|
-
* @returns Perimeter length.
|
|
21859
|
-
*
|
|
21860
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21861
|
-
*/
|
|
21862
|
-
function getProjectedQuadPerimeter(corners) {
|
|
21863
|
-
let perimeter = 0;
|
|
21864
|
-
for (let cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
|
|
21865
|
-
const currentCorner = corners[cornerIndex];
|
|
21866
|
-
const nextCorner = corners[(cornerIndex + 1) % corners.length];
|
|
21867
|
-
perimeter += Math.hypot(nextCorner.x - currentCorner.x, nextCorner.y - currentCorner.y);
|
|
21868
|
-
}
|
|
21869
|
-
return perimeter;
|
|
21870
|
-
}
|
|
21871
21876
|
|
|
21872
21877
|
/* eslint-disable no-magic-numbers */
|
|
21873
21878
|
/**
|
|
@@ -22436,7 +22441,7 @@
|
|
|
22436
22441
|
*
|
|
22437
22442
|
* @private helper of `octopus3AvatarVisual`
|
|
22438
22443
|
*/
|
|
22439
|
-
function formatAlphaHex(opacity) {
|
|
22444
|
+
function formatAlphaHex$1(opacity) {
|
|
22440
22445
|
return Math.round(Math.min(1, Math.max(0, opacity)) * 255)
|
|
22441
22446
|
.toString(16)
|
|
22442
22447
|
.padStart(2, '0');
|
|
@@ -22815,7 +22820,7 @@
|
|
|
22815
22820
|
context.beginPath();
|
|
22816
22821
|
context.moveTo(-radiusX * 0.74, radiusY * 0.2);
|
|
22817
22822
|
context.quadraticCurveTo(0, radiusY * 0.38, radiusX * 0.74, radiusY * 0.2);
|
|
22818
|
-
context.strokeStyle = `${palette.highlight}${formatAlphaHex(eyeStyle.lowerLidOpacity)}`;
|
|
22823
|
+
context.strokeStyle = `${palette.highlight}${formatAlphaHex$1(eyeStyle.lowerLidOpacity)}`;
|
|
22819
22824
|
context.lineWidth = radiusX * 0.08;
|
|
22820
22825
|
context.lineCap = 'round';
|
|
22821
22826
|
context.stroke();
|
|
@@ -22823,6 +22828,518 @@
|
|
|
22823
22828
|
context.restore();
|
|
22824
22829
|
}
|
|
22825
22830
|
|
|
22831
|
+
/* eslint-disable no-magic-numbers */
|
|
22832
|
+
/**
|
|
22833
|
+
* Light direction used by the organic 3D octopus shading.
|
|
22834
|
+
*
|
|
22835
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
22836
|
+
*/
|
|
22837
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
22838
|
+
x: 0.48,
|
|
22839
|
+
y: -0.62,
|
|
22840
|
+
z: 0.94,
|
|
22841
|
+
});
|
|
22842
|
+
/**
|
|
22843
|
+
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
22844
|
+
*
|
|
22845
|
+
* @private built-in avatar visual
|
|
22846
|
+
*/
|
|
22847
|
+
const octopus3dAvatarVisual = {
|
|
22848
|
+
id: 'octopus3d',
|
|
22849
|
+
title: 'Octopus 3D',
|
|
22850
|
+
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
22851
|
+
isAnimated: true,
|
|
22852
|
+
supportsPointerTracking: true,
|
|
22853
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
22854
|
+
const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
|
|
22855
|
+
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
22856
|
+
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
22857
|
+
const animationPhase = animationRandom() * Math.PI * 2;
|
|
22858
|
+
const sceneCenterX = size * 0.5;
|
|
22859
|
+
const sceneCenterY = size * 0.56;
|
|
22860
|
+
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
22861
|
+
const mantleCenter = {
|
|
22862
|
+
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
22863
|
+
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
22864
|
+
z: interaction.intensity * size * 0.012,
|
|
22865
|
+
};
|
|
22866
|
+
const underbodyCenter = {
|
|
22867
|
+
x: mantleCenter.x * 0.86,
|
|
22868
|
+
y: mantleCenter.y + size * 0.168,
|
|
22869
|
+
z: mantleCenter.z - size * 0.018,
|
|
22870
|
+
};
|
|
22871
|
+
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
22872
|
+
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
22873
|
+
const mantleRadiusZ = size * morphologyProfile.body.bodyRadiusRatio * (0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
22874
|
+
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
22875
|
+
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
22876
|
+
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
22877
|
+
const bodyYaw = -0.18 +
|
|
22878
|
+
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
22879
|
+
interaction.bodyOffsetX * 0.18 +
|
|
22880
|
+
interaction.gazeX * 0.22;
|
|
22881
|
+
const bodyPitch = -0.08 +
|
|
22882
|
+
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
22883
|
+
interaction.bodyOffsetY * 0.08 -
|
|
22884
|
+
interaction.gazeY * 0.08;
|
|
22885
|
+
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
22886
|
+
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
22887
|
+
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
22888
|
+
center: mantleCenter,
|
|
22889
|
+
radiusX: mantleRadiusX,
|
|
22890
|
+
radiusY: mantleRadiusY,
|
|
22891
|
+
radiusZ: mantleRadiusZ,
|
|
22892
|
+
rotationX: headPitch,
|
|
22893
|
+
rotationY: headYaw,
|
|
22894
|
+
sceneCenterX,
|
|
22895
|
+
sceneCenterY,
|
|
22896
|
+
size,
|
|
22897
|
+
palette,
|
|
22898
|
+
verticalColorBias: 0,
|
|
22899
|
+
outlineColor: `${palette.highlight}7a`,
|
|
22900
|
+
});
|
|
22901
|
+
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
22902
|
+
center: underbodyCenter,
|
|
22903
|
+
radiusX: underbodyRadiusX,
|
|
22904
|
+
radiusY: underbodyRadiusY,
|
|
22905
|
+
radiusZ: underbodyRadiusZ,
|
|
22906
|
+
rotationX: bodyPitch,
|
|
22907
|
+
rotationY: bodyYaw,
|
|
22908
|
+
sceneCenterX,
|
|
22909
|
+
sceneCenterY,
|
|
22910
|
+
size,
|
|
22911
|
+
palette,
|
|
22912
|
+
verticalColorBias: 0.18,
|
|
22913
|
+
outlineColor: `${palette.shadow}8f`,
|
|
22914
|
+
});
|
|
22915
|
+
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
22916
|
+
createRandom,
|
|
22917
|
+
morphologyProfile,
|
|
22918
|
+
timeMs,
|
|
22919
|
+
size,
|
|
22920
|
+
center: underbodyCenter,
|
|
22921
|
+
radiusX: underbodyRadiusX,
|
|
22922
|
+
radiusY: underbodyRadiusY,
|
|
22923
|
+
radiusZ: underbodyRadiusZ,
|
|
22924
|
+
rotationX: bodyPitch,
|
|
22925
|
+
rotationY: bodyYaw,
|
|
22926
|
+
sceneCenterX,
|
|
22927
|
+
sceneCenterY,
|
|
22928
|
+
animationPhase,
|
|
22929
|
+
});
|
|
22930
|
+
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
22931
|
+
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
22932
|
+
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
22933
|
+
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
22934
|
+
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
22935
|
+
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
22936
|
+
drawAvatarFrame(context, size, palette);
|
|
22937
|
+
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
22938
|
+
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
22939
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
22940
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
22941
|
+
}
|
|
22942
|
+
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
22943
|
+
drawSurfacePatch(context, surfacePatch);
|
|
22944
|
+
}
|
|
22945
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
22946
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
22947
|
+
}
|
|
22948
|
+
drawProjectedEye(context, {
|
|
22949
|
+
x: -faceEyeSpacing,
|
|
22950
|
+
y: faceEyeYOffset,
|
|
22951
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
22952
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
|
|
22953
|
+
drawProjectedEye(context, {
|
|
22954
|
+
x: faceEyeSpacing,
|
|
22955
|
+
y: faceEyeYOffset,
|
|
22956
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
22957
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
|
|
22958
|
+
drawProjectedMouth(context, [
|
|
22959
|
+
{ x: -mouthHalfWidth, y: mouthY, z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY) },
|
|
22960
|
+
{
|
|
22961
|
+
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
22962
|
+
y: mouthY +
|
|
22963
|
+
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
22964
|
+
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
22965
|
+
interaction.gazeY * size * 0.01,
|
|
22966
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
22967
|
+
},
|
|
22968
|
+
{ x: mouthHalfWidth, y: mouthY, z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY) },
|
|
22969
|
+
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
22970
|
+
},
|
|
22971
|
+
};
|
|
22972
|
+
/**
|
|
22973
|
+
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
22974
|
+
*
|
|
22975
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
22976
|
+
*/
|
|
22977
|
+
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
22978
|
+
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);
|
|
22979
|
+
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
22980
|
+
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
22981
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
22982
|
+
context.fillStyle = glowGradient;
|
|
22983
|
+
context.fillRect(0, 0, size, size);
|
|
22984
|
+
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);
|
|
22985
|
+
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
22986
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
22987
|
+
context.fillStyle = lowerGradient;
|
|
22988
|
+
context.fillRect(0, 0, size, size);
|
|
22989
|
+
}
|
|
22990
|
+
/**
|
|
22991
|
+
* Draws the soft ground shadow below the octopus.
|
|
22992
|
+
*
|
|
22993
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
22994
|
+
*/
|
|
22995
|
+
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
22996
|
+
context.save();
|
|
22997
|
+
context.fillStyle = `${palette.shadow}66`;
|
|
22998
|
+
context.filter = `blur(${size * 0.022}px)`;
|
|
22999
|
+
context.beginPath();
|
|
23000
|
+
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);
|
|
23001
|
+
context.fill();
|
|
23002
|
+
context.restore();
|
|
23003
|
+
}
|
|
23004
|
+
/**
|
|
23005
|
+
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
23006
|
+
*
|
|
23007
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23008
|
+
*/
|
|
23009
|
+
function resolveVisibleEllipsoidPatches(options) {
|
|
23010
|
+
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
23011
|
+
const latitudePatchCount = 10;
|
|
23012
|
+
const longitudePatchCount = 18;
|
|
23013
|
+
const surfacePatches = [];
|
|
23014
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
23015
|
+
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
23016
|
+
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
23017
|
+
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
23018
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
23019
|
+
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
23020
|
+
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
23021
|
+
const localCorners = [
|
|
23022
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
23023
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
23024
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
23025
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
23026
|
+
];
|
|
23027
|
+
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
23028
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
23029
|
+
if (surfaceNormal.z <= 0.01) {
|
|
23030
|
+
continue;
|
|
23031
|
+
}
|
|
23032
|
+
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
23033
|
+
surfacePatches.push({
|
|
23034
|
+
corners: projectedCorners,
|
|
23035
|
+
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
23036
|
+
transformedCorners.length,
|
|
23037
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
23038
|
+
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
23039
|
+
outlineColor,
|
|
23040
|
+
});
|
|
23041
|
+
}
|
|
23042
|
+
}
|
|
23043
|
+
return surfacePatches;
|
|
23044
|
+
}
|
|
23045
|
+
/**
|
|
23046
|
+
* Samples one point on an ellipsoid aligned to the local axes.
|
|
23047
|
+
*
|
|
23048
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23049
|
+
*/
|
|
23050
|
+
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
23051
|
+
const cosineLatitude = Math.cos(latitude);
|
|
23052
|
+
return {
|
|
23053
|
+
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
23054
|
+
y: Math.sin(latitude) * radiusY,
|
|
23055
|
+
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
23056
|
+
};
|
|
23057
|
+
}
|
|
23058
|
+
/**
|
|
23059
|
+
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
23060
|
+
*
|
|
23061
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23062
|
+
*/
|
|
23063
|
+
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
23064
|
+
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
23065
|
+
if (clampedVerticalProgress < 0.2) {
|
|
23066
|
+
return palette.highlight;
|
|
23067
|
+
}
|
|
23068
|
+
if (clampedVerticalProgress < 0.45) {
|
|
23069
|
+
return palette.secondary;
|
|
23070
|
+
}
|
|
23071
|
+
if (clampedVerticalProgress < 0.8) {
|
|
23072
|
+
return palette.primary;
|
|
23073
|
+
}
|
|
23074
|
+
return `${palette.shadow}f2`;
|
|
23075
|
+
}
|
|
23076
|
+
/**
|
|
23077
|
+
* Draws one projected mesh patch with organic shading.
|
|
23078
|
+
*
|
|
23079
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23080
|
+
*/
|
|
23081
|
+
function drawSurfacePatch(context, surfacePatch) {
|
|
23082
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
23083
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
23084
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
23085
|
+
}
|
|
23086
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
23087
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
23088
|
+
}
|
|
23089
|
+
context.save();
|
|
23090
|
+
context.beginPath();
|
|
23091
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
23092
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
23093
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
23094
|
+
}
|
|
23095
|
+
context.closePath();
|
|
23096
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
23097
|
+
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
23098
|
+
context.lineJoin = 'round';
|
|
23099
|
+
context.stroke();
|
|
23100
|
+
context.restore();
|
|
23101
|
+
}
|
|
23102
|
+
/**
|
|
23103
|
+
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
23104
|
+
*
|
|
23105
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23106
|
+
*/
|
|
23107
|
+
function createOctopusTentacleStrokes(options) {
|
|
23108
|
+
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
23109
|
+
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
23110
|
+
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
23111
|
+
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
23112
|
+
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
23113
|
+
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
23114
|
+
const lateralReach = size *
|
|
23115
|
+
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
23116
|
+
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
23117
|
+
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
23118
|
+
const anchorPoint = {
|
|
23119
|
+
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
23120
|
+
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
23121
|
+
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
23122
|
+
};
|
|
23123
|
+
const controlPointOne = {
|
|
23124
|
+
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
23125
|
+
y: anchorPoint.y + flowLength * 0.26,
|
|
23126
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
23127
|
+
};
|
|
23128
|
+
const controlPointTwo = {
|
|
23129
|
+
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
23130
|
+
y: anchorPoint.y + flowLength * 0.66,
|
|
23131
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
23132
|
+
};
|
|
23133
|
+
const endPoint = {
|
|
23134
|
+
x: anchorPoint.x +
|
|
23135
|
+
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
23136
|
+
sway * size * 0.028,
|
|
23137
|
+
y: anchorPoint.y + flowLength,
|
|
23138
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
23139
|
+
};
|
|
23140
|
+
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
23141
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
23142
|
+
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
23143
|
+
return {
|
|
23144
|
+
projectedPoints,
|
|
23145
|
+
averageDepth,
|
|
23146
|
+
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
23147
|
+
baseWidth: size *
|
|
23148
|
+
(0.019 +
|
|
23149
|
+
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
23150
|
+
tentacleRandom() * 0.003 +
|
|
23151
|
+
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
23152
|
+
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
23153
|
+
colorBias: tentacleRandom(),
|
|
23154
|
+
};
|
|
23155
|
+
});
|
|
23156
|
+
}
|
|
23157
|
+
/**
|
|
23158
|
+
* Samples one point on a cubic Bezier curve in 3D.
|
|
23159
|
+
*
|
|
23160
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23161
|
+
*/
|
|
23162
|
+
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
23163
|
+
const inverseProgress = 1 - progress;
|
|
23164
|
+
return {
|
|
23165
|
+
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
23166
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
23167
|
+
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
23168
|
+
progress * progress * progress * endPoint.x,
|
|
23169
|
+
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
23170
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
23171
|
+
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
23172
|
+
progress * progress * progress * endPoint.y,
|
|
23173
|
+
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
23174
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
23175
|
+
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
23176
|
+
progress * progress * progress * endPoint.z,
|
|
23177
|
+
};
|
|
23178
|
+
}
|
|
23179
|
+
/**
|
|
23180
|
+
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
23181
|
+
*
|
|
23182
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23183
|
+
*/
|
|
23184
|
+
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
23185
|
+
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
23186
|
+
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
23187
|
+
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
23188
|
+
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
23189
|
+
const progress = segmentIndex / projectedSegments;
|
|
23190
|
+
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
23191
|
+
context.beginPath();
|
|
23192
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
23193
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
23194
|
+
context.strokeStyle =
|
|
23195
|
+
tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
23196
|
+
context.lineWidth = width;
|
|
23197
|
+
context.lineCap = 'round';
|
|
23198
|
+
context.stroke();
|
|
23199
|
+
context.beginPath();
|
|
23200
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
23201
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
23202
|
+
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
23203
|
+
context.lineWidth = Math.max(1, width * 0.34);
|
|
23204
|
+
context.lineCap = 'round';
|
|
23205
|
+
context.stroke();
|
|
23206
|
+
}
|
|
23207
|
+
}
|
|
23208
|
+
/**
|
|
23209
|
+
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
23210
|
+
*
|
|
23211
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23212
|
+
*/
|
|
23213
|
+
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
23214
|
+
const normalizedX = x / radiusX;
|
|
23215
|
+
const normalizedY = y / radiusY;
|
|
23216
|
+
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
23217
|
+
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
23218
|
+
}
|
|
23219
|
+
/**
|
|
23220
|
+
* Draws one projected eye on the turned octopus mantle.
|
|
23221
|
+
*
|
|
23222
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23223
|
+
*/
|
|
23224
|
+
function drawProjectedEye(context, localCenter, radiusX, radiusY, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, phase, interaction, eyeStyle) {
|
|
23225
|
+
const centerScenePoint = transformScenePoint(localCenter, center, rotationX, rotationY);
|
|
23226
|
+
if (centerScenePoint.z <= center.z) {
|
|
23227
|
+
return;
|
|
23228
|
+
}
|
|
23229
|
+
const horizontalScenePoint = transformScenePoint({ x: localCenter.x + radiusX, y: localCenter.y, z: localCenter.z }, center, rotationX, rotationY);
|
|
23230
|
+
const verticalScenePoint = transformScenePoint({ x: localCenter.x, y: localCenter.y + radiusY, z: localCenter.z }, center, rotationX, rotationY);
|
|
23231
|
+
const projectedCenterPoint = projectScenePoint(centerScenePoint, size, sceneCenterX, sceneCenterY);
|
|
23232
|
+
const projectedHorizontalPoint = projectScenePoint(horizontalScenePoint, size, sceneCenterX, sceneCenterY);
|
|
23233
|
+
const projectedVerticalPoint = projectScenePoint(verticalScenePoint, size, sceneCenterX, sceneCenterY);
|
|
23234
|
+
const projectedRadiusX = Math.hypot(projectedHorizontalPoint.x - projectedCenterPoint.x, projectedHorizontalPoint.y - projectedCenterPoint.y);
|
|
23235
|
+
const projectedRadiusY = Math.hypot(projectedVerticalPoint.x - projectedCenterPoint.x, projectedVerticalPoint.y - projectedCenterPoint.y);
|
|
23236
|
+
if (projectedRadiusX < size * 0.008 || projectedRadiusY < size * 0.008) {
|
|
23237
|
+
return;
|
|
23238
|
+
}
|
|
23239
|
+
const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
|
|
23240
|
+
radiusX: projectedRadiusX,
|
|
23241
|
+
radiusY: projectedRadiusY,
|
|
23242
|
+
timeMs,
|
|
23243
|
+
phase,
|
|
23244
|
+
interaction,
|
|
23245
|
+
});
|
|
23246
|
+
const rotation = Math.atan2(projectedHorizontalPoint.y - projectedCenterPoint.y, projectedHorizontalPoint.x - projectedCenterPoint.x);
|
|
23247
|
+
context.save();
|
|
23248
|
+
context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
|
|
23249
|
+
context.rotate(rotation);
|
|
23250
|
+
context.beginPath();
|
|
23251
|
+
context.ellipse(0, 0, projectedRadiusX, projectedRadiusY, 0, 0, Math.PI * 2);
|
|
23252
|
+
context.fillStyle = '#f8fbff';
|
|
23253
|
+
context.fill();
|
|
23254
|
+
context.clip();
|
|
23255
|
+
const irisGradient = context.createRadialGradient(-projectedRadiusX * 0.2, -projectedRadiusY * 0.26, projectedRadiusX * 0.05, 0, 0, projectedRadiusX * 0.92);
|
|
23256
|
+
irisGradient.addColorStop(0, palette.highlight);
|
|
23257
|
+
irisGradient.addColorStop(0.56, palette.secondary);
|
|
23258
|
+
irisGradient.addColorStop(1, palette.shadow);
|
|
23259
|
+
context.beginPath();
|
|
23260
|
+
context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.62 * eyeStyle.irisScale, projectedRadiusY * 0.72 * eyeStyle.irisScale, 0, 0, Math.PI * 2);
|
|
23261
|
+
context.fillStyle = irisGradient;
|
|
23262
|
+
context.fill();
|
|
23263
|
+
context.beginPath();
|
|
23264
|
+
context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.15 * eyeStyle.pupilWidthScale, projectedRadiusY * 0.48 * eyeStyle.pupilHeightScale, 0, 0, Math.PI * 2);
|
|
23265
|
+
context.fillStyle = palette.ink;
|
|
23266
|
+
context.fill();
|
|
23267
|
+
context.beginPath();
|
|
23268
|
+
context.ellipse(pupilOffsetX - projectedRadiusX * 0.22, pupilOffsetY - projectedRadiusY * 0.24, projectedRadiusX * 0.12, projectedRadiusY * 0.14, 0, 0, Math.PI * 2);
|
|
23269
|
+
context.fillStyle = '#ffffff';
|
|
23270
|
+
context.fill();
|
|
23271
|
+
context.restore();
|
|
23272
|
+
context.save();
|
|
23273
|
+
context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
|
|
23274
|
+
context.rotate(rotation);
|
|
23275
|
+
context.beginPath();
|
|
23276
|
+
context.ellipse(0, 0, projectedRadiusX, projectedRadiusY, 0, 0, Math.PI * 2);
|
|
23277
|
+
context.strokeStyle = `${palette.shadow}cc`;
|
|
23278
|
+
context.lineWidth = projectedRadiusX * 0.16;
|
|
23279
|
+
context.stroke();
|
|
23280
|
+
context.beginPath();
|
|
23281
|
+
context.moveTo(-projectedRadiusX * 0.88, -projectedRadiusY * eyeStyle.upperLidInsetRatio);
|
|
23282
|
+
context.quadraticCurveTo(0, -projectedRadiusY * (eyeStyle.upperLidArchRatio - interaction.gazeY * 0.16 + interaction.intensity * 0.08), projectedRadiusX * 0.88, -projectedRadiusY * eyeStyle.upperLidInsetRatio);
|
|
23283
|
+
context.strokeStyle = `${palette.shadow}73`;
|
|
23284
|
+
context.lineWidth = projectedRadiusX * 0.14;
|
|
23285
|
+
context.lineCap = 'round';
|
|
23286
|
+
context.stroke();
|
|
23287
|
+
if (eyeStyle.lowerLidOpacity > 0) {
|
|
23288
|
+
context.beginPath();
|
|
23289
|
+
context.moveTo(-projectedRadiusX * 0.74, projectedRadiusY * 0.2);
|
|
23290
|
+
context.quadraticCurveTo(0, projectedRadiusY * 0.38, projectedRadiusX * 0.74, projectedRadiusY * 0.2);
|
|
23291
|
+
context.strokeStyle = `${palette.highlight}${formatAlphaHex(eyeStyle.lowerLidOpacity)}`;
|
|
23292
|
+
context.lineWidth = projectedRadiusX * 0.08;
|
|
23293
|
+
context.lineCap = 'round';
|
|
23294
|
+
context.stroke();
|
|
23295
|
+
}
|
|
23296
|
+
context.restore();
|
|
23297
|
+
}
|
|
23298
|
+
/**
|
|
23299
|
+
* Draws a subtle projected mouth arc across the front of the mantle.
|
|
23300
|
+
*
|
|
23301
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23302
|
+
*/
|
|
23303
|
+
function drawProjectedMouth(context, localPoints, center, rotationX, rotationY, sceneCenterX, sceneCenterY, palette, size) {
|
|
23304
|
+
const scenePoints = localPoints.map((localPoint) => transformScenePoint(localPoint, center, rotationX, rotationY));
|
|
23305
|
+
if (scenePoints.some((scenePoint) => scenePoint.z <= center.z)) {
|
|
23306
|
+
return;
|
|
23307
|
+
}
|
|
23308
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
23309
|
+
context.beginPath();
|
|
23310
|
+
context.moveTo(projectedPoints[0].x, projectedPoints[0].y);
|
|
23311
|
+
context.quadraticCurveTo(projectedPoints[1].x, projectedPoints[1].y, projectedPoints[2].x, projectedPoints[2].y);
|
|
23312
|
+
context.strokeStyle = `${palette.ink}b8`;
|
|
23313
|
+
context.lineWidth = Math.max(1.1, size * 0.009);
|
|
23314
|
+
context.lineCap = 'round';
|
|
23315
|
+
context.stroke();
|
|
23316
|
+
}
|
|
23317
|
+
/**
|
|
23318
|
+
* Draws one filled projected quad.
|
|
23319
|
+
*
|
|
23320
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23321
|
+
*/
|
|
23322
|
+
function drawProjectedQuad(context, corners, fillStyle) {
|
|
23323
|
+
context.beginPath();
|
|
23324
|
+
context.moveTo(corners[0].x, corners[0].y);
|
|
23325
|
+
context.lineTo(corners[1].x, corners[1].y);
|
|
23326
|
+
context.lineTo(corners[2].x, corners[2].y);
|
|
23327
|
+
context.lineTo(corners[3].x, corners[3].y);
|
|
23328
|
+
context.closePath();
|
|
23329
|
+
context.fillStyle = fillStyle;
|
|
23330
|
+
context.fill();
|
|
23331
|
+
}
|
|
23332
|
+
/**
|
|
23333
|
+
* Converts an opacity ratio into a two-digit hexadecimal alpha suffix.
|
|
23334
|
+
*
|
|
23335
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23336
|
+
*/
|
|
23337
|
+
function formatAlphaHex(opacity) {
|
|
23338
|
+
return Math.round(clampNumber$1(opacity, 0, 1) * 255)
|
|
23339
|
+
.toString(16)
|
|
23340
|
+
.padStart(2, '0');
|
|
23341
|
+
}
|
|
23342
|
+
|
|
22826
23343
|
/* eslint-disable no-magic-numbers */
|
|
22827
23344
|
/**
|
|
22828
23345
|
* Octopus avatar visual.
|
|
@@ -23591,6 +24108,7 @@
|
|
|
23591
24108
|
octopusAvatarVisual,
|
|
23592
24109
|
octopus2AvatarVisual,
|
|
23593
24110
|
octopus3AvatarVisual,
|
|
24111
|
+
octopus3dAvatarVisual,
|
|
23594
24112
|
asciiOctopusAvatarVisual,
|
|
23595
24113
|
minecraftAvatarVisual,
|
|
23596
24114
|
minecraft2AvatarVisual,
|
|
@@ -25784,16 +26302,22 @@
|
|
|
25784
26302
|
* Each teammate is listed with its tool name, TEAM instructions, and optional profile hints.
|
|
25785
26303
|
*/
|
|
25786
26304
|
function buildTeamSystemMessageBody(teamEntries) {
|
|
25787
|
-
const
|
|
25788
|
-
|
|
25789
|
-
|
|
25790
|
-
|
|
25791
|
-
|
|
25792
|
-
|
|
25793
|
-
|
|
25794
|
-
|
|
25795
|
-
|
|
25796
|
-
|
|
26305
|
+
const teammateSections = teamEntries.map((entry, index) => {
|
|
26306
|
+
const toolLine = `${index + 1}) ${entry.teammate.label} tool \`${entry.toolName}\``;
|
|
26307
|
+
const detailLines = collectTeamEntryDetails(entry).map(formatTeamEntryDetailLine);
|
|
26308
|
+
if (detailLines.length === 0) {
|
|
26309
|
+
return toolLine;
|
|
26310
|
+
}
|
|
26311
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
26312
|
+
${toolLine}
|
|
26313
|
+
${block(detailLines.join('\n'))}
|
|
26314
|
+
`);
|
|
26315
|
+
});
|
|
26316
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
26317
|
+
${block(TEAM_SYSTEM_MESSAGE_GUIDANCE_LINES.join('\n'))}
|
|
26318
|
+
|
|
26319
|
+
${block(teammateSections.join('\n\n'))}
|
|
26320
|
+
`);
|
|
25797
26321
|
}
|
|
25798
26322
|
/**
|
|
25799
26323
|
* Builds the model-visible description for one teammate tool.
|
|
@@ -33254,7 +33778,11 @@
|
|
|
33254
33778
|
if (examples.length === 0) {
|
|
33255
33779
|
return null;
|
|
33256
33780
|
}
|
|
33257
|
-
return
|
|
33781
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
33782
|
+
## Sample of communication with the agent:
|
|
33783
|
+
|
|
33784
|
+
${block(examples.join('\n\n'))}
|
|
33785
|
+
`);
|
|
33258
33786
|
}
|
|
33259
33787
|
/**
|
|
33260
33788
|
* Collects the individual lines used in the example interaction section.
|
|
@@ -33291,7 +33819,11 @@
|
|
|
33291
33819
|
function appendSystemMessageSection(requirements, section) {
|
|
33292
33820
|
return {
|
|
33293
33821
|
...requirements,
|
|
33294
|
-
systemMessage:
|
|
33822
|
+
systemMessage: _spaceTrim.spaceTrim((block) => `
|
|
33823
|
+
${block(requirements.systemMessage)}
|
|
33824
|
+
|
|
33825
|
+
${block(section)}
|
|
33826
|
+
`),
|
|
33295
33827
|
};
|
|
33296
33828
|
}
|
|
33297
33829
|
/**
|
|
@@ -36252,7 +36784,7 @@
|
|
|
36252
36784
|
lines = lines.map((line) => `${line}<br/>`);
|
|
36253
36785
|
return lines.join('\n');
|
|
36254
36786
|
},
|
|
36255
|
-
} /* <- Note: [🤛]
|
|
36787
|
+
}; /* <- Note: [🤛] */
|
|
36256
36788
|
|
|
36257
36789
|
/**
|
|
36258
36790
|
* Registration of transpiler
|