@promptbook/wizard 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 +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/esm/index.es.js
CHANGED
|
@@ -38,7 +38,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
38
38
|
* @generated
|
|
39
39
|
* @see https://github.com/webgptorg/promptbook
|
|
40
40
|
*/
|
|
41
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
41
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-71';
|
|
42
42
|
/**
|
|
43
43
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
44
44
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -5297,7 +5297,7 @@ const createDeepseekExecutionTools = Object.assign((options) => {
|
|
|
5297
5297
|
}, {
|
|
5298
5298
|
packageName: '@promptbook/deepseek',
|
|
5299
5299
|
className: 'DeepseekExecutionTools',
|
|
5300
|
-
}) /* <- Note: [🤛]
|
|
5300
|
+
}); /* <- Note: [🤛] */
|
|
5301
5301
|
// TODO: [🎶] Naming "constructor" vs "creator" vs "factory"
|
|
5302
5302
|
|
|
5303
5303
|
/**
|
|
@@ -5764,7 +5764,7 @@ const createGoogleExecutionTools = Object.assign((options) => {
|
|
|
5764
5764
|
}, {
|
|
5765
5765
|
packageName: '@promptbook/google',
|
|
5766
5766
|
className: 'GoogleExecutionTools',
|
|
5767
|
-
}) /* <- Note: [🤛]
|
|
5767
|
+
}); /* <- Note: [🤛] */
|
|
5768
5768
|
// TODO: !!!!! Rename to `createGoogleLlmExecutionTools`, `...GoogleLlmExecutionTools`
|
|
5769
5769
|
// TODO: [🎶] Naming "constructor" vs "creator" vs "factory"
|
|
5770
5770
|
|
|
@@ -10280,7 +10280,7 @@ const createOpenAiCompatibleExecutionTools = Object.assign((options) => {
|
|
|
10280
10280
|
}, {
|
|
10281
10281
|
packageName: '@promptbook/openai',
|
|
10282
10282
|
className: 'OpenAiCompatibleExecutionTools',
|
|
10283
|
-
}) /* <- Note: [🤛]
|
|
10283
|
+
}); /* <- Note: [🤛] */
|
|
10284
10284
|
/**
|
|
10285
10285
|
* Execution Tools for calling ONE SPECIFIC PRECONFIGURED OpenAI compatible provider
|
|
10286
10286
|
*
|
|
@@ -10802,11 +10802,11 @@ function capitalize(word) {
|
|
|
10802
10802
|
*/
|
|
10803
10803
|
function pipelineJsonToString(pipelineJson) {
|
|
10804
10804
|
const { title, pipelineUrl, bookVersion, description, parameters, tasks } = pipelineJson;
|
|
10805
|
-
let pipelineString =
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10805
|
+
let pipelineString = spaceTrim$1((block) => `
|
|
10806
|
+
# ${title}
|
|
10807
|
+
|
|
10808
|
+
${block(description || '')}
|
|
10809
|
+
`);
|
|
10810
10810
|
const commands = [];
|
|
10811
10811
|
if (pipelineUrl) {
|
|
10812
10812
|
commands.push(`PIPELINE URL ${pipelineUrl}`);
|
|
@@ -10822,20 +10822,17 @@ function pipelineJsonToString(pipelineJson) {
|
|
|
10822
10822
|
for (const parameter of parameters.filter(({ isOutput }) => isOutput)) {
|
|
10823
10823
|
commands.push(`OUTPUT PARAMETER ${taskParameterJsonToString(parameter)}`);
|
|
10824
10824
|
}
|
|
10825
|
-
pipelineString
|
|
10826
|
-
|
|
10825
|
+
pipelineString = spaceTrim$1((block) => `
|
|
10826
|
+
${block(pipelineString)}
|
|
10827
|
+
|
|
10828
|
+
${block(commands.map((command) => `- ${command}`).join('\n'))}
|
|
10829
|
+
`);
|
|
10827
10830
|
for (const task of tasks) {
|
|
10828
10831
|
const {
|
|
10829
10832
|
/* Note: Not using:> name, */
|
|
10830
10833
|
title, description,
|
|
10831
10834
|
/* Note: dependentParameterNames, */
|
|
10832
10835
|
jokerParameterNames: jokers, taskType, content, postprocessingFunctionNames: postprocessing, expectations, format, resultingParameterName, } = task;
|
|
10833
|
-
pipelineString += '\n\n';
|
|
10834
|
-
pipelineString += `## ${title}`;
|
|
10835
|
-
if (description) {
|
|
10836
|
-
pipelineString += '\n\n';
|
|
10837
|
-
pipelineString += description;
|
|
10838
|
-
}
|
|
10839
10836
|
const commands = [];
|
|
10840
10837
|
let contentLanguage = 'text';
|
|
10841
10838
|
if (taskType === 'PROMPT_TASK') {
|
|
@@ -10898,18 +10895,23 @@ function pipelineJsonToString(pipelineJson) {
|
|
|
10898
10895
|
commands.push(`FORMAT JSON`);
|
|
10899
10896
|
}
|
|
10900
10897
|
} /* not else */
|
|
10901
|
-
pipelineString
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10898
|
+
pipelineString = spaceTrim$1((block) => `
|
|
10899
|
+
${block(pipelineString)}
|
|
10900
|
+
|
|
10901
|
+
## ${title}
|
|
10902
|
+
|
|
10903
|
+
${block(description || '')}
|
|
10904
|
+
|
|
10905
|
+
${block(commands.map((command) => `- ${command}`).join('\n'))}
|
|
10906
|
+
|
|
10907
|
+
\`\`\`${contentLanguage}
|
|
10908
|
+
${block(spaceTrim$1(content))}
|
|
10909
|
+
\`\`\`
|
|
10910
|
+
|
|
10911
|
+
\`-> {${resultingParameterName}}\`
|
|
10912
|
+
`); // <- TODO: [main] !!3 If the parameter here has description, add it and use taskParameterJsonToString
|
|
10913
|
+
// <- TODO: [main] !!3 Escape
|
|
10914
|
+
// <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
|
|
10913
10915
|
}
|
|
10914
10916
|
return validatePipelineString(pipelineString);
|
|
10915
10917
|
}
|
|
@@ -21188,6 +21190,184 @@ function drawFractalCore(context, size, palette, timeMs, corePhase) {
|
|
|
21188
21190
|
context.restore();
|
|
21189
21191
|
}
|
|
21190
21192
|
|
|
21193
|
+
/* eslint-disable no-magic-numbers */
|
|
21194
|
+
/**
|
|
21195
|
+
* Default camera distance ratio shared by the proper-3D avatar visuals.
|
|
21196
|
+
*
|
|
21197
|
+
* @private helper of the 3D avatar visuals
|
|
21198
|
+
*/
|
|
21199
|
+
const DEFAULT_3D_CAMERA_DISTANCE_RATIO = 1.4;
|
|
21200
|
+
/**
|
|
21201
|
+
* Clamps one number into the provided range.
|
|
21202
|
+
*
|
|
21203
|
+
* @param value Input value.
|
|
21204
|
+
* @param minimumValue Inclusive lower bound.
|
|
21205
|
+
* @param maximumValue Inclusive upper bound.
|
|
21206
|
+
* @returns Clamped value.
|
|
21207
|
+
*
|
|
21208
|
+
* @private helper of the 3D avatar visuals
|
|
21209
|
+
*/
|
|
21210
|
+
function clampNumber$1(value, minimumValue, maximumValue) {
|
|
21211
|
+
return Math.min(maximumValue, Math.max(minimumValue, value));
|
|
21212
|
+
}
|
|
21213
|
+
/**
|
|
21214
|
+
* Rotates one point around the local Y axis.
|
|
21215
|
+
*
|
|
21216
|
+
* @param point Source point.
|
|
21217
|
+
* @param angle Rotation angle in radians.
|
|
21218
|
+
* @returns Rotated point.
|
|
21219
|
+
*
|
|
21220
|
+
* @private helper of the 3D avatar visuals
|
|
21221
|
+
*/
|
|
21222
|
+
function rotatePointAroundY(point, angle) {
|
|
21223
|
+
const cosine = Math.cos(angle);
|
|
21224
|
+
const sine = Math.sin(angle);
|
|
21225
|
+
return {
|
|
21226
|
+
x: point.x * cosine + point.z * sine,
|
|
21227
|
+
y: point.y,
|
|
21228
|
+
z: -point.x * sine + point.z * cosine,
|
|
21229
|
+
};
|
|
21230
|
+
}
|
|
21231
|
+
/**
|
|
21232
|
+
* Rotates one point around the local X axis.
|
|
21233
|
+
*
|
|
21234
|
+
* @param point Source point.
|
|
21235
|
+
* @param angle Rotation angle in radians.
|
|
21236
|
+
* @returns Rotated point.
|
|
21237
|
+
*
|
|
21238
|
+
* @private helper of the 3D avatar visuals
|
|
21239
|
+
*/
|
|
21240
|
+
function rotatePointAroundX(point, angle) {
|
|
21241
|
+
const cosine = Math.cos(angle);
|
|
21242
|
+
const sine = Math.sin(angle);
|
|
21243
|
+
return {
|
|
21244
|
+
x: point.x,
|
|
21245
|
+
y: point.y * cosine - point.z * sine,
|
|
21246
|
+
z: point.y * sine + point.z * cosine,
|
|
21247
|
+
};
|
|
21248
|
+
}
|
|
21249
|
+
/**
|
|
21250
|
+
* Applies the local rotations and translation to one scene point.
|
|
21251
|
+
*
|
|
21252
|
+
* @param localPoint Point in local object space.
|
|
21253
|
+
* @param center Object center in scene space.
|
|
21254
|
+
* @param rotationX Object pitch in radians.
|
|
21255
|
+
* @param rotationY Object yaw in radians.
|
|
21256
|
+
* @returns Transformed scene-space point.
|
|
21257
|
+
*
|
|
21258
|
+
* @private helper of the 3D avatar visuals
|
|
21259
|
+
*/
|
|
21260
|
+
function transformScenePoint(localPoint, center, rotationX, rotationY) {
|
|
21261
|
+
const yawedPoint = rotatePointAroundY(localPoint, rotationY);
|
|
21262
|
+
const pitchedPoint = rotatePointAroundX(yawedPoint, rotationX);
|
|
21263
|
+
return {
|
|
21264
|
+
x: center.x + pitchedPoint.x,
|
|
21265
|
+
y: center.y + pitchedPoint.y,
|
|
21266
|
+
z: center.z + pitchedPoint.z,
|
|
21267
|
+
};
|
|
21268
|
+
}
|
|
21269
|
+
/**
|
|
21270
|
+
* Projects one scene point into canvas coordinates.
|
|
21271
|
+
*
|
|
21272
|
+
* @param point Scene-space point.
|
|
21273
|
+
* @param size Canvas size in CSS pixels.
|
|
21274
|
+
* @param sceneCenterX Horizontal scene center.
|
|
21275
|
+
* @param sceneCenterY Vertical scene center.
|
|
21276
|
+
* @param cameraDistanceRatio Optional camera distance ratio.
|
|
21277
|
+
* @returns Projected point.
|
|
21278
|
+
*
|
|
21279
|
+
* @private helper of the 3D avatar visuals
|
|
21280
|
+
*/
|
|
21281
|
+
function projectScenePoint(point, size, sceneCenterX, sceneCenterY, cameraDistanceRatio = DEFAULT_3D_CAMERA_DISTANCE_RATIO) {
|
|
21282
|
+
const cameraDistance = size * cameraDistanceRatio;
|
|
21283
|
+
const perspectiveScale = cameraDistance / Math.max(cameraDistance - point.z, cameraDistance * 0.35);
|
|
21284
|
+
return {
|
|
21285
|
+
x: sceneCenterX + point.x * perspectiveScale,
|
|
21286
|
+
y: sceneCenterY + point.y * perspectiveScale,
|
|
21287
|
+
z: point.z,
|
|
21288
|
+
};
|
|
21289
|
+
}
|
|
21290
|
+
/**
|
|
21291
|
+
* Subtracts one 3D point from another.
|
|
21292
|
+
*
|
|
21293
|
+
* @param leftPoint Left point.
|
|
21294
|
+
* @param rightPoint Right point.
|
|
21295
|
+
* @returns Difference vector.
|
|
21296
|
+
*
|
|
21297
|
+
* @private helper of the 3D avatar visuals
|
|
21298
|
+
*/
|
|
21299
|
+
function subtractPoint3D(leftPoint, rightPoint) {
|
|
21300
|
+
return {
|
|
21301
|
+
x: leftPoint.x - rightPoint.x,
|
|
21302
|
+
y: leftPoint.y - rightPoint.y,
|
|
21303
|
+
z: leftPoint.z - rightPoint.z,
|
|
21304
|
+
};
|
|
21305
|
+
}
|
|
21306
|
+
/**
|
|
21307
|
+
* Computes the 3D cross product of two vectors.
|
|
21308
|
+
*
|
|
21309
|
+
* @param leftVector Left vector.
|
|
21310
|
+
* @param rightVector Right vector.
|
|
21311
|
+
* @returns Cross product.
|
|
21312
|
+
*
|
|
21313
|
+
* @private helper of the 3D avatar visuals
|
|
21314
|
+
*/
|
|
21315
|
+
function crossProduct3D(leftVector, rightVector) {
|
|
21316
|
+
return {
|
|
21317
|
+
x: leftVector.y * rightVector.z - leftVector.z * rightVector.y,
|
|
21318
|
+
y: leftVector.z * rightVector.x - leftVector.x * rightVector.z,
|
|
21319
|
+
z: leftVector.x * rightVector.y - leftVector.y * rightVector.x,
|
|
21320
|
+
};
|
|
21321
|
+
}
|
|
21322
|
+
/**
|
|
21323
|
+
* Computes the 3D dot product of two vectors.
|
|
21324
|
+
*
|
|
21325
|
+
* @param leftVector Left vector.
|
|
21326
|
+
* @param rightVector Right vector.
|
|
21327
|
+
* @returns Dot product.
|
|
21328
|
+
*
|
|
21329
|
+
* @private helper of the 3D avatar visuals
|
|
21330
|
+
*/
|
|
21331
|
+
function dotProduct3D(leftVector, rightVector) {
|
|
21332
|
+
return leftVector.x * rightVector.x + leftVector.y * rightVector.y + leftVector.z * rightVector.z;
|
|
21333
|
+
}
|
|
21334
|
+
/**
|
|
21335
|
+
* Normalizes one 3D vector while keeping zero vectors stable.
|
|
21336
|
+
*
|
|
21337
|
+
* @param vector Source vector.
|
|
21338
|
+
* @returns Normalized vector.
|
|
21339
|
+
*
|
|
21340
|
+
* @private helper of the 3D avatar visuals
|
|
21341
|
+
*/
|
|
21342
|
+
function normalizeVector3(vector) {
|
|
21343
|
+
const length = Math.hypot(vector.x, vector.y, vector.z);
|
|
21344
|
+
if (length === 0) {
|
|
21345
|
+
return vector;
|
|
21346
|
+
}
|
|
21347
|
+
return {
|
|
21348
|
+
x: vector.x / length,
|
|
21349
|
+
y: vector.y / length,
|
|
21350
|
+
z: vector.z / length,
|
|
21351
|
+
};
|
|
21352
|
+
}
|
|
21353
|
+
/**
|
|
21354
|
+
* Measures the perimeter of one projected quad.
|
|
21355
|
+
*
|
|
21356
|
+
* @param corners Quad corners.
|
|
21357
|
+
* @returns Perimeter length.
|
|
21358
|
+
*
|
|
21359
|
+
* @private helper of the 3D avatar visuals
|
|
21360
|
+
*/
|
|
21361
|
+
function getProjectedQuadPerimeter(corners) {
|
|
21362
|
+
let perimeter = 0;
|
|
21363
|
+
for (let cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
|
|
21364
|
+
const currentCorner = corners[cornerIndex];
|
|
21365
|
+
const nextCorner = corners[(cornerIndex + 1) % corners.length];
|
|
21366
|
+
perimeter += Math.hypot(nextCorner.x - currentCorner.x, nextCorner.y - currentCorner.y);
|
|
21367
|
+
}
|
|
21368
|
+
return perimeter;
|
|
21369
|
+
}
|
|
21370
|
+
|
|
21191
21371
|
/* eslint-disable no-magic-numbers */
|
|
21192
21372
|
/**
|
|
21193
21373
|
* Builds the seeded six-face texture pack used by the Minecraft-style head cuboid.
|
|
@@ -21360,18 +21540,12 @@ function fillTextureRect(texture, x, y, width, height, color) {
|
|
|
21360
21540
|
}
|
|
21361
21541
|
|
|
21362
21542
|
/* eslint-disable no-magic-numbers */
|
|
21363
|
-
/**
|
|
21364
|
-
* Fixed scene camera distance used for the proper-3D projection.
|
|
21365
|
-
*
|
|
21366
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21367
|
-
*/
|
|
21368
|
-
const CAMERA_DISTANCE_RATIO = 1.4;
|
|
21369
21543
|
/**
|
|
21370
21544
|
* Shared light direction used to shade projected cuboid faces.
|
|
21371
21545
|
*
|
|
21372
21546
|
* @private helper of `minecraft2AvatarVisual`
|
|
21373
21547
|
*/
|
|
21374
|
-
const LIGHT_DIRECTION = normalizeVector3({
|
|
21548
|
+
const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
21375
21549
|
x: 0.4,
|
|
21376
21550
|
y: -0.65,
|
|
21377
21551
|
z: 0.92,
|
|
@@ -21583,7 +21757,7 @@ function resolveVisibleCuboidFaces(cuboid, size, sceneCenterX, sceneCenterY) {
|
|
|
21583
21757
|
corners: projectedCorners,
|
|
21584
21758
|
texture: faceDefinition.texture,
|
|
21585
21759
|
averageDepth: transformedCorners.reduce((depthSum, corner) => depthSum + corner.z, 0) / transformedCorners.length,
|
|
21586
|
-
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION), -1, 1),
|
|
21760
|
+
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$1), -1, 1),
|
|
21587
21761
|
outlineColor: cuboid.outlineColor,
|
|
21588
21762
|
};
|
|
21589
21763
|
});
|
|
@@ -21610,7 +21784,7 @@ function drawTexturedProjectedFace(context, face) {
|
|
|
21610
21784
|
const endX = (columnIndex + 1) / columns;
|
|
21611
21785
|
const startY = rowIndex / rows;
|
|
21612
21786
|
const endY = (rowIndex + 1) / rows;
|
|
21613
|
-
drawProjectedQuad(context, [
|
|
21787
|
+
drawProjectedQuad$1(context, [
|
|
21614
21788
|
interpolateProjectedQuad(face.corners, startX, startY),
|
|
21615
21789
|
interpolateProjectedQuad(face.corners, endX, startY),
|
|
21616
21790
|
interpolateProjectedQuad(face.corners, endX, endY),
|
|
@@ -21619,10 +21793,10 @@ function drawTexturedProjectedFace(context, face) {
|
|
|
21619
21793
|
}
|
|
21620
21794
|
}
|
|
21621
21795
|
if (face.lightIntensity > 0) {
|
|
21622
|
-
drawProjectedQuad(context, face.corners, `rgba(255, 255, 255, ${0.15 * face.lightIntensity})`);
|
|
21796
|
+
drawProjectedQuad$1(context, face.corners, `rgba(255, 255, 255, ${0.15 * face.lightIntensity})`);
|
|
21623
21797
|
}
|
|
21624
21798
|
else if (face.lightIntensity < 0) {
|
|
21625
|
-
drawProjectedQuad(context, face.corners, `rgba(0, 0, 0, ${0.22 * Math.abs(face.lightIntensity)})`);
|
|
21799
|
+
drawProjectedQuad$1(context, face.corners, `rgba(0, 0, 0, ${0.22 * Math.abs(face.lightIntensity)})`);
|
|
21626
21800
|
}
|
|
21627
21801
|
context.save();
|
|
21628
21802
|
context.beginPath();
|
|
@@ -21646,7 +21820,7 @@ function drawTexturedProjectedFace(context, face) {
|
|
|
21646
21820
|
*
|
|
21647
21821
|
* @private helper of `minecraft2AvatarVisual`
|
|
21648
21822
|
*/
|
|
21649
|
-
function drawProjectedQuad(context, corners, fillStyle) {
|
|
21823
|
+
function drawProjectedQuad$1(context, corners, fillStyle) {
|
|
21650
21824
|
context.beginPath();
|
|
21651
21825
|
context.moveTo(corners[0].x, corners[0].y);
|
|
21652
21826
|
context.lineTo(corners[1].x, corners[1].y);
|
|
@@ -21688,175 +21862,6 @@ function interpolateProjectedPoint(startPoint, endPoint, ratio) {
|
|
|
21688
21862
|
z: startPoint.z + (endPoint.z - startPoint.z) * ratio,
|
|
21689
21863
|
};
|
|
21690
21864
|
}
|
|
21691
|
-
/**
|
|
21692
|
-
* Projects one rotated scene point into canvas coordinates.
|
|
21693
|
-
*
|
|
21694
|
-
* @param point Scene point.
|
|
21695
|
-
* @param size Canvas size in CSS pixels.
|
|
21696
|
-
* @param sceneCenterX Horizontal scene center.
|
|
21697
|
-
* @param sceneCenterY Vertical scene center.
|
|
21698
|
-
* @returns Projected point.
|
|
21699
|
-
*
|
|
21700
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21701
|
-
*/
|
|
21702
|
-
function projectScenePoint(point, size, sceneCenterX, sceneCenterY) {
|
|
21703
|
-
const cameraDistance = size * CAMERA_DISTANCE_RATIO;
|
|
21704
|
-
const perspectiveScale = cameraDistance / Math.max(cameraDistance - point.z, cameraDistance * 0.35);
|
|
21705
|
-
return {
|
|
21706
|
-
x: sceneCenterX + point.x * perspectiveScale,
|
|
21707
|
-
y: sceneCenterY + point.y * perspectiveScale,
|
|
21708
|
-
z: point.z,
|
|
21709
|
-
};
|
|
21710
|
-
}
|
|
21711
|
-
/**
|
|
21712
|
-
* Applies the local cuboid rotations and translation to one scene point.
|
|
21713
|
-
*
|
|
21714
|
-
* @param localPoint Point in cuboid-local space.
|
|
21715
|
-
* @param center Cuboid center in scene space.
|
|
21716
|
-
* @param rotationX Cuboid pitch in radians.
|
|
21717
|
-
* @param rotationY Cuboid yaw in radians.
|
|
21718
|
-
* @returns Transformed scene-space point.
|
|
21719
|
-
*
|
|
21720
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21721
|
-
*/
|
|
21722
|
-
function transformScenePoint(localPoint, center, rotationX, rotationY) {
|
|
21723
|
-
const yawedPoint = rotatePointAroundY(localPoint, rotationY);
|
|
21724
|
-
const pitchedPoint = rotatePointAroundX(yawedPoint, rotationX);
|
|
21725
|
-
return {
|
|
21726
|
-
x: center.x + pitchedPoint.x,
|
|
21727
|
-
y: center.y + pitchedPoint.y,
|
|
21728
|
-
z: center.z + pitchedPoint.z,
|
|
21729
|
-
};
|
|
21730
|
-
}
|
|
21731
|
-
/**
|
|
21732
|
-
* Rotates one point around the local Y axis.
|
|
21733
|
-
*
|
|
21734
|
-
* @param point Source point.
|
|
21735
|
-
* @param angle Rotation angle in radians.
|
|
21736
|
-
* @returns Rotated point.
|
|
21737
|
-
*
|
|
21738
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21739
|
-
*/
|
|
21740
|
-
function rotatePointAroundY(point, angle) {
|
|
21741
|
-
const cosine = Math.cos(angle);
|
|
21742
|
-
const sine = Math.sin(angle);
|
|
21743
|
-
return {
|
|
21744
|
-
x: point.x * cosine + point.z * sine,
|
|
21745
|
-
y: point.y,
|
|
21746
|
-
z: -point.x * sine + point.z * cosine,
|
|
21747
|
-
};
|
|
21748
|
-
}
|
|
21749
|
-
/**
|
|
21750
|
-
* Rotates one point around the local X axis.
|
|
21751
|
-
*
|
|
21752
|
-
* @param point Source point.
|
|
21753
|
-
* @param angle Rotation angle in radians.
|
|
21754
|
-
* @returns Rotated point.
|
|
21755
|
-
*
|
|
21756
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21757
|
-
*/
|
|
21758
|
-
function rotatePointAroundX(point, angle) {
|
|
21759
|
-
const cosine = Math.cos(angle);
|
|
21760
|
-
const sine = Math.sin(angle);
|
|
21761
|
-
return {
|
|
21762
|
-
x: point.x,
|
|
21763
|
-
y: point.y * cosine - point.z * sine,
|
|
21764
|
-
z: point.y * sine + point.z * cosine,
|
|
21765
|
-
};
|
|
21766
|
-
}
|
|
21767
|
-
/**
|
|
21768
|
-
* Subtracts one 3D point from another.
|
|
21769
|
-
*
|
|
21770
|
-
* @param leftPoint Left point.
|
|
21771
|
-
* @param rightPoint Right point.
|
|
21772
|
-
* @returns Difference vector.
|
|
21773
|
-
*
|
|
21774
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21775
|
-
*/
|
|
21776
|
-
function subtractPoint3D(leftPoint, rightPoint) {
|
|
21777
|
-
return {
|
|
21778
|
-
x: leftPoint.x - rightPoint.x,
|
|
21779
|
-
y: leftPoint.y - rightPoint.y,
|
|
21780
|
-
z: leftPoint.z - rightPoint.z,
|
|
21781
|
-
};
|
|
21782
|
-
}
|
|
21783
|
-
/**
|
|
21784
|
-
* Computes the 3D cross product of two vectors.
|
|
21785
|
-
*
|
|
21786
|
-
* @param leftVector Left vector.
|
|
21787
|
-
* @param rightVector Right vector.
|
|
21788
|
-
* @returns Cross product.
|
|
21789
|
-
*
|
|
21790
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21791
|
-
*/
|
|
21792
|
-
function crossProduct3D(leftVector, rightVector) {
|
|
21793
|
-
return {
|
|
21794
|
-
x: leftVector.y * rightVector.z - leftVector.z * rightVector.y,
|
|
21795
|
-
y: leftVector.z * rightVector.x - leftVector.x * rightVector.z,
|
|
21796
|
-
z: leftVector.x * rightVector.y - leftVector.y * rightVector.x,
|
|
21797
|
-
};
|
|
21798
|
-
}
|
|
21799
|
-
/**
|
|
21800
|
-
* Computes the 3D dot product of two vectors.
|
|
21801
|
-
*
|
|
21802
|
-
* @param leftVector Left vector.
|
|
21803
|
-
* @param rightVector Right vector.
|
|
21804
|
-
* @returns Dot product.
|
|
21805
|
-
*
|
|
21806
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21807
|
-
*/
|
|
21808
|
-
function dotProduct3D(leftVector, rightVector) {
|
|
21809
|
-
return leftVector.x * rightVector.x + leftVector.y * rightVector.y + leftVector.z * rightVector.z;
|
|
21810
|
-
}
|
|
21811
|
-
/**
|
|
21812
|
-
* Normalizes one 3D vector while keeping zero vectors stable.
|
|
21813
|
-
*
|
|
21814
|
-
* @param vector Source vector.
|
|
21815
|
-
* @returns Normalized vector.
|
|
21816
|
-
*
|
|
21817
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21818
|
-
*/
|
|
21819
|
-
function normalizeVector3(vector) {
|
|
21820
|
-
const length = Math.hypot(vector.x, vector.y, vector.z);
|
|
21821
|
-
if (length === 0) {
|
|
21822
|
-
return vector;
|
|
21823
|
-
}
|
|
21824
|
-
return {
|
|
21825
|
-
x: vector.x / length,
|
|
21826
|
-
y: vector.y / length,
|
|
21827
|
-
z: vector.z / length,
|
|
21828
|
-
};
|
|
21829
|
-
}
|
|
21830
|
-
/**
|
|
21831
|
-
* Clamps one number into the provided range.
|
|
21832
|
-
*
|
|
21833
|
-
* @param value Input value.
|
|
21834
|
-
* @param minimumValue Inclusive lower bound.
|
|
21835
|
-
* @param maximumValue Inclusive upper bound.
|
|
21836
|
-
* @returns Clamped value.
|
|
21837
|
-
*
|
|
21838
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21839
|
-
*/
|
|
21840
|
-
function clampNumber$1(value, minimumValue, maximumValue) {
|
|
21841
|
-
return Math.min(maximumValue, Math.max(minimumValue, value));
|
|
21842
|
-
}
|
|
21843
|
-
/**
|
|
21844
|
-
* Measures the perimeter of one projected quad.
|
|
21845
|
-
*
|
|
21846
|
-
* @param corners Quad corners.
|
|
21847
|
-
* @returns Perimeter length.
|
|
21848
|
-
*
|
|
21849
|
-
* @private helper of `minecraft2AvatarVisual`
|
|
21850
|
-
*/
|
|
21851
|
-
function getProjectedQuadPerimeter(corners) {
|
|
21852
|
-
let perimeter = 0;
|
|
21853
|
-
for (let cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
|
|
21854
|
-
const currentCorner = corners[cornerIndex];
|
|
21855
|
-
const nextCorner = corners[(cornerIndex + 1) % corners.length];
|
|
21856
|
-
perimeter += Math.hypot(nextCorner.x - currentCorner.x, nextCorner.y - currentCorner.y);
|
|
21857
|
-
}
|
|
21858
|
-
return perimeter;
|
|
21859
|
-
}
|
|
21860
21865
|
|
|
21861
21866
|
/* eslint-disable no-magic-numbers */
|
|
21862
21867
|
/**
|
|
@@ -22425,7 +22430,7 @@ function resolveSeededIntegerRange(random, minimumValue, maximumValue) {
|
|
|
22425
22430
|
*
|
|
22426
22431
|
* @private helper of `octopus3AvatarVisual`
|
|
22427
22432
|
*/
|
|
22428
|
-
function formatAlphaHex(opacity) {
|
|
22433
|
+
function formatAlphaHex$1(opacity) {
|
|
22429
22434
|
return Math.round(Math.min(1, Math.max(0, opacity)) * 255)
|
|
22430
22435
|
.toString(16)
|
|
22431
22436
|
.padStart(2, '0');
|
|
@@ -22804,7 +22809,7 @@ function drawSeededEye(context, centerX, centerY, radiusX, radiusY, rotation, pa
|
|
|
22804
22809
|
context.beginPath();
|
|
22805
22810
|
context.moveTo(-radiusX * 0.74, radiusY * 0.2);
|
|
22806
22811
|
context.quadraticCurveTo(0, radiusY * 0.38, radiusX * 0.74, radiusY * 0.2);
|
|
22807
|
-
context.strokeStyle = `${palette.highlight}${formatAlphaHex(eyeStyle.lowerLidOpacity)}`;
|
|
22812
|
+
context.strokeStyle = `${palette.highlight}${formatAlphaHex$1(eyeStyle.lowerLidOpacity)}`;
|
|
22808
22813
|
context.lineWidth = radiusX * 0.08;
|
|
22809
22814
|
context.lineCap = 'round';
|
|
22810
22815
|
context.stroke();
|
|
@@ -22812,6 +22817,518 @@ function drawSeededEye(context, centerX, centerY, radiusX, radiusY, rotation, pa
|
|
|
22812
22817
|
context.restore();
|
|
22813
22818
|
}
|
|
22814
22819
|
|
|
22820
|
+
/* eslint-disable no-magic-numbers */
|
|
22821
|
+
/**
|
|
22822
|
+
* Light direction used by the organic 3D octopus shading.
|
|
22823
|
+
*
|
|
22824
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
22825
|
+
*/
|
|
22826
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
22827
|
+
x: 0.48,
|
|
22828
|
+
y: -0.62,
|
|
22829
|
+
z: 0.94,
|
|
22830
|
+
});
|
|
22831
|
+
/**
|
|
22832
|
+
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
22833
|
+
*
|
|
22834
|
+
* @private built-in avatar visual
|
|
22835
|
+
*/
|
|
22836
|
+
const octopus3dAvatarVisual = {
|
|
22837
|
+
id: 'octopus3d',
|
|
22838
|
+
title: 'Octopus 3D',
|
|
22839
|
+
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
22840
|
+
isAnimated: true,
|
|
22841
|
+
supportsPointerTracking: true,
|
|
22842
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
22843
|
+
const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
|
|
22844
|
+
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
22845
|
+
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
22846
|
+
const animationPhase = animationRandom() * Math.PI * 2;
|
|
22847
|
+
const sceneCenterX = size * 0.5;
|
|
22848
|
+
const sceneCenterY = size * 0.56;
|
|
22849
|
+
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
22850
|
+
const mantleCenter = {
|
|
22851
|
+
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
22852
|
+
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
22853
|
+
z: interaction.intensity * size * 0.012,
|
|
22854
|
+
};
|
|
22855
|
+
const underbodyCenter = {
|
|
22856
|
+
x: mantleCenter.x * 0.86,
|
|
22857
|
+
y: mantleCenter.y + size * 0.168,
|
|
22858
|
+
z: mantleCenter.z - size * 0.018,
|
|
22859
|
+
};
|
|
22860
|
+
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
22861
|
+
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
22862
|
+
const mantleRadiusZ = size * morphologyProfile.body.bodyRadiusRatio * (0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
22863
|
+
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
22864
|
+
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
22865
|
+
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
22866
|
+
const bodyYaw = -0.18 +
|
|
22867
|
+
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
22868
|
+
interaction.bodyOffsetX * 0.18 +
|
|
22869
|
+
interaction.gazeX * 0.22;
|
|
22870
|
+
const bodyPitch = -0.08 +
|
|
22871
|
+
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
22872
|
+
interaction.bodyOffsetY * 0.08 -
|
|
22873
|
+
interaction.gazeY * 0.08;
|
|
22874
|
+
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
22875
|
+
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
22876
|
+
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
22877
|
+
center: mantleCenter,
|
|
22878
|
+
radiusX: mantleRadiusX,
|
|
22879
|
+
radiusY: mantleRadiusY,
|
|
22880
|
+
radiusZ: mantleRadiusZ,
|
|
22881
|
+
rotationX: headPitch,
|
|
22882
|
+
rotationY: headYaw,
|
|
22883
|
+
sceneCenterX,
|
|
22884
|
+
sceneCenterY,
|
|
22885
|
+
size,
|
|
22886
|
+
palette,
|
|
22887
|
+
verticalColorBias: 0,
|
|
22888
|
+
outlineColor: `${palette.highlight}7a`,
|
|
22889
|
+
});
|
|
22890
|
+
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
22891
|
+
center: underbodyCenter,
|
|
22892
|
+
radiusX: underbodyRadiusX,
|
|
22893
|
+
radiusY: underbodyRadiusY,
|
|
22894
|
+
radiusZ: underbodyRadiusZ,
|
|
22895
|
+
rotationX: bodyPitch,
|
|
22896
|
+
rotationY: bodyYaw,
|
|
22897
|
+
sceneCenterX,
|
|
22898
|
+
sceneCenterY,
|
|
22899
|
+
size,
|
|
22900
|
+
palette,
|
|
22901
|
+
verticalColorBias: 0.18,
|
|
22902
|
+
outlineColor: `${palette.shadow}8f`,
|
|
22903
|
+
});
|
|
22904
|
+
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
22905
|
+
createRandom,
|
|
22906
|
+
morphologyProfile,
|
|
22907
|
+
timeMs,
|
|
22908
|
+
size,
|
|
22909
|
+
center: underbodyCenter,
|
|
22910
|
+
radiusX: underbodyRadiusX,
|
|
22911
|
+
radiusY: underbodyRadiusY,
|
|
22912
|
+
radiusZ: underbodyRadiusZ,
|
|
22913
|
+
rotationX: bodyPitch,
|
|
22914
|
+
rotationY: bodyYaw,
|
|
22915
|
+
sceneCenterX,
|
|
22916
|
+
sceneCenterY,
|
|
22917
|
+
animationPhase,
|
|
22918
|
+
});
|
|
22919
|
+
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
22920
|
+
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
22921
|
+
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
22922
|
+
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
22923
|
+
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
22924
|
+
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
22925
|
+
drawAvatarFrame(context, size, palette);
|
|
22926
|
+
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
22927
|
+
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
22928
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
22929
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
22930
|
+
}
|
|
22931
|
+
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
22932
|
+
drawSurfacePatch(context, surfacePatch);
|
|
22933
|
+
}
|
|
22934
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
22935
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
22936
|
+
}
|
|
22937
|
+
drawProjectedEye(context, {
|
|
22938
|
+
x: -faceEyeSpacing,
|
|
22939
|
+
y: faceEyeYOffset,
|
|
22940
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
22941
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
|
|
22942
|
+
drawProjectedEye(context, {
|
|
22943
|
+
x: faceEyeSpacing,
|
|
22944
|
+
y: faceEyeYOffset,
|
|
22945
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
22946
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
|
|
22947
|
+
drawProjectedMouth(context, [
|
|
22948
|
+
{ x: -mouthHalfWidth, y: mouthY, z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY) },
|
|
22949
|
+
{
|
|
22950
|
+
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
22951
|
+
y: mouthY +
|
|
22952
|
+
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
22953
|
+
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
22954
|
+
interaction.gazeY * size * 0.01,
|
|
22955
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
22956
|
+
},
|
|
22957
|
+
{ x: mouthHalfWidth, y: mouthY, z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY) },
|
|
22958
|
+
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
22959
|
+
},
|
|
22960
|
+
};
|
|
22961
|
+
/**
|
|
22962
|
+
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
22963
|
+
*
|
|
22964
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
22965
|
+
*/
|
|
22966
|
+
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
22967
|
+
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);
|
|
22968
|
+
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
22969
|
+
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
22970
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
22971
|
+
context.fillStyle = glowGradient;
|
|
22972
|
+
context.fillRect(0, 0, size, size);
|
|
22973
|
+
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);
|
|
22974
|
+
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
22975
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
22976
|
+
context.fillStyle = lowerGradient;
|
|
22977
|
+
context.fillRect(0, 0, size, size);
|
|
22978
|
+
}
|
|
22979
|
+
/**
|
|
22980
|
+
* Draws the soft ground shadow below the octopus.
|
|
22981
|
+
*
|
|
22982
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
22983
|
+
*/
|
|
22984
|
+
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
22985
|
+
context.save();
|
|
22986
|
+
context.fillStyle = `${palette.shadow}66`;
|
|
22987
|
+
context.filter = `blur(${size * 0.022}px)`;
|
|
22988
|
+
context.beginPath();
|
|
22989
|
+
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);
|
|
22990
|
+
context.fill();
|
|
22991
|
+
context.restore();
|
|
22992
|
+
}
|
|
22993
|
+
/**
|
|
22994
|
+
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
22995
|
+
*
|
|
22996
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
22997
|
+
*/
|
|
22998
|
+
function resolveVisibleEllipsoidPatches(options) {
|
|
22999
|
+
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
23000
|
+
const latitudePatchCount = 10;
|
|
23001
|
+
const longitudePatchCount = 18;
|
|
23002
|
+
const surfacePatches = [];
|
|
23003
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
23004
|
+
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
23005
|
+
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
23006
|
+
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
23007
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
23008
|
+
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
23009
|
+
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
23010
|
+
const localCorners = [
|
|
23011
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
23012
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
23013
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
23014
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
23015
|
+
];
|
|
23016
|
+
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
23017
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
23018
|
+
if (surfaceNormal.z <= 0.01) {
|
|
23019
|
+
continue;
|
|
23020
|
+
}
|
|
23021
|
+
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
23022
|
+
surfacePatches.push({
|
|
23023
|
+
corners: projectedCorners,
|
|
23024
|
+
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
23025
|
+
transformedCorners.length,
|
|
23026
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
23027
|
+
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
23028
|
+
outlineColor,
|
|
23029
|
+
});
|
|
23030
|
+
}
|
|
23031
|
+
}
|
|
23032
|
+
return surfacePatches;
|
|
23033
|
+
}
|
|
23034
|
+
/**
|
|
23035
|
+
* Samples one point on an ellipsoid aligned to the local axes.
|
|
23036
|
+
*
|
|
23037
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23038
|
+
*/
|
|
23039
|
+
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
23040
|
+
const cosineLatitude = Math.cos(latitude);
|
|
23041
|
+
return {
|
|
23042
|
+
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
23043
|
+
y: Math.sin(latitude) * radiusY,
|
|
23044
|
+
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
23045
|
+
};
|
|
23046
|
+
}
|
|
23047
|
+
/**
|
|
23048
|
+
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
23049
|
+
*
|
|
23050
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23051
|
+
*/
|
|
23052
|
+
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
23053
|
+
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
23054
|
+
if (clampedVerticalProgress < 0.2) {
|
|
23055
|
+
return palette.highlight;
|
|
23056
|
+
}
|
|
23057
|
+
if (clampedVerticalProgress < 0.45) {
|
|
23058
|
+
return palette.secondary;
|
|
23059
|
+
}
|
|
23060
|
+
if (clampedVerticalProgress < 0.8) {
|
|
23061
|
+
return palette.primary;
|
|
23062
|
+
}
|
|
23063
|
+
return `${palette.shadow}f2`;
|
|
23064
|
+
}
|
|
23065
|
+
/**
|
|
23066
|
+
* Draws one projected mesh patch with organic shading.
|
|
23067
|
+
*
|
|
23068
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23069
|
+
*/
|
|
23070
|
+
function drawSurfacePatch(context, surfacePatch) {
|
|
23071
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
23072
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
23073
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
23074
|
+
}
|
|
23075
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
23076
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
23077
|
+
}
|
|
23078
|
+
context.save();
|
|
23079
|
+
context.beginPath();
|
|
23080
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
23081
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
23082
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
23083
|
+
}
|
|
23084
|
+
context.closePath();
|
|
23085
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
23086
|
+
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
23087
|
+
context.lineJoin = 'round';
|
|
23088
|
+
context.stroke();
|
|
23089
|
+
context.restore();
|
|
23090
|
+
}
|
|
23091
|
+
/**
|
|
23092
|
+
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
23093
|
+
*
|
|
23094
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23095
|
+
*/
|
|
23096
|
+
function createOctopusTentacleStrokes(options) {
|
|
23097
|
+
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
23098
|
+
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
23099
|
+
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
23100
|
+
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
23101
|
+
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
23102
|
+
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
23103
|
+
const lateralReach = size *
|
|
23104
|
+
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
23105
|
+
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
23106
|
+
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
23107
|
+
const anchorPoint = {
|
|
23108
|
+
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
23109
|
+
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
23110
|
+
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
23111
|
+
};
|
|
23112
|
+
const controlPointOne = {
|
|
23113
|
+
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
23114
|
+
y: anchorPoint.y + flowLength * 0.26,
|
|
23115
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
23116
|
+
};
|
|
23117
|
+
const controlPointTwo = {
|
|
23118
|
+
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
23119
|
+
y: anchorPoint.y + flowLength * 0.66,
|
|
23120
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
23121
|
+
};
|
|
23122
|
+
const endPoint = {
|
|
23123
|
+
x: anchorPoint.x +
|
|
23124
|
+
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
23125
|
+
sway * size * 0.028,
|
|
23126
|
+
y: anchorPoint.y + flowLength,
|
|
23127
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
23128
|
+
};
|
|
23129
|
+
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
23130
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
23131
|
+
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
23132
|
+
return {
|
|
23133
|
+
projectedPoints,
|
|
23134
|
+
averageDepth,
|
|
23135
|
+
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
23136
|
+
baseWidth: size *
|
|
23137
|
+
(0.019 +
|
|
23138
|
+
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
23139
|
+
tentacleRandom() * 0.003 +
|
|
23140
|
+
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
23141
|
+
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
23142
|
+
colorBias: tentacleRandom(),
|
|
23143
|
+
};
|
|
23144
|
+
});
|
|
23145
|
+
}
|
|
23146
|
+
/**
|
|
23147
|
+
* Samples one point on a cubic Bezier curve in 3D.
|
|
23148
|
+
*
|
|
23149
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23150
|
+
*/
|
|
23151
|
+
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
23152
|
+
const inverseProgress = 1 - progress;
|
|
23153
|
+
return {
|
|
23154
|
+
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
23155
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
23156
|
+
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
23157
|
+
progress * progress * progress * endPoint.x,
|
|
23158
|
+
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
23159
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
23160
|
+
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
23161
|
+
progress * progress * progress * endPoint.y,
|
|
23162
|
+
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
23163
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
23164
|
+
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
23165
|
+
progress * progress * progress * endPoint.z,
|
|
23166
|
+
};
|
|
23167
|
+
}
|
|
23168
|
+
/**
|
|
23169
|
+
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
23170
|
+
*
|
|
23171
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23172
|
+
*/
|
|
23173
|
+
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
23174
|
+
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
23175
|
+
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
23176
|
+
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
23177
|
+
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
23178
|
+
const progress = segmentIndex / projectedSegments;
|
|
23179
|
+
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
23180
|
+
context.beginPath();
|
|
23181
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
23182
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
23183
|
+
context.strokeStyle =
|
|
23184
|
+
tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
23185
|
+
context.lineWidth = width;
|
|
23186
|
+
context.lineCap = 'round';
|
|
23187
|
+
context.stroke();
|
|
23188
|
+
context.beginPath();
|
|
23189
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
23190
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
23191
|
+
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
23192
|
+
context.lineWidth = Math.max(1, width * 0.34);
|
|
23193
|
+
context.lineCap = 'round';
|
|
23194
|
+
context.stroke();
|
|
23195
|
+
}
|
|
23196
|
+
}
|
|
23197
|
+
/**
|
|
23198
|
+
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
23199
|
+
*
|
|
23200
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23201
|
+
*/
|
|
23202
|
+
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
23203
|
+
const normalizedX = x / radiusX;
|
|
23204
|
+
const normalizedY = y / radiusY;
|
|
23205
|
+
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
23206
|
+
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
23207
|
+
}
|
|
23208
|
+
/**
|
|
23209
|
+
* Draws one projected eye on the turned octopus mantle.
|
|
23210
|
+
*
|
|
23211
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23212
|
+
*/
|
|
23213
|
+
function drawProjectedEye(context, localCenter, radiusX, radiusY, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, phase, interaction, eyeStyle) {
|
|
23214
|
+
const centerScenePoint = transformScenePoint(localCenter, center, rotationX, rotationY);
|
|
23215
|
+
if (centerScenePoint.z <= center.z) {
|
|
23216
|
+
return;
|
|
23217
|
+
}
|
|
23218
|
+
const horizontalScenePoint = transformScenePoint({ x: localCenter.x + radiusX, y: localCenter.y, z: localCenter.z }, center, rotationX, rotationY);
|
|
23219
|
+
const verticalScenePoint = transformScenePoint({ x: localCenter.x, y: localCenter.y + radiusY, z: localCenter.z }, center, rotationX, rotationY);
|
|
23220
|
+
const projectedCenterPoint = projectScenePoint(centerScenePoint, size, sceneCenterX, sceneCenterY);
|
|
23221
|
+
const projectedHorizontalPoint = projectScenePoint(horizontalScenePoint, size, sceneCenterX, sceneCenterY);
|
|
23222
|
+
const projectedVerticalPoint = projectScenePoint(verticalScenePoint, size, sceneCenterX, sceneCenterY);
|
|
23223
|
+
const projectedRadiusX = Math.hypot(projectedHorizontalPoint.x - projectedCenterPoint.x, projectedHorizontalPoint.y - projectedCenterPoint.y);
|
|
23224
|
+
const projectedRadiusY = Math.hypot(projectedVerticalPoint.x - projectedCenterPoint.x, projectedVerticalPoint.y - projectedCenterPoint.y);
|
|
23225
|
+
if (projectedRadiusX < size * 0.008 || projectedRadiusY < size * 0.008) {
|
|
23226
|
+
return;
|
|
23227
|
+
}
|
|
23228
|
+
const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
|
|
23229
|
+
radiusX: projectedRadiusX,
|
|
23230
|
+
radiusY: projectedRadiusY,
|
|
23231
|
+
timeMs,
|
|
23232
|
+
phase,
|
|
23233
|
+
interaction,
|
|
23234
|
+
});
|
|
23235
|
+
const rotation = Math.atan2(projectedHorizontalPoint.y - projectedCenterPoint.y, projectedHorizontalPoint.x - projectedCenterPoint.x);
|
|
23236
|
+
context.save();
|
|
23237
|
+
context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
|
|
23238
|
+
context.rotate(rotation);
|
|
23239
|
+
context.beginPath();
|
|
23240
|
+
context.ellipse(0, 0, projectedRadiusX, projectedRadiusY, 0, 0, Math.PI * 2);
|
|
23241
|
+
context.fillStyle = '#f8fbff';
|
|
23242
|
+
context.fill();
|
|
23243
|
+
context.clip();
|
|
23244
|
+
const irisGradient = context.createRadialGradient(-projectedRadiusX * 0.2, -projectedRadiusY * 0.26, projectedRadiusX * 0.05, 0, 0, projectedRadiusX * 0.92);
|
|
23245
|
+
irisGradient.addColorStop(0, palette.highlight);
|
|
23246
|
+
irisGradient.addColorStop(0.56, palette.secondary);
|
|
23247
|
+
irisGradient.addColorStop(1, palette.shadow);
|
|
23248
|
+
context.beginPath();
|
|
23249
|
+
context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.62 * eyeStyle.irisScale, projectedRadiusY * 0.72 * eyeStyle.irisScale, 0, 0, Math.PI * 2);
|
|
23250
|
+
context.fillStyle = irisGradient;
|
|
23251
|
+
context.fill();
|
|
23252
|
+
context.beginPath();
|
|
23253
|
+
context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.15 * eyeStyle.pupilWidthScale, projectedRadiusY * 0.48 * eyeStyle.pupilHeightScale, 0, 0, Math.PI * 2);
|
|
23254
|
+
context.fillStyle = palette.ink;
|
|
23255
|
+
context.fill();
|
|
23256
|
+
context.beginPath();
|
|
23257
|
+
context.ellipse(pupilOffsetX - projectedRadiusX * 0.22, pupilOffsetY - projectedRadiusY * 0.24, projectedRadiusX * 0.12, projectedRadiusY * 0.14, 0, 0, Math.PI * 2);
|
|
23258
|
+
context.fillStyle = '#ffffff';
|
|
23259
|
+
context.fill();
|
|
23260
|
+
context.restore();
|
|
23261
|
+
context.save();
|
|
23262
|
+
context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
|
|
23263
|
+
context.rotate(rotation);
|
|
23264
|
+
context.beginPath();
|
|
23265
|
+
context.ellipse(0, 0, projectedRadiusX, projectedRadiusY, 0, 0, Math.PI * 2);
|
|
23266
|
+
context.strokeStyle = `${palette.shadow}cc`;
|
|
23267
|
+
context.lineWidth = projectedRadiusX * 0.16;
|
|
23268
|
+
context.stroke();
|
|
23269
|
+
context.beginPath();
|
|
23270
|
+
context.moveTo(-projectedRadiusX * 0.88, -projectedRadiusY * eyeStyle.upperLidInsetRatio);
|
|
23271
|
+
context.quadraticCurveTo(0, -projectedRadiusY * (eyeStyle.upperLidArchRatio - interaction.gazeY * 0.16 + interaction.intensity * 0.08), projectedRadiusX * 0.88, -projectedRadiusY * eyeStyle.upperLidInsetRatio);
|
|
23272
|
+
context.strokeStyle = `${palette.shadow}73`;
|
|
23273
|
+
context.lineWidth = projectedRadiusX * 0.14;
|
|
23274
|
+
context.lineCap = 'round';
|
|
23275
|
+
context.stroke();
|
|
23276
|
+
if (eyeStyle.lowerLidOpacity > 0) {
|
|
23277
|
+
context.beginPath();
|
|
23278
|
+
context.moveTo(-projectedRadiusX * 0.74, projectedRadiusY * 0.2);
|
|
23279
|
+
context.quadraticCurveTo(0, projectedRadiusY * 0.38, projectedRadiusX * 0.74, projectedRadiusY * 0.2);
|
|
23280
|
+
context.strokeStyle = `${palette.highlight}${formatAlphaHex(eyeStyle.lowerLidOpacity)}`;
|
|
23281
|
+
context.lineWidth = projectedRadiusX * 0.08;
|
|
23282
|
+
context.lineCap = 'round';
|
|
23283
|
+
context.stroke();
|
|
23284
|
+
}
|
|
23285
|
+
context.restore();
|
|
23286
|
+
}
|
|
23287
|
+
/**
|
|
23288
|
+
* Draws a subtle projected mouth arc across the front of the mantle.
|
|
23289
|
+
*
|
|
23290
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23291
|
+
*/
|
|
23292
|
+
function drawProjectedMouth(context, localPoints, center, rotationX, rotationY, sceneCenterX, sceneCenterY, palette, size) {
|
|
23293
|
+
const scenePoints = localPoints.map((localPoint) => transformScenePoint(localPoint, center, rotationX, rotationY));
|
|
23294
|
+
if (scenePoints.some((scenePoint) => scenePoint.z <= center.z)) {
|
|
23295
|
+
return;
|
|
23296
|
+
}
|
|
23297
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
23298
|
+
context.beginPath();
|
|
23299
|
+
context.moveTo(projectedPoints[0].x, projectedPoints[0].y);
|
|
23300
|
+
context.quadraticCurveTo(projectedPoints[1].x, projectedPoints[1].y, projectedPoints[2].x, projectedPoints[2].y);
|
|
23301
|
+
context.strokeStyle = `${palette.ink}b8`;
|
|
23302
|
+
context.lineWidth = Math.max(1.1, size * 0.009);
|
|
23303
|
+
context.lineCap = 'round';
|
|
23304
|
+
context.stroke();
|
|
23305
|
+
}
|
|
23306
|
+
/**
|
|
23307
|
+
* Draws one filled projected quad.
|
|
23308
|
+
*
|
|
23309
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23310
|
+
*/
|
|
23311
|
+
function drawProjectedQuad(context, corners, fillStyle) {
|
|
23312
|
+
context.beginPath();
|
|
23313
|
+
context.moveTo(corners[0].x, corners[0].y);
|
|
23314
|
+
context.lineTo(corners[1].x, corners[1].y);
|
|
23315
|
+
context.lineTo(corners[2].x, corners[2].y);
|
|
23316
|
+
context.lineTo(corners[3].x, corners[3].y);
|
|
23317
|
+
context.closePath();
|
|
23318
|
+
context.fillStyle = fillStyle;
|
|
23319
|
+
context.fill();
|
|
23320
|
+
}
|
|
23321
|
+
/**
|
|
23322
|
+
* Converts an opacity ratio into a two-digit hexadecimal alpha suffix.
|
|
23323
|
+
*
|
|
23324
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
23325
|
+
*/
|
|
23326
|
+
function formatAlphaHex(opacity) {
|
|
23327
|
+
return Math.round(clampNumber$1(opacity, 0, 1) * 255)
|
|
23328
|
+
.toString(16)
|
|
23329
|
+
.padStart(2, '0');
|
|
23330
|
+
}
|
|
23331
|
+
|
|
22815
23332
|
/* eslint-disable no-magic-numbers */
|
|
22816
23333
|
/**
|
|
22817
23334
|
* Octopus avatar visual.
|
|
@@ -23580,6 +24097,7 @@ const AVATAR_VISUALS = [
|
|
|
23580
24097
|
octopusAvatarVisual,
|
|
23581
24098
|
octopus2AvatarVisual,
|
|
23582
24099
|
octopus3AvatarVisual,
|
|
24100
|
+
octopus3dAvatarVisual,
|
|
23583
24101
|
asciiOctopusAvatarVisual,
|
|
23584
24102
|
minecraftAvatarVisual,
|
|
23585
24103
|
minecraft2AvatarVisual,
|
|
@@ -25773,16 +26291,22 @@ function resolveTeamTeammateLabels(teamContent, teammates) {
|
|
|
25773
26291
|
* Each teammate is listed with its tool name, TEAM instructions, and optional profile hints.
|
|
25774
26292
|
*/
|
|
25775
26293
|
function buildTeamSystemMessageBody(teamEntries) {
|
|
25776
|
-
const
|
|
25777
|
-
|
|
25778
|
-
|
|
25779
|
-
|
|
25780
|
-
|
|
25781
|
-
|
|
25782
|
-
|
|
25783
|
-
|
|
25784
|
-
|
|
25785
|
-
|
|
26294
|
+
const teammateSections = teamEntries.map((entry, index) => {
|
|
26295
|
+
const toolLine = `${index + 1}) ${entry.teammate.label} tool \`${entry.toolName}\``;
|
|
26296
|
+
const detailLines = collectTeamEntryDetails(entry).map(formatTeamEntryDetailLine);
|
|
26297
|
+
if (detailLines.length === 0) {
|
|
26298
|
+
return toolLine;
|
|
26299
|
+
}
|
|
26300
|
+
return spaceTrim$1((block) => `
|
|
26301
|
+
${toolLine}
|
|
26302
|
+
${block(detailLines.join('\n'))}
|
|
26303
|
+
`);
|
|
26304
|
+
});
|
|
26305
|
+
return spaceTrim$1((block) => `
|
|
26306
|
+
${block(TEAM_SYSTEM_MESSAGE_GUIDANCE_LINES.join('\n'))}
|
|
26307
|
+
|
|
26308
|
+
${block(teammateSections.join('\n\n'))}
|
|
26309
|
+
`);
|
|
25786
26310
|
}
|
|
25787
26311
|
/**
|
|
25788
26312
|
* Builds the model-visible description for one teammate tool.
|
|
@@ -33243,7 +33767,11 @@ function createExampleInteractionsContent(parseResult, samples) {
|
|
|
33243
33767
|
if (examples.length === 0) {
|
|
33244
33768
|
return null;
|
|
33245
33769
|
}
|
|
33246
|
-
return
|
|
33770
|
+
return spaceTrim$1((block) => `
|
|
33771
|
+
## Sample of communication with the agent:
|
|
33772
|
+
|
|
33773
|
+
${block(examples.join('\n\n'))}
|
|
33774
|
+
`);
|
|
33247
33775
|
}
|
|
33248
33776
|
/**
|
|
33249
33777
|
* Collects the individual lines used in the example interaction section.
|
|
@@ -33280,7 +33808,11 @@ function collectExampleInteractionLines(parseResult, samples) {
|
|
|
33280
33808
|
function appendSystemMessageSection(requirements, section) {
|
|
33281
33809
|
return {
|
|
33282
33810
|
...requirements,
|
|
33283
|
-
systemMessage:
|
|
33811
|
+
systemMessage: spaceTrim$1((block) => `
|
|
33812
|
+
${block(requirements.systemMessage)}
|
|
33813
|
+
|
|
33814
|
+
${block(section)}
|
|
33815
|
+
`),
|
|
33284
33816
|
};
|
|
33285
33817
|
}
|
|
33286
33818
|
/**
|
|
@@ -36241,7 +36773,7 @@ const FormattedBookInMarkdownTranspiler = {
|
|
|
36241
36773
|
lines = lines.map((line) => `${line}<br/>`);
|
|
36242
36774
|
return lines.join('\n');
|
|
36243
36775
|
},
|
|
36244
|
-
} /* <- Note: [🤛]
|
|
36776
|
+
}; /* <- Note: [🤛] */
|
|
36245
36777
|
|
|
36246
36778
|
/**
|
|
36247
36779
|
* Registration of transpiler
|