@promptbook/core 0.112.0-99 → 0.113.0-0
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/README.md +76 -44
- package/esm/index.es.js +2064 -158
- package/esm/index.es.js.map +1 -1
- package/esm/servers.d.ts +1 -9
- package/esm/src/_packages/components.index.d.ts +4 -0
- package/esm/src/_packages/core.index.d.ts +22 -2
- package/esm/src/_packages/node.index.d.ts +40 -0
- package/esm/src/_packages/types.index.d.ts +20 -0
- package/esm/src/avatars/avatarAnimationScheduler.d.ts +4 -0
- package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/esm/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
- package/esm/src/avatars/visuals/octopus3d4AvatarVisual.d.ts +7 -0
- package/esm/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -0
- package/esm/src/book-2.0/agent-source/agentSourceVisibility.d.ts +97 -0
- package/esm/src/book-2.0/agent-source/agentSourceVisibility.test.d.ts +1 -0
- package/esm/src/book-3.0/BookNodeAgentSource.d.ts +38 -0
- package/esm/src/book-3.0/CliAgent.d.ts +66 -0
- package/esm/src/book-3.0/CliAgent.test.d.ts +1 -0
- package/esm/src/book-3.0/LiteAgent.d.ts +68 -0
- package/esm/src/book-3.0/LiteAgent.test.d.ts +1 -0
- package/esm/src/book-3.0/agentFolderPaths.d.ts +30 -0
- package/esm/src/book-3.0/cliAgentEnv.d.ts +33 -0
- package/esm/src/book-components/BookEditor/BookEditor.d.ts +6 -5
- package/esm/src/book-components/BookEditor/BookEditorAboutPromptbookInformation.d.ts +12 -0
- package/esm/src/book-components/BookEditor/BookEditorBrowserConfig.d.ts +2 -0
- package/esm/src/book-components/BookEditor/BookEditorForClient.d.ts +7 -0
- package/esm/src/book-components/BookEditor/BookEditorMonacoTokenization.d.ts +2 -0
- package/esm/src/book-components/BookEditor/BookEditorTheme.d.ts +24 -0
- package/esm/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.d.ts +9 -0
- package/esm/src/book-components/BookEditor/useBookEditorMonacoLanguage.d.ts +1 -6
- package/esm/src/book-components/BookEditor/useBookEditorMonacoLifecycle.d.ts +1 -4
- package/esm/src/book-components/BookEditor/useBookEditorMonacoStyles.d.ts +2 -1
- package/esm/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
- package/esm/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
- package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
- package/esm/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
- package/esm/src/book-components/Chat/Chat/CitationIframePreview.d.ts +20 -0
- package/esm/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
- package/esm/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
- package/esm/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
- package/esm/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
- package/esm/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
- package/esm/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
- package/esm/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
- package/esm/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
- package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
- package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
- package/esm/src/book-components/Chat/utils/isVisibleChatToolCall.d.ts +10 -0
- package/esm/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
- package/esm/src/book-components/_common/Dropdown/Dropdown.d.ts +1 -1
- package/esm/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +1 -1
- package/esm/src/book-components/_common/Modal/Modal.d.ts +1 -1
- package/esm/src/book-components/icons/AboutIcon.d.ts +1 -1
- package/esm/src/book-components/icons/DownloadIcon.d.ts +1 -1
- package/esm/src/book-components/icons/ExitFullscreenIcon.d.ts +1 -1
- package/esm/src/book-components/icons/FullscreenIcon.d.ts +1 -1
- package/esm/src/cli/cli-commands/agent/agentCliOptions.d.ts +38 -0
- package/esm/src/cli/cli-commands/agent/chat.d.ts +10 -0
- package/esm/src/cli/cli-commands/agent/exec.d.ts +10 -0
- package/esm/src/cli/cli-commands/agent/run.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/agent-folder/agentProjectPaths.d.ts +2 -24
- package/esm/src/cli/cli-commands/agent.d.ts +14 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +23 -1
- package/esm/src/cli/cli-commands/agents-server/run.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +9 -2
- package/esm/src/cli/cli-commands/coder/ThinkingLevel.d.ts +1 -1
- package/esm/src/cli/cli-commands/coder/ensureCoderDeveloperAgentFile.d.ts +25 -0
- package/esm/src/cli/cli-commands/coder/find-unwritten.d.ts +10 -0
- package/esm/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.d.ts +2 -0
- package/esm/src/cli/cli-commands/coder/server.d.ts +13 -0
- package/esm/src/cli/cli-commands/coder/waitOptions.d.ts +14 -0
- package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +9 -25
- package/esm/src/collection/agent-collection/CreateAgentInput.d.ts +2 -1
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +22 -0
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.d.ts +21 -1
- package/esm/src/commitments/META_VISIBILITY/META_VISIBILITY.d.ts +27 -0
- package/esm/src/commitments/_common/teamInternalAgentAccess.d.ts +9 -1
- package/esm/src/commitments/index.d.ts +2 -1
- package/esm/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +1 -1
- package/esm/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +1 -1
- package/esm/src/scrapers/website/utils/createShowdownConverter.d.ts +2 -2
- package/esm/src/utils/isTimingSafeEqualString.d.ts +25 -0
- package/esm/src/utils/validators/url/isValidAgentUrl.d.ts +5 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +2075 -158
- package/umd/index.umd.js.map +1 -1
- package/umd/servers.d.ts +1 -9
- package/umd/src/_packages/components.index.d.ts +4 -0
- package/umd/src/_packages/core.index.d.ts +22 -2
- package/umd/src/_packages/node.index.d.ts +40 -0
- package/umd/src/_packages/types.index.d.ts +20 -0
- package/umd/src/avatars/avatarAnimationScheduler.d.ts +4 -0
- package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/umd/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
- package/umd/src/avatars/visuals/octopus3d4AvatarVisual.d.ts +7 -0
- package/umd/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -0
- package/umd/src/book-2.0/agent-source/agentSourceVisibility.d.ts +97 -0
- package/umd/src/book-2.0/agent-source/agentSourceVisibility.test.d.ts +1 -0
- package/umd/src/book-3.0/BookNodeAgentSource.d.ts +38 -0
- package/umd/src/book-3.0/CliAgent.d.ts +66 -0
- package/umd/src/book-3.0/CliAgent.test.d.ts +1 -0
- package/umd/src/book-3.0/LiteAgent.d.ts +68 -0
- package/umd/src/book-3.0/LiteAgent.test.d.ts +1 -0
- package/umd/src/book-3.0/agentFolderPaths.d.ts +30 -0
- package/umd/src/book-3.0/cliAgentEnv.d.ts +33 -0
- package/umd/src/book-components/BookEditor/BookEditor.d.ts +6 -5
- package/umd/src/book-components/BookEditor/BookEditorAboutPromptbookInformation.d.ts +12 -0
- package/umd/src/book-components/BookEditor/BookEditorBrowserConfig.d.ts +2 -0
- package/umd/src/book-components/BookEditor/BookEditorForClient.d.ts +7 -0
- package/umd/src/book-components/BookEditor/BookEditorMonacoTokenization.d.ts +2 -0
- package/umd/src/book-components/BookEditor/BookEditorTheme.d.ts +24 -0
- package/umd/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.d.ts +9 -0
- package/umd/src/book-components/BookEditor/useBookEditorMonacoLanguage.d.ts +1 -6
- package/umd/src/book-components/BookEditor/useBookEditorMonacoLifecycle.d.ts +1 -4
- package/umd/src/book-components/BookEditor/useBookEditorMonacoStyles.d.ts +2 -1
- package/umd/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
- package/umd/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
- package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
- package/umd/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
- package/umd/src/book-components/Chat/Chat/CitationIframePreview.d.ts +20 -0
- package/umd/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
- package/umd/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
- package/umd/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
- package/umd/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
- package/umd/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
- package/umd/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
- package/umd/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
- package/umd/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
- package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
- package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
- package/umd/src/book-components/Chat/utils/isVisibleChatToolCall.d.ts +10 -0
- package/umd/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
- package/umd/src/book-components/_common/Dropdown/Dropdown.d.ts +1 -1
- package/umd/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +1 -1
- package/umd/src/book-components/_common/Modal/Modal.d.ts +1 -1
- package/umd/src/book-components/icons/AboutIcon.d.ts +1 -1
- package/umd/src/book-components/icons/DownloadIcon.d.ts +1 -1
- package/umd/src/book-components/icons/ExitFullscreenIcon.d.ts +1 -1
- package/umd/src/book-components/icons/FullscreenIcon.d.ts +1 -1
- package/umd/src/cli/cli-commands/agent/agentCliOptions.d.ts +38 -0
- package/umd/src/cli/cli-commands/agent/chat.d.ts +10 -0
- package/umd/src/cli/cli-commands/agent/exec.d.ts +10 -0
- package/umd/src/cli/cli-commands/agent/run.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/agent-folder/agentProjectPaths.d.ts +2 -24
- package/umd/src/cli/cli-commands/agent.d.ts +14 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +23 -1
- package/umd/src/cli/cli-commands/agents-server/run.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +9 -2
- package/umd/src/cli/cli-commands/coder/ThinkingLevel.d.ts +1 -1
- package/umd/src/cli/cli-commands/coder/ensureCoderDeveloperAgentFile.d.ts +25 -0
- package/umd/src/cli/cli-commands/coder/find-unwritten.d.ts +10 -0
- package/umd/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.d.ts +2 -0
- package/umd/src/cli/cli-commands/coder/server.d.ts +13 -0
- package/umd/src/cli/cli-commands/coder/waitOptions.d.ts +14 -0
- package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +9 -25
- package/umd/src/collection/agent-collection/CreateAgentInput.d.ts +2 -1
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +22 -0
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.d.ts +21 -1
- package/umd/src/commitments/META_VISIBILITY/META_VISIBILITY.d.ts +27 -0
- package/umd/src/commitments/_common/teamInternalAgentAccess.d.ts +9 -1
- package/umd/src/commitments/index.d.ts +2 -1
- package/umd/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +1 -1
- package/umd/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +1 -1
- package/umd/src/scrapers/website/utils/createShowdownConverter.d.ts +2 -2
- package/umd/src/utils/isTimingSafeEqualString.d.ts +25 -0
- package/umd/src/utils/validators/url/isValidAgentUrl.d.ts +5 -0
- package/umd/src/version.d.ts +1 -1
package/umd/index.umd.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports', 'crypto-js', 'crypto-js/enc-hex', '
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-core"] = {}, global.
|
|
5
|
-
})(this, (function (exports,
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('spacetrim'), require('crypto-js'), require('crypto-js/enc-hex'), require('rxjs'), require('waitasecond'), require('crypto-js/sha256'), require('path'), require('mime-types'), require('papaparse'), require('moment'), require('crypto'), require('colors'), require('@openai/agents'), require('bottleneck'), require('openai')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'spacetrim', 'crypto-js', 'crypto-js/enc-hex', 'rxjs', 'waitasecond', 'crypto-js/sha256', 'path', 'mime-types', 'papaparse', 'moment', 'crypto', 'colors', '@openai/agents', 'bottleneck', 'openai'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-core"] = {}, global.spacetrim, global.CryptoJS, global.hexEncoder, global.rxjs, global.waitasecond, global.sha256, global.path, global.mimeTypes, global.papaparse, global.moment, global.crypto, global.colors, global.agents, global.Bottleneck, global.OpenAI));
|
|
5
|
+
})(this, (function (exports, spacetrim, CryptoJS, hexEncoder, rxjs, waitasecond, sha256, path, mimeTypes, papaparse, moment, crypto, colors, agents, Bottleneck, OpenAI) { 'use strict';
|
|
6
6
|
|
|
7
7
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
8
|
|
|
9
|
+
var CryptoJS__default = /*#__PURE__*/_interopDefaultLegacy(CryptoJS);
|
|
9
10
|
var hexEncoder__default = /*#__PURE__*/_interopDefaultLegacy(hexEncoder);
|
|
10
11
|
var sha256__default = /*#__PURE__*/_interopDefaultLegacy(sha256);
|
|
12
|
+
var papaparse__default = /*#__PURE__*/_interopDefaultLegacy(papaparse);
|
|
11
13
|
var moment__default = /*#__PURE__*/_interopDefaultLegacy(moment);
|
|
12
14
|
var colors__default = /*#__PURE__*/_interopDefaultLegacy(colors);
|
|
13
15
|
var Bottleneck__default = /*#__PURE__*/_interopDefaultLegacy(Bottleneck);
|
|
@@ -27,12 +29,26 @@
|
|
|
27
29
|
* @generated
|
|
28
30
|
* @see https://github.com/webgptorg/promptbook
|
|
29
31
|
*/
|
|
30
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.
|
|
32
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.113.0-0';
|
|
31
33
|
/**
|
|
32
34
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
33
35
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
34
36
|
*/
|
|
35
37
|
|
|
38
|
+
/**
|
|
39
|
+
* This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
|
|
40
|
+
*
|
|
41
|
+
* @public exported from `@promptbook/core`
|
|
42
|
+
*/
|
|
43
|
+
class ParseError extends Error {
|
|
44
|
+
constructor(message) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = 'ParseError';
|
|
47
|
+
Object.setPrototypeOf(this, ParseError.prototype);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// TODO: Maybe split `ParseError` and `ApplyError`
|
|
51
|
+
|
|
36
52
|
/**
|
|
37
53
|
* Trims string from all 4 sides
|
|
38
54
|
*
|
|
@@ -45,6 +61,181 @@
|
|
|
45
61
|
*/
|
|
46
62
|
const spaceTrim = spacetrim.spaceTrim;
|
|
47
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Supported visibility states for persisted agents.
|
|
66
|
+
*
|
|
67
|
+
* @public exported from `@promptbook/core`
|
|
68
|
+
*/
|
|
69
|
+
const AGENT_VISIBILITY_VALUES = ['PRIVATE', 'UNLISTED', 'PUBLIC'];
|
|
70
|
+
/**
|
|
71
|
+
* Fallback visibility used when no valid value is configured.
|
|
72
|
+
*
|
|
73
|
+
* @public exported from `@promptbook/core`
|
|
74
|
+
*/
|
|
75
|
+
const DEFAULT_AGENT_VISIBILITY = 'UNLISTED';
|
|
76
|
+
/**
|
|
77
|
+
* Matches a single-line `META VISIBILITY` commitment in book source.
|
|
78
|
+
*/
|
|
79
|
+
const META_VISIBILITY_LINE_PATTERN = /^(\s*)META\s+VISIBILITY\b([\s\S]*)$/iu;
|
|
80
|
+
/**
|
|
81
|
+
* Returns `true` when the value is one of supported visibility states.
|
|
82
|
+
*
|
|
83
|
+
* @param value - Raw value to validate.
|
|
84
|
+
* @returns Whether the value is a valid `AgentVisibility`.
|
|
85
|
+
*
|
|
86
|
+
* @public exported from `@promptbook/core`
|
|
87
|
+
*/
|
|
88
|
+
function isAgentVisibility(value) {
|
|
89
|
+
return typeof value === 'string' && AGENT_VISIBILITY_VALUES.includes(value);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Normalizes raw visibility text into a supported value.
|
|
93
|
+
*
|
|
94
|
+
* @param value - Raw visibility value.
|
|
95
|
+
* @returns Normalized visibility, or `null` when invalid.
|
|
96
|
+
*
|
|
97
|
+
* @public exported from `@promptbook/core`
|
|
98
|
+
*/
|
|
99
|
+
function normalizeAgentVisibility(value) {
|
|
100
|
+
if (typeof value !== 'string') {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const normalized = value.trim().toUpperCase();
|
|
104
|
+
return isAgentVisibility(normalized) ? normalized : null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Parses visibility from an unknown value with a safe fallback.
|
|
108
|
+
*
|
|
109
|
+
* @param value - Raw visibility value.
|
|
110
|
+
* @param fallback - Fallback when the value is invalid.
|
|
111
|
+
* @returns Parsed visibility.
|
|
112
|
+
*
|
|
113
|
+
* @public exported from `@promptbook/core`
|
|
114
|
+
*/
|
|
115
|
+
function parseAgentVisibility(value, fallback = DEFAULT_AGENT_VISIBILITY) {
|
|
116
|
+
var _a;
|
|
117
|
+
return (_a = normalizeAgentVisibility(value)) !== null && _a !== void 0 ? _a : fallback;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Parses visibility and throws when the value is not supported.
|
|
121
|
+
*
|
|
122
|
+
* @param value - Raw visibility value.
|
|
123
|
+
* @param sourceLabel - Human-readable source used in the error message.
|
|
124
|
+
* @returns Parsed visibility.
|
|
125
|
+
*
|
|
126
|
+
* @public exported from `@promptbook/core`
|
|
127
|
+
*/
|
|
128
|
+
function parseAgentVisibilityStrict(value, sourceLabel = 'visibility') {
|
|
129
|
+
const visibility = normalizeAgentVisibility(value);
|
|
130
|
+
if (visibility) {
|
|
131
|
+
return visibility;
|
|
132
|
+
}
|
|
133
|
+
throw new ParseError(spaceTrim(`
|
|
134
|
+
Invalid ${sourceLabel}.
|
|
135
|
+
|
|
136
|
+
Value must be one of: ${AGENT_VISIBILITY_VALUES.map((allowedValue) => `\`${allowedValue}\``).join(', ')}.
|
|
137
|
+
`));
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Extracts the last `META VISIBILITY` value from an agent source.
|
|
141
|
+
*
|
|
142
|
+
* @param agentSource - Raw book source.
|
|
143
|
+
* @param options - Strict parsing options.
|
|
144
|
+
* @returns Normalized visibility, or `null` when no commitment is present.
|
|
145
|
+
*
|
|
146
|
+
* @public exported from `@promptbook/core`
|
|
147
|
+
*/
|
|
148
|
+
function parseAgentSourceVisibility(agentSource, options = {}) {
|
|
149
|
+
let visibilityContent = null;
|
|
150
|
+
for (const line of agentSource.split(/\r?\n/u)) {
|
|
151
|
+
const lineMatch = META_VISIBILITY_LINE_PATTERN.exec(line);
|
|
152
|
+
if (lineMatch) {
|
|
153
|
+
visibilityContent = lineMatch[2].trim();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (visibilityContent === null) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const visibility = normalizeAgentVisibility(visibilityContent);
|
|
160
|
+
if (visibility || !options.isStrict) {
|
|
161
|
+
return visibility;
|
|
162
|
+
}
|
|
163
|
+
return parseAgentVisibilityStrict(visibilityContent, '`META VISIBILITY` commitment');
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Returns whether an agent should be listed publicly in anonymous views.
|
|
167
|
+
*
|
|
168
|
+
* @param visibility - Agent visibility to evaluate.
|
|
169
|
+
* @returns `true` for publicly listed agents.
|
|
170
|
+
*
|
|
171
|
+
* @public exported from `@promptbook/core`
|
|
172
|
+
*/
|
|
173
|
+
function isPublicAgentVisibility(visibility) {
|
|
174
|
+
return visibility === 'PUBLIC';
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Returns the next visibility in UI rotation order.
|
|
178
|
+
*
|
|
179
|
+
* @param visibility - Current visibility.
|
|
180
|
+
* @returns Next visibility value.
|
|
181
|
+
*
|
|
182
|
+
* @public exported from `@promptbook/core`
|
|
183
|
+
*/
|
|
184
|
+
function getNextAgentVisibility(visibility) {
|
|
185
|
+
switch (visibility) {
|
|
186
|
+
case 'PRIVATE':
|
|
187
|
+
return 'UNLISTED';
|
|
188
|
+
case 'UNLISTED':
|
|
189
|
+
return 'PUBLIC';
|
|
190
|
+
case 'PUBLIC':
|
|
191
|
+
default:
|
|
192
|
+
return 'PRIVATE';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Inserts or replaces the `META VISIBILITY` commitment in a book source.
|
|
197
|
+
*
|
|
198
|
+
* @param agentSource - Raw book source.
|
|
199
|
+
* @param visibility - Visibility to persist.
|
|
200
|
+
* @returns Source with exactly one normalized `META VISIBILITY` line.
|
|
201
|
+
*
|
|
202
|
+
* @public exported from `@promptbook/core`
|
|
203
|
+
*/
|
|
204
|
+
function setAgentSourceVisibility(agentSource, visibility) {
|
|
205
|
+
var _a;
|
|
206
|
+
const normalizedVisibility = parseAgentVisibilityStrict(visibility, '`META VISIBILITY` commitment');
|
|
207
|
+
const lines = agentSource.split(/\r?\n/u);
|
|
208
|
+
const nextLines = [];
|
|
209
|
+
let isVisibilityLineWritten = false;
|
|
210
|
+
for (const line of lines) {
|
|
211
|
+
const lineMatch = META_VISIBILITY_LINE_PATTERN.exec(line);
|
|
212
|
+
if (!lineMatch) {
|
|
213
|
+
nextLines.push(line);
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (isVisibilityLineWritten) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
nextLines.push(`${(_a = lineMatch[1]) !== null && _a !== void 0 ? _a : ''}META VISIBILITY ${normalizedVisibility}`);
|
|
220
|
+
isVisibilityLineWritten = true;
|
|
221
|
+
}
|
|
222
|
+
if (!isVisibilityLineWritten) {
|
|
223
|
+
nextLines.splice(findMetaVisibilityInsertIndex(nextLines), 0, `META VISIBILITY ${normalizedVisibility}`);
|
|
224
|
+
}
|
|
225
|
+
return nextLines.join('\n');
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Finds the position after the first non-empty line, which is the agent title.
|
|
229
|
+
*
|
|
230
|
+
* @param lines - Source lines.
|
|
231
|
+
* @returns Insertion index for profile metadata.
|
|
232
|
+
*/
|
|
233
|
+
function findMetaVisibilityInsertIndex(lines) {
|
|
234
|
+
const titleLineIndex = lines.findIndex((line) => line.trim().length > 0);
|
|
235
|
+
return titleLineIndex === -1 ? 0 : titleLineIndex + 1;
|
|
236
|
+
}
|
|
237
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
238
|
+
|
|
48
239
|
/**
|
|
49
240
|
* Class implementing take chain.
|
|
50
241
|
*
|
|
@@ -1652,7 +1843,7 @@
|
|
|
1652
1843
|
* @public exported from `@promptbook/utils`
|
|
1653
1844
|
*/
|
|
1654
1845
|
function computeHash(value) {
|
|
1655
|
-
return
|
|
1846
|
+
return CryptoJS__default["default"].SHA256(hexEncoder__default["default"].parse(spacetrim.spaceTrim(valueToString(value)))).toString( /* hex */);
|
|
1656
1847
|
}
|
|
1657
1848
|
// TODO: [🥬][🥬] Use this ACRY
|
|
1658
1849
|
|
|
@@ -1768,20 +1959,6 @@
|
|
|
1768
1959
|
}
|
|
1769
1960
|
}
|
|
1770
1961
|
|
|
1771
|
-
/**
|
|
1772
|
-
* This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
|
|
1773
|
-
*
|
|
1774
|
-
* @public exported from `@promptbook/core`
|
|
1775
|
-
*/
|
|
1776
|
-
class ParseError extends Error {
|
|
1777
|
-
constructor(message) {
|
|
1778
|
-
super(message);
|
|
1779
|
-
this.name = 'ParseError';
|
|
1780
|
-
Object.setPrototypeOf(this, ParseError.prototype);
|
|
1781
|
-
}
|
|
1782
|
-
}
|
|
1783
|
-
// TODO: Maybe split `ParseError` and `ApplyError`
|
|
1784
|
-
|
|
1785
1962
|
/**
|
|
1786
1963
|
* Function isValidJsonString will tell you if the string is valid JSON or not
|
|
1787
1964
|
*
|
|
@@ -3772,7 +3949,7 @@
|
|
|
3772
3949
|
* @private internal helper function
|
|
3773
3950
|
*/
|
|
3774
3951
|
function $randomToken(randomness) {
|
|
3775
|
-
return
|
|
3952
|
+
return CryptoJS__default["default"].lib.WordArray.random(randomness).toString(CryptoJS__default["default"].enc.Hex);
|
|
3776
3953
|
}
|
|
3777
3954
|
// TODO: [🤶] Maybe export through `@promptbook/utils` or `@promptbook/random` package
|
|
3778
3955
|
// TODO: Maybe use nanoid instead https://github.com/ai/nanoid
|
|
@@ -5456,7 +5633,7 @@
|
|
|
5456
5633
|
* @public exported from `@promptbook/editable`
|
|
5457
5634
|
*/
|
|
5458
5635
|
function knowledgeSourceContentToName(knowledgeSourceContent) {
|
|
5459
|
-
const hash =
|
|
5636
|
+
const hash = CryptoJS__default["default"].SHA256(hexEncoder__default["default"].parse(JSON.stringify(knowledgeSourceContent)))
|
|
5460
5637
|
// <- TODO: [🥬] Encapsulate sha256 to some private utility function
|
|
5461
5638
|
.toString( /* hex */)
|
|
5462
5639
|
.substring(0, 20);
|
|
@@ -6369,7 +6546,7 @@
|
|
|
6369
6546
|
console.warn('CSV string contains carriage return characters, but in the CSV settings the `newline` setting does not include them. Autohealing the CSV string.');
|
|
6370
6547
|
value = value.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
6371
6548
|
}
|
|
6372
|
-
const csv =
|
|
6549
|
+
const csv = papaparse__default["default"].parse(value, settings);
|
|
6373
6550
|
return csv;
|
|
6374
6551
|
}
|
|
6375
6552
|
|
|
@@ -6454,10 +6631,10 @@
|
|
|
6454
6631
|
i > index ? { ...row, [outputParameterName]: PENDING_VALUE_PLACEHOLDER } : row,
|
|
6455
6632
|
);
|
|
6456
6633
|
*/
|
|
6457
|
-
await onProgress(
|
|
6634
|
+
await onProgress(papaparse__default["default"].unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS }));
|
|
6458
6635
|
}
|
|
6459
6636
|
}
|
|
6460
|
-
return
|
|
6637
|
+
return papaparse__default["default"].unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS });
|
|
6461
6638
|
},
|
|
6462
6639
|
},
|
|
6463
6640
|
{
|
|
@@ -6485,7 +6662,7 @@
|
|
|
6485
6662
|
return /* not await */ mapCallback({ [key]: value }, index, array.length);
|
|
6486
6663
|
}));
|
|
6487
6664
|
}));
|
|
6488
|
-
return
|
|
6665
|
+
return papaparse__default["default"].unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS });
|
|
6489
6666
|
},
|
|
6490
6667
|
},
|
|
6491
6668
|
],
|
|
@@ -9897,6 +10074,11 @@
|
|
|
9897
10074
|
* - `isValidAgentUrl` *(this one)* which tests just agent URL
|
|
9898
10075
|
* - `isValidPipelineUrl` which tests just pipeline URL
|
|
9899
10076
|
*
|
|
10077
|
+
* Note: This is a pure structural validator and does not block private/internal network
|
|
10078
|
+
* addresses. Callers that fetch the URL server-side from an untrusted network context must
|
|
10079
|
+
* additionally apply the `assertSafeUrl` SSRF guard from the Agents Server before any
|
|
10080
|
+
* outbound request.
|
|
10081
|
+
*
|
|
9900
10082
|
* @public exported from `@promptbook/utils`
|
|
9901
10083
|
*/
|
|
9902
10084
|
function isValidAgentUrl(url) {
|
|
@@ -9910,12 +10092,6 @@
|
|
|
9910
10092
|
// TODO: [🐠]
|
|
9911
10093
|
return false;
|
|
9912
10094
|
}
|
|
9913
|
-
/*
|
|
9914
|
-
Note: [👣][🧠] Is it secure to allow pipeline URLs on private and unsecured networks?
|
|
9915
|
-
if (isUrlOnPrivateNetwork(url)) {
|
|
9916
|
-
return false;
|
|
9917
|
-
}
|
|
9918
|
-
*/
|
|
9919
10095
|
return true;
|
|
9920
10096
|
}
|
|
9921
10097
|
// TODO: [🐠] Maybe more info why the URL is invalid
|
|
@@ -10091,8 +10267,11 @@
|
|
|
10091
10267
|
if (!trimmedContent) {
|
|
10092
10268
|
return requirements;
|
|
10093
10269
|
}
|
|
10094
|
-
|
|
10095
|
-
|
|
10270
|
+
const goalSection = spacetrim.spaceTrim((block) => `
|
|
10271
|
+
## Goal
|
|
10272
|
+
|
|
10273
|
+
${block(trimmedContent)}
|
|
10274
|
+
`);
|
|
10096
10275
|
const requirementsWithGoal = this.appendToSystemMessage(requirements, goalSection, '\n\n');
|
|
10097
10276
|
return this.appendToPromptSuffix(requirementsWithGoal, trimmedContent);
|
|
10098
10277
|
}
|
|
@@ -10614,8 +10793,11 @@
|
|
|
10614
10793
|
if (!trimmedContent) {
|
|
10615
10794
|
return requirements;
|
|
10616
10795
|
}
|
|
10617
|
-
|
|
10618
|
-
|
|
10796
|
+
const languageSection = spacetrim.spaceTrim((block) => `
|
|
10797
|
+
## Language
|
|
10798
|
+
|
|
10799
|
+
- Your language is ${block(trimmedContent)}
|
|
10800
|
+
`);
|
|
10619
10801
|
return this.appendToSystemMessage(requirements, languageSection, '\n\n');
|
|
10620
10802
|
}
|
|
10621
10803
|
}
|
|
@@ -13062,21 +13244,22 @@
|
|
|
13062
13244
|
* @private helper of `fractalAvatarVisual`
|
|
13063
13245
|
*/
|
|
13064
13246
|
function drawDragonCurveLayer(context, points, options) {
|
|
13065
|
-
const {
|
|
13247
|
+
const { primaryColor, secondaryColor, tertiaryColor, shadowColor, strokeWidth, timeMs, layerIndex } = options;
|
|
13066
13248
|
const firstPoint = points[0];
|
|
13067
13249
|
const lastPoint = points[points.length - 1];
|
|
13068
13250
|
const ribbonGradient = context.createLinearGradient(firstPoint.x, firstPoint.y, lastPoint.x, lastPoint.y);
|
|
13069
13251
|
ribbonGradient.addColorStop(0, `${primaryColor}f2`);
|
|
13070
13252
|
ribbonGradient.addColorStop(0.5, `${secondaryColor}e6`);
|
|
13071
13253
|
ribbonGradient.addColorStop(1, `${tertiaryColor}f2`);
|
|
13254
|
+
// Approximate the blurred shadow stroke with a wider semi-transparent stroke instead of
|
|
13255
|
+
// context.filter blur, which triggers a costly software rasterization pass every frame.
|
|
13072
13256
|
context.save();
|
|
13073
13257
|
context.beginPath();
|
|
13074
13258
|
tracePolyline(context, points);
|
|
13075
|
-
context.strokeStyle = `${shadowColor}
|
|
13076
|
-
context.lineWidth = strokeWidth *
|
|
13259
|
+
context.strokeStyle = `${shadowColor}48`;
|
|
13260
|
+
context.lineWidth = strokeWidth * 4.5;
|
|
13077
13261
|
context.lineJoin = 'round';
|
|
13078
13262
|
context.lineCap = 'round';
|
|
13079
|
-
context.filter = `blur(${size * 0.022}px)`;
|
|
13080
13263
|
context.stroke();
|
|
13081
13264
|
context.restore();
|
|
13082
13265
|
context.beginPath();
|
|
@@ -13538,7 +13721,7 @@
|
|
|
13538
13721
|
*
|
|
13539
13722
|
* @private helper of `minecraft2AvatarVisual`
|
|
13540
13723
|
*/
|
|
13541
|
-
const LIGHT_DIRECTION$
|
|
13724
|
+
const LIGHT_DIRECTION$4 = normalizeVector3({
|
|
13542
13725
|
x: 0.4,
|
|
13543
13726
|
y: -0.65,
|
|
13544
13727
|
z: 0.92,
|
|
@@ -13660,11 +13843,23 @@
|
|
|
13660
13843
|
* @private helper of `minecraft2AvatarVisual`
|
|
13661
13844
|
*/
|
|
13662
13845
|
function drawMinecraftShadow(context, size, palette, interaction, timeMs) {
|
|
13846
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.03;
|
|
13847
|
+
const cy = size * 0.85 + Math.sin(timeMs / 880) * size * 0.01;
|
|
13848
|
+
const rx = size * (0.16 + interaction.intensity * 0.015);
|
|
13849
|
+
const ry = size * 0.055;
|
|
13850
|
+
// Radial gradient approximates the blurry ellipse shadow without context.filter blur.
|
|
13663
13851
|
context.save();
|
|
13664
|
-
context.
|
|
13665
|
-
context.
|
|
13852
|
+
context.translate(cx, cy);
|
|
13853
|
+
context.scale(1, ry / rx);
|
|
13854
|
+
const blurRadius = rx * 1.4;
|
|
13855
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
13856
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
13857
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
13858
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
13859
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
13860
|
+
context.fillStyle = shadowGradient;
|
|
13666
13861
|
context.beginPath();
|
|
13667
|
-
context.
|
|
13862
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
13668
13863
|
context.fill();
|
|
13669
13864
|
context.restore();
|
|
13670
13865
|
}
|
|
@@ -13750,7 +13945,7 @@
|
|
|
13750
13945
|
corners: projectedCorners,
|
|
13751
13946
|
texture: faceDefinition.texture,
|
|
13752
13947
|
averageDepth: transformedCorners.reduce((depthSum, corner) => depthSum + corner.z, 0) / transformedCorners.length,
|
|
13753
|
-
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$
|
|
13948
|
+
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$4), -1, 1),
|
|
13754
13949
|
outlineColor: cuboid.outlineColor,
|
|
13755
13950
|
};
|
|
13756
13951
|
});
|
|
@@ -13888,13 +14083,27 @@
|
|
|
13888
14083
|
spotlight.addColorStop(1, `${palette.highlight}00`);
|
|
13889
14084
|
context.fillStyle = spotlight;
|
|
13890
14085
|
context.fillRect(0, 0, size, size);
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
14086
|
+
{
|
|
14087
|
+
// Radial gradient approximates the blurry ellipse shadow without context.filter blur.
|
|
14088
|
+
const cx = size * 0.5;
|
|
14089
|
+
const cy = size * 0.86;
|
|
14090
|
+
const rx = size * 0.2;
|
|
14091
|
+
const ry = size * 0.06;
|
|
14092
|
+
const blurRadius = rx * 1.4;
|
|
14093
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
14094
|
+
shadowGradient.addColorStop(0, 'rgba(0,0,0,0.28)');
|
|
14095
|
+
shadowGradient.addColorStop(0.45, 'rgba(0,0,0,0.14)');
|
|
14096
|
+
shadowGradient.addColorStop(0.8, 'rgba(0,0,0,0.05)');
|
|
14097
|
+
shadowGradient.addColorStop(1, 'rgba(0,0,0,0)');
|
|
14098
|
+
context.save();
|
|
14099
|
+
context.translate(cx, cy);
|
|
14100
|
+
context.scale(1, ry / rx);
|
|
14101
|
+
context.fillStyle = shadowGradient;
|
|
14102
|
+
context.beginPath();
|
|
14103
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
14104
|
+
context.fill();
|
|
14105
|
+
context.restore();
|
|
14106
|
+
}
|
|
13898
14107
|
drawVoxelCuboid(context, {
|
|
13899
14108
|
x: bodyX,
|
|
13900
14109
|
y: bodyY,
|
|
@@ -14423,7 +14632,7 @@
|
|
|
14423
14632
|
*
|
|
14424
14633
|
* @private helper of `octopus3AvatarVisual`
|
|
14425
14634
|
*/
|
|
14426
|
-
function formatAlphaHex$
|
|
14635
|
+
function formatAlphaHex$2(opacity) {
|
|
14427
14636
|
return Math.round(Math.min(1, Math.max(0, opacity)) * 255)
|
|
14428
14637
|
.toString(16)
|
|
14429
14638
|
.padStart(2, '0');
|
|
@@ -14802,7 +15011,7 @@
|
|
|
14802
15011
|
context.beginPath();
|
|
14803
15012
|
context.moveTo(-radiusX * 0.74, radiusY * 0.2);
|
|
14804
15013
|
context.quadraticCurveTo(0, radiusY * 0.38, radiusX * 0.74, radiusY * 0.2);
|
|
14805
|
-
context.strokeStyle = `${palette.highlight}${formatAlphaHex$
|
|
15014
|
+
context.strokeStyle = `${palette.highlight}${formatAlphaHex$2(eyeStyle.lowerLidOpacity)}`;
|
|
14806
15015
|
context.lineWidth = radiusX * 0.08;
|
|
14807
15016
|
context.lineCap = 'round';
|
|
14808
15017
|
context.stroke();
|
|
@@ -14883,7 +15092,7 @@
|
|
|
14883
15092
|
context.beginPath();
|
|
14884
15093
|
context.moveTo(-projectedRadiusX * 0.74, projectedRadiusY * 0.2);
|
|
14885
15094
|
context.quadraticCurveTo(0, projectedRadiusY * 0.38, projectedRadiusX * 0.74, projectedRadiusY * 0.2);
|
|
14886
|
-
context.strokeStyle = `${palette.highlight}${formatAlphaHex(eyeStyle.lowerLidOpacity)}`;
|
|
15095
|
+
context.strokeStyle = `${palette.highlight}${formatAlphaHex$1(eyeStyle.lowerLidOpacity)}`;
|
|
14887
15096
|
context.lineWidth = projectedRadiusX * 0.08;
|
|
14888
15097
|
context.lineCap = 'round';
|
|
14889
15098
|
context.stroke();
|
|
@@ -14929,7 +15138,7 @@
|
|
|
14929
15138
|
*
|
|
14930
15139
|
* @private helper of the 3D octopus avatar visuals
|
|
14931
15140
|
*/
|
|
14932
|
-
function formatAlphaHex(opacity) {
|
|
15141
|
+
function formatAlphaHex$1(opacity) {
|
|
14933
15142
|
return Math.round(clampNumber$1(opacity, 0, 1) * 255)
|
|
14934
15143
|
.toString(16)
|
|
14935
15144
|
.padStart(2, '0');
|
|
@@ -14941,11 +15150,40 @@
|
|
|
14941
15150
|
*
|
|
14942
15151
|
* @private helper of `octopus3dAvatarVisual`
|
|
14943
15152
|
*/
|
|
14944
|
-
const LIGHT_DIRECTION$
|
|
15153
|
+
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
14945
15154
|
x: 0.48,
|
|
14946
15155
|
y: -0.62,
|
|
14947
15156
|
z: 0.94,
|
|
14948
15157
|
});
|
|
15158
|
+
/**
|
|
15159
|
+
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
15160
|
+
*
|
|
15161
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
15162
|
+
*/
|
|
15163
|
+
const octopus3dStableStateCache = new WeakMap();
|
|
15164
|
+
/**
|
|
15165
|
+
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
15166
|
+
*
|
|
15167
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
15168
|
+
*/
|
|
15169
|
+
function getOctopus3dStableState(createRandom) {
|
|
15170
|
+
const cached = octopus3dStableStateCache.get(createRandom);
|
|
15171
|
+
if (cached !== undefined) {
|
|
15172
|
+
return cached;
|
|
15173
|
+
}
|
|
15174
|
+
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
15175
|
+
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
15176
|
+
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
15177
|
+
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
15178
|
+
const state = {
|
|
15179
|
+
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
15180
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
15181
|
+
leftEyePhaseOffset,
|
|
15182
|
+
rightEyePhaseOffset,
|
|
15183
|
+
};
|
|
15184
|
+
octopus3dStableStateCache.set(createRandom, state);
|
|
15185
|
+
return state;
|
|
15186
|
+
}
|
|
14949
15187
|
/**
|
|
14950
15188
|
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
14951
15189
|
*
|
|
@@ -14958,10 +15196,7 @@
|
|
|
14958
15196
|
isAnimated: true,
|
|
14959
15197
|
supportsPointerTracking: true,
|
|
14960
15198
|
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
14961
|
-
const morphologyProfile =
|
|
14962
|
-
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
14963
|
-
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
14964
|
-
const animationPhase = animationRandom() * Math.PI * 2;
|
|
15199
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
14965
15200
|
const sceneCenterX = size * 0.5;
|
|
14966
15201
|
const sceneCenterY = size * 0.56;
|
|
14967
15202
|
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
@@ -15058,12 +15293,12 @@
|
|
|
15058
15293
|
x: -faceEyeSpacing,
|
|
15059
15294
|
y: faceEyeYOffset,
|
|
15060
15295
|
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
15061
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase +
|
|
15296
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
15062
15297
|
drawProjectedOrganicEye(context, {
|
|
15063
15298
|
x: faceEyeSpacing,
|
|
15064
15299
|
y: faceEyeYOffset,
|
|
15065
15300
|
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
15066
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 +
|
|
15301
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
15067
15302
|
drawProjectedOrganicMouth(context, [
|
|
15068
15303
|
{
|
|
15069
15304
|
x: -mouthHalfWidth,
|
|
@@ -15107,14 +15342,28 @@
|
|
|
15107
15342
|
/**
|
|
15108
15343
|
* Draws the soft ground shadow below the octopus.
|
|
15109
15344
|
*
|
|
15345
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
15346
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
15347
|
+
*
|
|
15110
15348
|
* @private helper of `octopus3dAvatarVisual`
|
|
15111
15349
|
*/
|
|
15112
15350
|
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
15351
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
15352
|
+
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
15353
|
+
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
15354
|
+
const ry = size * 0.06;
|
|
15113
15355
|
context.save();
|
|
15114
|
-
context.
|
|
15115
|
-
context.
|
|
15356
|
+
context.translate(cx, cy);
|
|
15357
|
+
context.scale(1, ry / rx);
|
|
15358
|
+
const blurRadius = rx * 1.4;
|
|
15359
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
15360
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
15361
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
15362
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
15363
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
15364
|
+
context.fillStyle = shadowGradient;
|
|
15116
15365
|
context.beginPath();
|
|
15117
|
-
context.
|
|
15366
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
15118
15367
|
context.fill();
|
|
15119
15368
|
context.restore();
|
|
15120
15369
|
}
|
|
@@ -15151,7 +15400,7 @@
|
|
|
15151
15400
|
corners: projectedCorners,
|
|
15152
15401
|
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
15153
15402
|
transformedCorners.length,
|
|
15154
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
15403
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
15155
15404
|
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
15156
15405
|
outlineColor,
|
|
15157
15406
|
});
|
|
@@ -15340,11 +15589,40 @@
|
|
|
15340
15589
|
*
|
|
15341
15590
|
* @private helper of `octopus3d2AvatarVisual`
|
|
15342
15591
|
*/
|
|
15343
|
-
const LIGHT_DIRECTION = normalizeVector3({
|
|
15592
|
+
const LIGHT_DIRECTION$2 = normalizeVector3({
|
|
15344
15593
|
x: 0.38,
|
|
15345
15594
|
y: -0.6,
|
|
15346
15595
|
z: 0.98,
|
|
15347
15596
|
});
|
|
15597
|
+
/**
|
|
15598
|
+
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
15599
|
+
*
|
|
15600
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
15601
|
+
*/
|
|
15602
|
+
const octopus3d2StableStateCache = new WeakMap();
|
|
15603
|
+
/**
|
|
15604
|
+
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
15605
|
+
*
|
|
15606
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
15607
|
+
*/
|
|
15608
|
+
function getOctopus3d2StableState(createRandom) {
|
|
15609
|
+
const cached = octopus3d2StableStateCache.get(createRandom);
|
|
15610
|
+
if (cached !== undefined) {
|
|
15611
|
+
return cached;
|
|
15612
|
+
}
|
|
15613
|
+
const animationRandom = createRandom('octopus3d2-animation-profile');
|
|
15614
|
+
const eyeRandom = createRandom('octopus3d2-eye-profile');
|
|
15615
|
+
const leftEyePhaseOffset = eyeRandom() * 0.7;
|
|
15616
|
+
const rightEyePhaseOffset = eyeRandom() * 0.7;
|
|
15617
|
+
const state = {
|
|
15618
|
+
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
15619
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
15620
|
+
leftEyePhaseOffset,
|
|
15621
|
+
rightEyePhaseOffset,
|
|
15622
|
+
};
|
|
15623
|
+
octopus3d2StableStateCache.set(createRandom, state);
|
|
15624
|
+
return state;
|
|
15625
|
+
}
|
|
15348
15626
|
/**
|
|
15349
15627
|
* Octopus 3D 2 avatar visual.
|
|
15350
15628
|
*
|
|
@@ -15357,10 +15635,7 @@
|
|
|
15357
15635
|
isAnimated: true,
|
|
15358
15636
|
supportsPointerTracking: true,
|
|
15359
15637
|
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
15360
|
-
const morphologyProfile =
|
|
15361
|
-
const animationRandom = createRandom('octopus3d2-animation-profile');
|
|
15362
|
-
const eyeRandom = createRandom('octopus3d2-eye-profile');
|
|
15363
|
-
const animationPhase = animationRandom() * Math.PI * 2;
|
|
15638
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3d2StableState(createRandom);
|
|
15364
15639
|
const sceneCenterX = size * 0.5;
|
|
15365
15640
|
const sceneCenterY = size * 0.575;
|
|
15366
15641
|
const bob = Math.sin(timeMs / 940 + animationPhase) * size * 0.013;
|
|
@@ -15413,8 +15688,8 @@
|
|
|
15413
15688
|
const rightEyeLocalCenter = sampleBlobbyOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude);
|
|
15414
15689
|
const eyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.78;
|
|
15415
15690
|
const eyeRadiusY = eyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.92;
|
|
15416
|
-
drawProjectedOrganicEye(context, leftEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase +
|
|
15417
|
-
drawProjectedOrganicEye(context, rightEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.9 +
|
|
15691
|
+
drawProjectedOrganicEye(context, leftEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
15692
|
+
drawProjectedOrganicEye(context, rightEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.9 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
15418
15693
|
drawProjectedOrganicMouth(context, [
|
|
15419
15694
|
sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
|
|
15420
15695
|
sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
|
|
@@ -15443,54 +15718,118 @@
|
|
|
15443
15718
|
/**
|
|
15444
15719
|
* Draws the soft floor shadow that anchors the single mesh in the frame.
|
|
15445
15720
|
*
|
|
15721
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
15722
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
15723
|
+
*
|
|
15446
15724
|
* @private helper of `octopus3d2AvatarVisual`
|
|
15447
15725
|
*/
|
|
15448
15726
|
function drawBlobbyOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
|
|
15727
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.045;
|
|
15728
|
+
const cy = size * 0.88 + Math.sin(timeMs / 940) * size * 0.008;
|
|
15729
|
+
const rx = size * (0.18 + (morphologyProfile.body.horizontalStretch - 1) * 0.04 + interaction.intensity * 0.018);
|
|
15730
|
+
const ry = size * 0.062;
|
|
15449
15731
|
context.save();
|
|
15450
|
-
context.
|
|
15451
|
-
context.
|
|
15732
|
+
context.translate(cx, cy);
|
|
15733
|
+
context.scale(1, ry / rx);
|
|
15734
|
+
const blurRadius = rx * 1.4;
|
|
15735
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
15736
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
15737
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
15738
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
15739
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
15740
|
+
context.fillStyle = shadowGradient;
|
|
15452
15741
|
context.beginPath();
|
|
15453
|
-
context.
|
|
15742
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
15454
15743
|
context.fill();
|
|
15455
15744
|
context.restore();
|
|
15456
15745
|
}
|
|
15746
|
+
/**
|
|
15747
|
+
* Number of latitude segments used by the single blobby octopus mesh.
|
|
15748
|
+
*
|
|
15749
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
15750
|
+
*/
|
|
15751
|
+
const LATITUDE_PATCH_COUNT$2 = 12;
|
|
15752
|
+
/**
|
|
15753
|
+
* Number of longitude segments used by the single blobby octopus mesh.
|
|
15754
|
+
*
|
|
15755
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
15756
|
+
*/
|
|
15757
|
+
const LONGITUDE_PATCH_COUNT$2 = 24;
|
|
15457
15758
|
/**
|
|
15458
15759
|
* Resolves all visible projected patches for the single blobby octopus mesh.
|
|
15459
15760
|
*
|
|
15761
|
+
* Within a single frame, mesh corner samples and longitude-only lobe-wave values are
|
|
15762
|
+
* quantized to the patch grid and computed once each rather than re-evaluated for every
|
|
15763
|
+
* patch corner — the patch loop alone would call `sampleBlobbyOctopusSurfacePoint`
|
|
15764
|
+
* `latitudePatchCount * longitudePatchCount * 4` times without caching, even though most
|
|
15765
|
+
* corners are shared between neighboring patches.
|
|
15766
|
+
*
|
|
15460
15767
|
* @private helper of `octopus3d2AvatarVisual`
|
|
15461
15768
|
*/
|
|
15462
15769
|
function resolveVisibleBlobbyOctopusPatches(options) {
|
|
15463
15770
|
const { center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, morphologyProfile, animationPhase, timeMs, } = options;
|
|
15464
|
-
const latitudePatchCount =
|
|
15465
|
-
const longitudePatchCount =
|
|
15771
|
+
const latitudePatchCount = LATITUDE_PATCH_COUNT$2;
|
|
15772
|
+
const longitudePatchCount = LONGITUDE_PATCH_COUNT$2;
|
|
15466
15773
|
const surfacePatches = [];
|
|
15774
|
+
const latitudeBoundaries = new Float64Array(latitudePatchCount + 1);
|
|
15775
|
+
const longitudeBoundaries = new Float64Array(longitudePatchCount + 1);
|
|
15776
|
+
for (let boundaryIndex = 0; boundaryIndex <= latitudePatchCount; boundaryIndex++) {
|
|
15777
|
+
latitudeBoundaries[boundaryIndex] = -Math.PI / 2 + (boundaryIndex / latitudePatchCount) * Math.PI;
|
|
15778
|
+
}
|
|
15779
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
15780
|
+
longitudeBoundaries[boundaryIndex] = -Math.PI + (boundaryIndex / longitudePatchCount) * Math.PI * 2;
|
|
15781
|
+
}
|
|
15782
|
+
const cachedLobeWavesByCornerLongitude = new Float64Array(longitudePatchCount + 1);
|
|
15783
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
15784
|
+
cachedLobeWavesByCornerLongitude[boundaryIndex] = resolveLowerLobeWave(longitudeBoundaries[boundaryIndex], morphologyProfile, animationPhase, timeMs);
|
|
15785
|
+
}
|
|
15786
|
+
const cornerCount = (latitudePatchCount + 1) * (longitudePatchCount + 1);
|
|
15787
|
+
const transformedCornerSamples = new Array(cornerCount);
|
|
15788
|
+
for (let latitudeBoundaryIndex = 0; latitudeBoundaryIndex <= latitudePatchCount; latitudeBoundaryIndex++) {
|
|
15789
|
+
const cornerLatitude = latitudeBoundaries[latitudeBoundaryIndex];
|
|
15790
|
+
for (let longitudeBoundaryIndex = 0; longitudeBoundaryIndex <= longitudePatchCount; longitudeBoundaryIndex++) {
|
|
15791
|
+
const cornerLongitude = longitudeBoundaries[longitudeBoundaryIndex];
|
|
15792
|
+
const cornerIndex = latitudeBoundaryIndex * (longitudePatchCount + 1) + longitudeBoundaryIndex;
|
|
15793
|
+
const cornerSample = sampleBlobbyOctopusSurfacePointWithLongitudeCache(options, cornerLatitude, cornerLongitude, cachedLobeWavesByCornerLongitude[longitudeBoundaryIndex]);
|
|
15794
|
+
transformedCornerSamples[cornerIndex] = transformScenePoint(cornerSample, center, rotationX, rotationY);
|
|
15795
|
+
}
|
|
15796
|
+
}
|
|
15467
15797
|
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
15468
|
-
const startLatitude =
|
|
15469
|
-
const endLatitude =
|
|
15798
|
+
const startLatitude = latitudeBoundaries[latitudeIndex];
|
|
15799
|
+
const endLatitude = latitudeBoundaries[latitudeIndex + 1];
|
|
15470
15800
|
const centerLatitude = (startLatitude + endLatitude) / 2;
|
|
15471
15801
|
const verticalProgress = (Math.sin(centerLatitude) + 1) / 2;
|
|
15802
|
+
const startCornerRowOffset = latitudeIndex * (longitudePatchCount + 1);
|
|
15803
|
+
const endCornerRowOffset = (latitudeIndex + 1) * (longitudePatchCount + 1);
|
|
15472
15804
|
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
15473
|
-
const startLongitude =
|
|
15474
|
-
const endLongitude =
|
|
15805
|
+
const startLongitude = longitudeBoundaries[longitudeIndex];
|
|
15806
|
+
const endLongitude = longitudeBoundaries[longitudeIndex + 1];
|
|
15475
15807
|
const centerLongitude = (startLongitude + endLongitude) / 2;
|
|
15476
|
-
const
|
|
15477
|
-
|
|
15478
|
-
|
|
15479
|
-
|
|
15480
|
-
|
|
15808
|
+
const transformedCorners = [
|
|
15809
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex],
|
|
15810
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex + 1],
|
|
15811
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex + 1],
|
|
15812
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex],
|
|
15481
15813
|
];
|
|
15482
|
-
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
15483
15814
|
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
15484
15815
|
if (surfaceNormal.z <= 0.01) {
|
|
15485
15816
|
continue;
|
|
15486
15817
|
}
|
|
15487
|
-
const projectedCorners =
|
|
15818
|
+
const projectedCorners = [
|
|
15819
|
+
projectScenePoint(transformedCorners[0], size, sceneCenterX, sceneCenterY),
|
|
15820
|
+
projectScenePoint(transformedCorners[1], size, sceneCenterX, sceneCenterY),
|
|
15821
|
+
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
15822
|
+
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
15823
|
+
];
|
|
15488
15824
|
surfacePatches.push({
|
|
15489
15825
|
corners: projectedCorners,
|
|
15490
|
-
averageDepth: transformedCorners.
|
|
15491
|
-
transformedCorners.
|
|
15492
|
-
|
|
15493
|
-
|
|
15826
|
+
averageDepth: (transformedCorners[0].z +
|
|
15827
|
+
transformedCorners[1].z +
|
|
15828
|
+
transformedCorners[2].z +
|
|
15829
|
+
transformedCorners[3].z) /
|
|
15830
|
+
4,
|
|
15831
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$2), -1, 1),
|
|
15832
|
+
fillStyle: resolveBlobbySurfacePatchFillStyle$1(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), resolveLowerLobeWave(centerLongitude, morphologyProfile, animationPhase, timeMs)),
|
|
15494
15833
|
outlineColor: verticalProgress < 0.58 ? `${palette.highlight}73` : `${palette.shadow}8a`,
|
|
15495
15834
|
});
|
|
15496
15835
|
}
|
|
@@ -15506,12 +15845,21 @@
|
|
|
15506
15845
|
* @private helper of `octopus3d2AvatarVisual`
|
|
15507
15846
|
*/
|
|
15508
15847
|
function sampleBlobbyOctopusSurfacePoint(options, latitude, longitude) {
|
|
15848
|
+
const { morphologyProfile, animationPhase, timeMs } = options;
|
|
15849
|
+
return sampleBlobbyOctopusSurfacePointWithLongitudeCache(options, latitude, longitude, resolveLowerLobeWave(longitude, morphologyProfile, animationPhase, timeMs));
|
|
15850
|
+
}
|
|
15851
|
+
/**
|
|
15852
|
+
* Samples one point on the continuous Octopus 3D 2 surface using a precomputed lower-lobe wave
|
|
15853
|
+
* to skip the per-call trig evaluation for `latitudePatchCount + 1` longitude-shared corners.
|
|
15854
|
+
*
|
|
15855
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
15856
|
+
*/
|
|
15857
|
+
function sampleBlobbyOctopusSurfacePointWithLongitudeCache(options, latitude, longitude, lowerLobeWave) {
|
|
15509
15858
|
const { radiusX, radiusY, radiusZ, morphologyProfile, timeMs, animationPhase } = options;
|
|
15510
15859
|
const cosineLatitude = Math.max(0, Math.cos(latitude));
|
|
15511
15860
|
const verticalProgress = (Math.sin(latitude) + 1) / 2;
|
|
15512
15861
|
const upperBlend = Math.pow(1 - verticalProgress, 1.2);
|
|
15513
15862
|
const lowerBlend = Math.pow(verticalProgress, 1.42);
|
|
15514
|
-
const lowerLobeWave = resolveLowerLobeWave(longitude, morphologyProfile, animationPhase, timeMs);
|
|
15515
15863
|
const skirtEnvelope = Math.pow(cosineLatitude, 0.5) * lowerBlend;
|
|
15516
15864
|
const horizontalScale = 1.02 +
|
|
15517
15865
|
skirtEnvelope * (0.34 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.22 + lowerLobeWave * 0.22) -
|
|
@@ -15549,7 +15897,7 @@
|
|
|
15549
15897
|
*
|
|
15550
15898
|
* @private helper of `octopus3d2AvatarVisual`
|
|
15551
15899
|
*/
|
|
15552
|
-
function resolveBlobbySurfacePatchFillStyle(palette, verticalProgress, forwardness, lowerLobeWave) {
|
|
15900
|
+
function resolveBlobbySurfacePatchFillStyle$1(palette, verticalProgress, forwardness, lowerLobeWave) {
|
|
15553
15901
|
const tonalProgress = clampNumber$1(verticalProgress + lowerLobeWave * 0.12 - forwardness * 0.07, 0, 1);
|
|
15554
15902
|
if (tonalProgress < 0.16) {
|
|
15555
15903
|
return palette.highlight;
|
|
@@ -15589,6 +15937,1384 @@
|
|
|
15589
15937
|
context.restore();
|
|
15590
15938
|
}
|
|
15591
15939
|
|
|
15940
|
+
/* eslint-disable no-magic-numbers */
|
|
15941
|
+
/**
|
|
15942
|
+
* Light direction used by the continuous octopus mesh shading.
|
|
15943
|
+
*
|
|
15944
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
15945
|
+
*/
|
|
15946
|
+
const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
15947
|
+
x: 0.34,
|
|
15948
|
+
y: -0.62,
|
|
15949
|
+
z: 1,
|
|
15950
|
+
});
|
|
15951
|
+
/**
|
|
15952
|
+
* Real-octopus tentacle count used by the continuous lower mesh.
|
|
15953
|
+
*
|
|
15954
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
15955
|
+
*/
|
|
15956
|
+
const OCTOPUS_TENTACLE_COUNT$1 = 8;
|
|
15957
|
+
/**
|
|
15958
|
+
* Cache keyed by the `createRandom` factory reference, which is stable for the lifetime of one
|
|
15959
|
+
* mounted `<Avatar/>` component (created inside `resolveAvatarRenderDefinition` and held in a
|
|
15960
|
+
* React `useMemo`). Using a `WeakMap` ensures the entry is collected when the component unmounts.
|
|
15961
|
+
*
|
|
15962
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
15963
|
+
*/
|
|
15964
|
+
const stableStateCache = new WeakMap();
|
|
15965
|
+
/**
|
|
15966
|
+
* Returns the stable per-avatar state, computing it on first access and returning the cached
|
|
15967
|
+
* result on every subsequent call within the same `<Avatar/>` mount.
|
|
15968
|
+
*
|
|
15969
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
15970
|
+
*/
|
|
15971
|
+
function getOctopus3d3StableState(createRandom) {
|
|
15972
|
+
const cached = stableStateCache.get(createRandom);
|
|
15973
|
+
if (cached !== undefined) {
|
|
15974
|
+
return cached;
|
|
15975
|
+
}
|
|
15976
|
+
const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
|
|
15977
|
+
const animationRandom = createRandom('octopus3d3-animation-profile');
|
|
15978
|
+
const eyeRandom = createRandom('octopus3d3-eye-profile');
|
|
15979
|
+
const leftEyePhaseOffset = eyeRandom() * 0.7;
|
|
15980
|
+
const rightEyePhaseOffset = eyeRandom() * 0.7;
|
|
15981
|
+
const state = {
|
|
15982
|
+
morphologyProfile,
|
|
15983
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
15984
|
+
leftEyePhaseOffset,
|
|
15985
|
+
rightEyePhaseOffset,
|
|
15986
|
+
tentacleProfiles: createContinuousTentacleProfiles(createRandom, morphologyProfile),
|
|
15987
|
+
};
|
|
15988
|
+
stableStateCache.set(createRandom, state);
|
|
15989
|
+
return state;
|
|
15990
|
+
}
|
|
15991
|
+
/**
|
|
15992
|
+
* Octopus 3D 3 avatar visual.
|
|
15993
|
+
*
|
|
15994
|
+
* @private built-in avatar visual
|
|
15995
|
+
*/
|
|
15996
|
+
const octopus3d3AvatarVisual = {
|
|
15997
|
+
id: 'octopus3d3',
|
|
15998
|
+
title: 'Octopus 3D 3',
|
|
15999
|
+
description: 'Cute continuous 3D octopus with a blobby single mesh, waving tentacle lobes, rich shading, and cursor-aware eyes.',
|
|
16000
|
+
isAnimated: true,
|
|
16001
|
+
supportsPointerTracking: true,
|
|
16002
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
16003
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset, tentacleProfiles } = getOctopus3d3StableState(createRandom);
|
|
16004
|
+
const sceneCenterX = size * 0.5;
|
|
16005
|
+
const sceneCenterY = size * 0.535;
|
|
16006
|
+
const bob = Math.sin(timeMs / 960 + animationPhase) * size * 0.012;
|
|
16007
|
+
const meshCenter = {
|
|
16008
|
+
x: interaction.bodyOffsetX * size * 0.048 + size * morphologyProfile.body.centerXJitterRatio * 0.44,
|
|
16009
|
+
y: -size * 0.07 + interaction.bodyOffsetY * size * 0.026 + bob,
|
|
16010
|
+
z: interaction.intensity * size * 0.018,
|
|
16011
|
+
};
|
|
16012
|
+
const rotationY = -0.1 +
|
|
16013
|
+
Math.sin(timeMs / 2700 + animationPhase) * 0.035 +
|
|
16014
|
+
interaction.bodyOffsetX * 0.22 +
|
|
16015
|
+
interaction.gazeX * 0.88;
|
|
16016
|
+
const rotationX = -0.07 +
|
|
16017
|
+
Math.cos(timeMs / 3100 + animationPhase * 0.7) * 0.018 -
|
|
16018
|
+
interaction.bodyOffsetY * 0.08 -
|
|
16019
|
+
interaction.gazeY * 0.38;
|
|
16020
|
+
const surfaceOptions = {
|
|
16021
|
+
radiusX: size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch * 1.1,
|
|
16022
|
+
radiusY: size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.08,
|
|
16023
|
+
radiusZ: size *
|
|
16024
|
+
morphologyProfile.body.bodyRadiusRatio *
|
|
16025
|
+
(1.02 + (morphologyProfile.body.horizontalStretch - 1) * 0.18),
|
|
16026
|
+
morphologyProfile,
|
|
16027
|
+
timeMs,
|
|
16028
|
+
animationPhase,
|
|
16029
|
+
tentacleProfiles,
|
|
16030
|
+
};
|
|
16031
|
+
const surfacePatches = resolveVisibleContinuousOctopusPatches({
|
|
16032
|
+
...surfaceOptions,
|
|
16033
|
+
center: meshCenter,
|
|
16034
|
+
rotationX,
|
|
16035
|
+
rotationY,
|
|
16036
|
+
sceneCenterX,
|
|
16037
|
+
sceneCenterY,
|
|
16038
|
+
size,
|
|
16039
|
+
palette,
|
|
16040
|
+
});
|
|
16041
|
+
const eyeLatitude = clampNumber$1(morphologyProfile.face.eyeCenterYOffsetRatio * 4.2 - 0.03, -0.22, 0.08);
|
|
16042
|
+
const eyeLongitude = clampNumber$1(morphologyProfile.face.eyeSpacingRatio * 3.1, 0.18, 0.32);
|
|
16043
|
+
const mouthLatitude = clampNumber$1(eyeLatitude + 0.2 + morphologyProfile.face.mouthYOffsetRatio, 0.08, 0.34);
|
|
16044
|
+
const mouthCenterLongitude = clampNumber$1(morphologyProfile.face.mouthCenterOffsetRatio * 5.6, -0.08, 0.08);
|
|
16045
|
+
const mouthHalfLongitude = clampNumber$1(eyeLongitude * 0.78, 0.15, 0.28);
|
|
16046
|
+
const mouthCurveLatitude = clampNumber$1(mouthLatitude + morphologyProfile.face.mouthCurveDepthRatio * 0.78, mouthLatitude + 0.03, 0.42);
|
|
16047
|
+
const eyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.76;
|
|
16048
|
+
const eyeRadiusY = eyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.9;
|
|
16049
|
+
drawAvatarFrame(context, size, palette);
|
|
16050
|
+
drawContinuousOctopusAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
16051
|
+
drawContinuousOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile);
|
|
16052
|
+
for (const surfacePatch of surfacePatches.sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
16053
|
+
drawContinuousSurfacePatch(context, surfacePatch);
|
|
16054
|
+
}
|
|
16055
|
+
drawProjectedSurfaceCurrents({
|
|
16056
|
+
context,
|
|
16057
|
+
surfaceOptions,
|
|
16058
|
+
center: meshCenter,
|
|
16059
|
+
rotationX,
|
|
16060
|
+
rotationY,
|
|
16061
|
+
sceneCenterX,
|
|
16062
|
+
sceneCenterY,
|
|
16063
|
+
size,
|
|
16064
|
+
palette,
|
|
16065
|
+
morphologyProfile,
|
|
16066
|
+
timeMs,
|
|
16067
|
+
animationPhase,
|
|
16068
|
+
});
|
|
16069
|
+
drawProjectedTentacleSuckers({
|
|
16070
|
+
context,
|
|
16071
|
+
surfaceOptions,
|
|
16072
|
+
center: meshCenter,
|
|
16073
|
+
rotationX,
|
|
16074
|
+
rotationY,
|
|
16075
|
+
sceneCenterX,
|
|
16076
|
+
sceneCenterY,
|
|
16077
|
+
size,
|
|
16078
|
+
palette,
|
|
16079
|
+
});
|
|
16080
|
+
drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
16081
|
+
drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.85 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
16082
|
+
drawProjectedOrganicMouth(context, [
|
|
16083
|
+
sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
|
|
16084
|
+
sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
|
|
16085
|
+
sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude + mouthHalfLongitude),
|
|
16086
|
+
], meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, palette, size);
|
|
16087
|
+
},
|
|
16088
|
+
};
|
|
16089
|
+
/**
|
|
16090
|
+
* Creates seeded tentacle-lobe profiles around the visible lower octopus body.
|
|
16091
|
+
*
|
|
16092
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16093
|
+
*/
|
|
16094
|
+
function createContinuousTentacleProfiles(createRandom, morphologyProfile) {
|
|
16095
|
+
return Array.from({ length: OCTOPUS_TENTACLE_COUNT$1 }, (_, tentacleIndex) => {
|
|
16096
|
+
const tentacleRandom = createRandom(`octopus3d3-tentacle-${tentacleIndex}`);
|
|
16097
|
+
const progress = tentacleIndex / (OCTOPUS_TENTACLE_COUNT$1 - 1);
|
|
16098
|
+
return {
|
|
16099
|
+
centerLongitude: -Math.PI * 0.86 +
|
|
16100
|
+
progress * Math.PI * 1.72 +
|
|
16101
|
+
(tentacleRandom() - 0.5) * (0.08 + morphologyProfile.tentacles.rootSpreadScale * 0.03),
|
|
16102
|
+
widthScale: 0.86 + tentacleRandom() * 0.34 + (morphologyProfile.tentacles.baseWidthScale - 1) * 0.16,
|
|
16103
|
+
lengthScale: 0.86 + tentacleRandom() * 0.36 + (morphologyProfile.tentacles.flowLengthScale - 1) * 0.22,
|
|
16104
|
+
swayScale: 0.82 + tentacleRandom() * 0.38 + (morphologyProfile.tentacles.swayScale - 1) * 0.2,
|
|
16105
|
+
depthScale: 0.86 + tentacleRandom() * 0.32 + (morphologyProfile.tentacles.tipReachScale - 1) * 0.2,
|
|
16106
|
+
phase: tentacleRandom() * Math.PI * 2,
|
|
16107
|
+
suckerSide: tentacleRandom() > 0.5 ? 1 : -1,
|
|
16108
|
+
};
|
|
16109
|
+
});
|
|
16110
|
+
}
|
|
16111
|
+
/**
|
|
16112
|
+
* Draws the soft underwater atmosphere behind the continuous octopus mesh.
|
|
16113
|
+
*
|
|
16114
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16115
|
+
*/
|
|
16116
|
+
function drawContinuousOctopusAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
16117
|
+
const glowGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.11, sceneCenterY - size * 0.17 + interaction.gazeY * size * 0.05, size * 0.04, sceneCenterX, sceneCenterY, size * (0.66 + interaction.intensity * 0.02));
|
|
16118
|
+
glowGradient.addColorStop(0, `${palette.highlight}66`);
|
|
16119
|
+
glowGradient.addColorStop(0.34, `${palette.accent}2e`);
|
|
16120
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
16121
|
+
context.fillStyle = glowGradient;
|
|
16122
|
+
context.fillRect(0, 0, size, size);
|
|
16123
|
+
const lowerGradient = context.createRadialGradient(sceneCenterX + Math.sin(timeMs / 1550) * size * 0.05, sceneCenterY + size * 0.29, size * 0.06, sceneCenterX, sceneCenterY + size * 0.3, size * 0.54);
|
|
16124
|
+
lowerGradient.addColorStop(0, `${palette.secondary}25`);
|
|
16125
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
16126
|
+
context.fillStyle = lowerGradient;
|
|
16127
|
+
context.fillRect(0, 0, size, size);
|
|
16128
|
+
}
|
|
16129
|
+
/**
|
|
16130
|
+
* Draws the soft lower shadow that anchors the octopus in the avatar frame.
|
|
16131
|
+
*
|
|
16132
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
16133
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
16134
|
+
*
|
|
16135
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16136
|
+
*/
|
|
16137
|
+
function drawContinuousOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
|
|
16138
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.045;
|
|
16139
|
+
const cy = size * 0.9 + Math.sin(timeMs / 980) * size * 0.007;
|
|
16140
|
+
const rx = size * (0.19 + morphologyProfile.tentacles.rootSpreadScale * 0.022 + interaction.intensity * 0.02);
|
|
16141
|
+
const ry = size * 0.06;
|
|
16142
|
+
// Scale the context so that drawing a circle produces the correct ellipse aspect ratio,
|
|
16143
|
+
// then fill with a radial gradient that approximates the blurry edge without context.filter.
|
|
16144
|
+
context.save();
|
|
16145
|
+
context.translate(cx, cy);
|
|
16146
|
+
context.scale(1, ry / rx);
|
|
16147
|
+
const blurRadius = rx * 1.4;
|
|
16148
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
16149
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
16150
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
16151
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
16152
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
16153
|
+
context.fillStyle = shadowGradient;
|
|
16154
|
+
context.beginPath();
|
|
16155
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
16156
|
+
context.fill();
|
|
16157
|
+
context.restore();
|
|
16158
|
+
}
|
|
16159
|
+
/**
|
|
16160
|
+
* Number of latitude segments used by the continuous Octopus 3D 3 mesh.
|
|
16161
|
+
*
|
|
16162
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16163
|
+
*/
|
|
16164
|
+
const LATITUDE_PATCH_COUNT$1 = 16;
|
|
16165
|
+
/**
|
|
16166
|
+
* Number of longitude segments used by the continuous Octopus 3D 3 mesh.
|
|
16167
|
+
*
|
|
16168
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16169
|
+
*/
|
|
16170
|
+
const LONGITUDE_PATCH_COUNT$1 = 40;
|
|
16171
|
+
/**
|
|
16172
|
+
* Resolves visible projected patches for the continuous octopus mesh.
|
|
16173
|
+
*
|
|
16174
|
+
* Within a single frame, mesh corner samples and longitude-only computations (tentacle
|
|
16175
|
+
* influence and lobe wave) are quantized to the patch grid and computed once each rather
|
|
16176
|
+
* than re-evaluated for every patch corner — the patch loop alone calls `sampleContinuousOctopusSurfacePoint`
|
|
16177
|
+
* for `latitudePatchCount * longitudePatchCount * 4` corners without caching, and each call
|
|
16178
|
+
* triggers an inner 8-iteration `Math.exp` loop, which dominates the per-frame cost.
|
|
16179
|
+
*
|
|
16180
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16181
|
+
*/
|
|
16182
|
+
function resolveVisibleContinuousOctopusPatches(options) {
|
|
16183
|
+
const { center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette } = options;
|
|
16184
|
+
const latitudePatchCount = LATITUDE_PATCH_COUNT$1;
|
|
16185
|
+
const longitudePatchCount = LONGITUDE_PATCH_COUNT$1;
|
|
16186
|
+
const surfacePatches = [];
|
|
16187
|
+
const latitudeBoundaries = new Float64Array(latitudePatchCount + 1);
|
|
16188
|
+
const longitudeBoundaries = new Float64Array(longitudePatchCount + 1);
|
|
16189
|
+
for (let boundaryIndex = 0; boundaryIndex <= latitudePatchCount; boundaryIndex++) {
|
|
16190
|
+
latitudeBoundaries[boundaryIndex] = -Math.PI / 2 + (boundaryIndex / latitudePatchCount) * Math.PI;
|
|
16191
|
+
}
|
|
16192
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
16193
|
+
longitudeBoundaries[boundaryIndex] = -Math.PI + (boundaryIndex / longitudePatchCount) * Math.PI * 2;
|
|
16194
|
+
}
|
|
16195
|
+
const cachedTentacleInfluencesByCornerLongitude = new Array(longitudePatchCount + 1);
|
|
16196
|
+
const cachedLobeWavesByCornerLongitude = new Float64Array(longitudePatchCount + 1);
|
|
16197
|
+
const cachedTentacleInfluencesByPatchCenterLongitude = new Array(longitudePatchCount);
|
|
16198
|
+
const cachedLobeWavesByPatchCenterLongitude = new Float64Array(longitudePatchCount);
|
|
16199
|
+
const cachedCosByPatchCenterLongitude = new Float64Array(longitudePatchCount);
|
|
16200
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
16201
|
+
const cornerLongitude = longitudeBoundaries[boundaryIndex];
|
|
16202
|
+
cachedTentacleInfluencesByCornerLongitude[boundaryIndex] = resolveContinuousTentacleInfluence(options, cornerLongitude);
|
|
16203
|
+
cachedLobeWavesByCornerLongitude[boundaryIndex] = resolveContinuousLobeWave(options, cornerLongitude);
|
|
16204
|
+
}
|
|
16205
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
16206
|
+
const patchCenterLongitude = (longitudeBoundaries[longitudeIndex] + longitudeBoundaries[longitudeIndex + 1]) / 2;
|
|
16207
|
+
cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex] = resolveContinuousTentacleInfluence(options, patchCenterLongitude);
|
|
16208
|
+
cachedLobeWavesByPatchCenterLongitude[longitudeIndex] = resolveContinuousLobeWave(options, patchCenterLongitude);
|
|
16209
|
+
cachedCosByPatchCenterLongitude[longitudeIndex] = Math.max(0, Math.cos(patchCenterLongitude));
|
|
16210
|
+
}
|
|
16211
|
+
const cornerCount = (latitudePatchCount + 1) * (longitudePatchCount + 1);
|
|
16212
|
+
const transformedCornerSamples = new Array(cornerCount);
|
|
16213
|
+
for (let latitudeBoundaryIndex = 0; latitudeBoundaryIndex <= latitudePatchCount; latitudeBoundaryIndex++) {
|
|
16214
|
+
const cornerLatitude = latitudeBoundaries[latitudeBoundaryIndex];
|
|
16215
|
+
for (let longitudeBoundaryIndex = 0; longitudeBoundaryIndex <= longitudePatchCount; longitudeBoundaryIndex++) {
|
|
16216
|
+
const cornerLongitude = longitudeBoundaries[longitudeBoundaryIndex];
|
|
16217
|
+
const cornerIndex = latitudeBoundaryIndex * (longitudePatchCount + 1) + longitudeBoundaryIndex;
|
|
16218
|
+
const cornerSample = sampleContinuousOctopusSurfacePointWithLongitudeCache(options, cornerLatitude, cornerLongitude, cachedTentacleInfluencesByCornerLongitude[longitudeBoundaryIndex], cachedLobeWavesByCornerLongitude[longitudeBoundaryIndex]);
|
|
16219
|
+
transformedCornerSamples[cornerIndex] = transformScenePoint(cornerSample, center, rotationX, rotationY);
|
|
16220
|
+
}
|
|
16221
|
+
}
|
|
16222
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
16223
|
+
const startLatitude = latitudeBoundaries[latitudeIndex];
|
|
16224
|
+
const endLatitude = latitudeBoundaries[latitudeIndex + 1];
|
|
16225
|
+
const centerLatitude = (startLatitude + endLatitude) / 2;
|
|
16226
|
+
const verticalProgress = (Math.sin(centerLatitude) + 1) / 2;
|
|
16227
|
+
const startCornerRowOffset = latitudeIndex * (longitudePatchCount + 1);
|
|
16228
|
+
const endCornerRowOffset = (latitudeIndex + 1) * (longitudePatchCount + 1);
|
|
16229
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
16230
|
+
const transformedCorners = [
|
|
16231
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex],
|
|
16232
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex + 1],
|
|
16233
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex + 1],
|
|
16234
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex],
|
|
16235
|
+
];
|
|
16236
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
16237
|
+
if (surfaceNormal.z <= 0.008) {
|
|
16238
|
+
continue;
|
|
16239
|
+
}
|
|
16240
|
+
const projectedCorners = [
|
|
16241
|
+
projectScenePoint(transformedCorners[0], size, sceneCenterX, sceneCenterY),
|
|
16242
|
+
projectScenePoint(transformedCorners[1], size, sceneCenterX, sceneCenterY),
|
|
16243
|
+
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
16244
|
+
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
16245
|
+
];
|
|
16246
|
+
surfacePatches.push({
|
|
16247
|
+
corners: projectedCorners,
|
|
16248
|
+
averageDepth: (transformedCorners[0].z +
|
|
16249
|
+
transformedCorners[1].z +
|
|
16250
|
+
transformedCorners[2].z +
|
|
16251
|
+
transformedCorners[3].z) /
|
|
16252
|
+
4,
|
|
16253
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$1), -1, 1),
|
|
16254
|
+
fillStyle: resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, cachedCosByPatchCenterLongitude[longitudeIndex], cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex].core, cachedLobeWavesByPatchCenterLongitude[longitudeIndex]),
|
|
16255
|
+
outlineColor: verticalProgress < 0.54 ? `${palette.highlight}69` : `${palette.shadow}78`,
|
|
16256
|
+
});
|
|
16257
|
+
}
|
|
16258
|
+
}
|
|
16259
|
+
return surfacePatches;
|
|
16260
|
+
}
|
|
16261
|
+
/**
|
|
16262
|
+
* Samples one point on the continuous Octopus 3D 3 surface.
|
|
16263
|
+
*
|
|
16264
|
+
* The lower hemisphere is pulled into eight seeded waving lobes, so the portrait reads as
|
|
16265
|
+
* tentacled while still being rendered as one connected blobby mesh.
|
|
16266
|
+
*
|
|
16267
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16268
|
+
*/
|
|
16269
|
+
function sampleContinuousOctopusSurfacePoint(options, latitude, longitude) {
|
|
16270
|
+
return sampleContinuousOctopusSurfacePointWithLongitudeCache(options, latitude, longitude, resolveContinuousTentacleInfluence(options, longitude), resolveContinuousLobeWave(options, longitude));
|
|
16271
|
+
}
|
|
16272
|
+
/**
|
|
16273
|
+
* Samples one point on the continuous Octopus 3D 3 surface using precomputed longitude-only
|
|
16274
|
+
* values to skip the per-call `Math.exp` tentacle-influence loop and the lobe-wave trig call.
|
|
16275
|
+
*
|
|
16276
|
+
* The patch loop quantizes the mesh into a fixed `(latitudePatchCount + 1) * (longitudePatchCount + 1)`
|
|
16277
|
+
* corner grid, so the same longitude is reused across every latitude row and each
|
|
16278
|
+
* tentacle/lobe value can be computed once per frame instead of `latitudePatchCount * 4` times.
|
|
16279
|
+
*
|
|
16280
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16281
|
+
*/
|
|
16282
|
+
function sampleContinuousOctopusSurfacePointWithLongitudeCache(options, latitude, longitude, tentacleInfluence, lowerLobeWave) {
|
|
16283
|
+
const { radiusX, radiusY, radiusZ, morphologyProfile, timeMs, animationPhase } = options;
|
|
16284
|
+
const cosineLatitude = Math.max(0, Math.cos(latitude));
|
|
16285
|
+
const verticalProgress = (Math.sin(latitude) + 1) / 2;
|
|
16286
|
+
const upperBlend = Math.pow(1 - verticalProgress, 1.28);
|
|
16287
|
+
const lowerBlend = smoothStep$1(0.38, 1, verticalProgress);
|
|
16288
|
+
const tipBlend = smoothStep$1(0.68, 1, verticalProgress);
|
|
16289
|
+
const centerPull = resolveSignedAngularDistance$1(longitude, tentacleInfluence.centerLongitude);
|
|
16290
|
+
const effectiveLongitude = longitude + centerPull * lowerBlend * tentacleInfluence.core * (0.24 + tipBlend * 0.2);
|
|
16291
|
+
const mantleRipple = Math.sin(longitude * morphologyProfile.body.lobeCount +
|
|
16292
|
+
animationPhase * 0.6 +
|
|
16293
|
+
timeMs / (1750 + morphologyProfile.body.lobeCount * 30)) *
|
|
16294
|
+
(0.018 + morphologyProfile.body.wobbleAmplitudeRatio * 0.8) *
|
|
16295
|
+
(0.3 + lowerBlend * 0.7);
|
|
16296
|
+
const tentacleWave = Math.sin(timeMs / 760 + tentacleInfluence.phase + verticalProgress * 2.4) *
|
|
16297
|
+
lowerBlend *
|
|
16298
|
+
tentacleInfluence.core *
|
|
16299
|
+
tentacleInfluence.swayScale;
|
|
16300
|
+
const horizontalScale = 1.04 +
|
|
16301
|
+
mantleRipple +
|
|
16302
|
+
lowerBlend * (0.16 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.1) +
|
|
16303
|
+
lowerBlend * tentacleInfluence.core * (0.2 + lowerLobeWave * 0.12) -
|
|
16304
|
+
upperBlend * 0.08;
|
|
16305
|
+
const depthScale = 1.06 +
|
|
16306
|
+
upperBlend * 0.16 +
|
|
16307
|
+
Math.max(0, Math.cos(effectiveLongitude)) * 0.1 +
|
|
16308
|
+
lowerBlend * tentacleInfluence.core * (0.1 + tentacleInfluence.depthScale * 0.06) -
|
|
16309
|
+
Math.max(0, -Math.cos(effectiveLongitude)) * 0.05;
|
|
16310
|
+
const tentacleTubeRadius = lowerBlend * tentacleInfluence.core * (0.11 + tipBlend * 0.06 + tentacleInfluence.widthScale * 0.025) * radiusX;
|
|
16311
|
+
const planarRadiusX = cosineLatitude * radiusX * horizontalScale + tentacleTubeRadius;
|
|
16312
|
+
const planarRadiusZ = cosineLatitude * radiusZ * depthScale + tentacleTubeRadius * 0.72;
|
|
16313
|
+
const lowerDrop = lowerBlend *
|
|
16314
|
+
radiusY *
|
|
16315
|
+
(0.18 +
|
|
16316
|
+
tentacleInfluence.core *
|
|
16317
|
+
(0.38 +
|
|
16318
|
+
tentacleInfluence.lengthScale * 0.22 +
|
|
16319
|
+
(morphologyProfile.tentacles.flowLengthScale - 1) * 0.08));
|
|
16320
|
+
return {
|
|
16321
|
+
x: Math.sin(effectiveLongitude) * planarRadiusX + tentacleWave * radiusX * (0.052 + tipBlend * 0.05),
|
|
16322
|
+
y: Math.sin(latitude) * radiusY * (1 + upperBlend * 0.12) -
|
|
16323
|
+
upperBlend * radiusY * 0.1 +
|
|
16324
|
+
lowerDrop +
|
|
16325
|
+
Math.sin(timeMs / 1420 + animationPhase + latitude * 1.6) * lowerBlend * radiusY * 0.018 +
|
|
16326
|
+
Math.cos(timeMs / 880 + tentacleInfluence.phase) *
|
|
16327
|
+
lowerBlend *
|
|
16328
|
+
tipBlend *
|
|
16329
|
+
tentacleInfluence.core *
|
|
16330
|
+
radiusY *
|
|
16331
|
+
0.034,
|
|
16332
|
+
z: Math.cos(effectiveLongitude) * planarRadiusZ +
|
|
16333
|
+
Math.cos(timeMs / 980 + tentacleInfluence.phase + verticalProgress) *
|
|
16334
|
+
lowerBlend *
|
|
16335
|
+
tentacleInfluence.core *
|
|
16336
|
+
radiusZ *
|
|
16337
|
+
0.04,
|
|
16338
|
+
};
|
|
16339
|
+
}
|
|
16340
|
+
/**
|
|
16341
|
+
* Blends nearby seeded tentacle profiles at one mesh longitude.
|
|
16342
|
+
*
|
|
16343
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16344
|
+
*/
|
|
16345
|
+
function resolveContinuousTentacleInfluence(options, longitude) {
|
|
16346
|
+
let totalWeight = 0;
|
|
16347
|
+
let weightedSin = 0;
|
|
16348
|
+
let weightedCos = 0;
|
|
16349
|
+
let weightedWidthScale = 0;
|
|
16350
|
+
let weightedLengthScale = 0;
|
|
16351
|
+
let weightedSwayScale = 0;
|
|
16352
|
+
let weightedDepthScale = 0;
|
|
16353
|
+
let weightedPhase = 0;
|
|
16354
|
+
for (const tentacleProfile of options.tentacleProfiles) {
|
|
16355
|
+
const distance = Math.abs(resolveSignedAngularDistance$1(longitude, tentacleProfile.centerLongitude));
|
|
16356
|
+
const width = 0.2 * tentacleProfile.widthScale;
|
|
16357
|
+
const weight = Math.exp(-(distance * distance) / (width * width));
|
|
16358
|
+
totalWeight += weight;
|
|
16359
|
+
weightedSin += Math.sin(tentacleProfile.centerLongitude) * weight;
|
|
16360
|
+
weightedCos += Math.cos(tentacleProfile.centerLongitude) * weight;
|
|
16361
|
+
weightedWidthScale += tentacleProfile.widthScale * weight;
|
|
16362
|
+
weightedLengthScale += tentacleProfile.lengthScale * weight;
|
|
16363
|
+
weightedSwayScale += tentacleProfile.swayScale * weight;
|
|
16364
|
+
weightedDepthScale += tentacleProfile.depthScale * weight;
|
|
16365
|
+
weightedPhase += tentacleProfile.phase * weight;
|
|
16366
|
+
}
|
|
16367
|
+
if (totalWeight < 0.0001) {
|
|
16368
|
+
return {
|
|
16369
|
+
core: 0,
|
|
16370
|
+
centerLongitude: longitude,
|
|
16371
|
+
widthScale: 1,
|
|
16372
|
+
lengthScale: 1,
|
|
16373
|
+
swayScale: 1,
|
|
16374
|
+
depthScale: 1,
|
|
16375
|
+
phase: 0,
|
|
16376
|
+
};
|
|
16377
|
+
}
|
|
16378
|
+
return {
|
|
16379
|
+
core: clampNumber$1(totalWeight, 0, 1),
|
|
16380
|
+
centerLongitude: Math.atan2(weightedSin / totalWeight, weightedCos / totalWeight),
|
|
16381
|
+
widthScale: weightedWidthScale / totalWeight,
|
|
16382
|
+
lengthScale: weightedLengthScale / totalWeight,
|
|
16383
|
+
swayScale: weightedSwayScale / totalWeight,
|
|
16384
|
+
depthScale: weightedDepthScale / totalWeight,
|
|
16385
|
+
phase: weightedPhase / totalWeight,
|
|
16386
|
+
};
|
|
16387
|
+
}
|
|
16388
|
+
/**
|
|
16389
|
+
* Resolves the soft lower wave that makes the continuous mesh read as a set of tentacles.
|
|
16390
|
+
*
|
|
16391
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16392
|
+
*/
|
|
16393
|
+
function resolveContinuousLobeWave(options, longitude) {
|
|
16394
|
+
const { morphologyProfile, animationPhase, timeMs } = options;
|
|
16395
|
+
return ((Math.cos(longitude * OCTOPUS_TENTACLE_COUNT$1 +
|
|
16396
|
+
animationPhase +
|
|
16397
|
+
timeMs / (980 + morphologyProfile.body.lobeCount * 18)) +
|
|
16398
|
+
1) /
|
|
16399
|
+
2);
|
|
16400
|
+
}
|
|
16401
|
+
/**
|
|
16402
|
+
* Resolves one base fill tone for a patch on the continuous octopus mesh.
|
|
16403
|
+
*
|
|
16404
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16405
|
+
*/
|
|
16406
|
+
function resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, forwardness, tentacleCore, lowerLobeWave) {
|
|
16407
|
+
const tonalProgress = clampNumber$1(verticalProgress + lowerLobeWave * 0.1 + tentacleCore * 0.08 - forwardness * 0.08, 0, 1);
|
|
16408
|
+
if (tonalProgress < 0.14) {
|
|
16409
|
+
return palette.highlight;
|
|
16410
|
+
}
|
|
16411
|
+
if (tonalProgress < 0.32) {
|
|
16412
|
+
return palette.secondary;
|
|
16413
|
+
}
|
|
16414
|
+
if (tonalProgress < 0.72) {
|
|
16415
|
+
return forwardness > 0.55 ? palette.secondary : palette.primary;
|
|
16416
|
+
}
|
|
16417
|
+
return tentacleCore > 0.44 ? `${palette.primary}f4` : `${palette.shadow}ee`;
|
|
16418
|
+
}
|
|
16419
|
+
/**
|
|
16420
|
+
* Draws one projected mesh patch with soft shading and a subtle edge.
|
|
16421
|
+
*
|
|
16422
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16423
|
+
*/
|
|
16424
|
+
function drawContinuousSurfacePatch(context, surfacePatch) {
|
|
16425
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
16426
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
16427
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.18 * surfacePatch.lightIntensity})`);
|
|
16428
|
+
}
|
|
16429
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
16430
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.25 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
16431
|
+
}
|
|
16432
|
+
context.save();
|
|
16433
|
+
context.beginPath();
|
|
16434
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
16435
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
16436
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
16437
|
+
}
|
|
16438
|
+
context.closePath();
|
|
16439
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
16440
|
+
context.lineWidth = Math.max(0.7, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0032);
|
|
16441
|
+
context.lineJoin = 'round';
|
|
16442
|
+
context.stroke();
|
|
16443
|
+
context.restore();
|
|
16444
|
+
}
|
|
16445
|
+
/**
|
|
16446
|
+
* Draws projected mantle-current lines on the front of the mesh.
|
|
16447
|
+
*
|
|
16448
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16449
|
+
*/
|
|
16450
|
+
function drawProjectedSurfaceCurrents(options) {
|
|
16451
|
+
const { context, surfaceOptions, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, morphologyProfile, timeMs, animationPhase, } = options;
|
|
16452
|
+
const currentCount = Math.min(6, morphologyProfile.details.mantleCurrentCount);
|
|
16453
|
+
const centerIndex = (currentCount - 1) / 2;
|
|
16454
|
+
context.save();
|
|
16455
|
+
context.lineCap = 'round';
|
|
16456
|
+
context.lineJoin = 'round';
|
|
16457
|
+
for (let currentIndex = 0; currentIndex < currentCount; currentIndex++) {
|
|
16458
|
+
const baseLongitude = (currentIndex - centerIndex) * 0.15;
|
|
16459
|
+
const projectedPoints = [];
|
|
16460
|
+
for (let sampleIndex = 0; sampleIndex < 8; sampleIndex++) {
|
|
16461
|
+
const progress = sampleIndex / 7;
|
|
16462
|
+
const latitude = -0.46 + progress * 0.74;
|
|
16463
|
+
const longitude = baseLongitude + Math.sin(timeMs / 1160 + animationPhase + currentIndex * 0.7 + progress * 2) * 0.035;
|
|
16464
|
+
const scenePoint = transformScenePoint(sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude, longitude), center, rotationX, rotationY);
|
|
16465
|
+
if (scenePoint.z > center.z - size * 0.016) {
|
|
16466
|
+
projectedPoints.push(projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
16467
|
+
}
|
|
16468
|
+
}
|
|
16469
|
+
if (projectedPoints.length < 3) {
|
|
16470
|
+
continue;
|
|
16471
|
+
}
|
|
16472
|
+
context.beginPath();
|
|
16473
|
+
context.moveTo(projectedPoints[0].x, projectedPoints[0].y);
|
|
16474
|
+
for (const projectedPoint of projectedPoints.slice(1)) {
|
|
16475
|
+
context.lineTo(projectedPoint.x, projectedPoint.y);
|
|
16476
|
+
}
|
|
16477
|
+
context.strokeStyle = currentIndex % 2 === 0 ? `${palette.highlight}3d` : `${palette.accent}33`;
|
|
16478
|
+
context.lineWidth = size * (0.0055 + currentIndex * 0.00045);
|
|
16479
|
+
context.stroke();
|
|
16480
|
+
}
|
|
16481
|
+
context.restore();
|
|
16482
|
+
}
|
|
16483
|
+
/**
|
|
16484
|
+
* Draws small projected sucker highlights on the waving lower mesh lobes.
|
|
16485
|
+
*
|
|
16486
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16487
|
+
*/
|
|
16488
|
+
function drawProjectedTentacleSuckers(options) {
|
|
16489
|
+
const { surfaceOptions, size } = options;
|
|
16490
|
+
const { timeMs } = surfaceOptions;
|
|
16491
|
+
for (const tentacleProfile of surfaceOptions.tentacleProfiles) {
|
|
16492
|
+
if (Math.cos(tentacleProfile.centerLongitude) < -0.12) {
|
|
16493
|
+
continue;
|
|
16494
|
+
}
|
|
16495
|
+
for (let suckerIndex = 0; suckerIndex < 3; suckerIndex++) {
|
|
16496
|
+
const latitude = 0.52 + suckerIndex * 0.14;
|
|
16497
|
+
const sideOffset = tentacleProfile.suckerSide * (0.035 + suckerIndex * 0.012) * tentacleProfile.widthScale;
|
|
16498
|
+
const waveOffset = Math.sin(timeMs / 900 + tentacleProfile.phase + suckerIndex * 0.8) * 0.018;
|
|
16499
|
+
drawProjectedSurfaceSpot({
|
|
16500
|
+
...options,
|
|
16501
|
+
latitude,
|
|
16502
|
+
longitude: tentacleProfile.centerLongitude + sideOffset + waveOffset,
|
|
16503
|
+
radiusScale: size * (0.0065 - suckerIndex * 0.0007),
|
|
16504
|
+
});
|
|
16505
|
+
}
|
|
16506
|
+
}
|
|
16507
|
+
}
|
|
16508
|
+
/**
|
|
16509
|
+
* Draws one tiny projected surface spot by sampling local mesh tangents.
|
|
16510
|
+
*
|
|
16511
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16512
|
+
*/
|
|
16513
|
+
function drawProjectedSurfaceSpot(options) {
|
|
16514
|
+
const { context, surfaceOptions, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, latitude, longitude, radiusScale, } = options;
|
|
16515
|
+
const localCenter = sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude, longitude);
|
|
16516
|
+
const localHorizontal = sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude, longitude + 0.018);
|
|
16517
|
+
const localVertical = sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude + 0.018, longitude);
|
|
16518
|
+
const sceneCenterPoint = transformScenePoint(localCenter, center, rotationX, rotationY);
|
|
16519
|
+
if (sceneCenterPoint.z <= center.z - size * 0.012) {
|
|
16520
|
+
return;
|
|
16521
|
+
}
|
|
16522
|
+
const projectedCenterPoint = projectScenePoint(sceneCenterPoint, size, sceneCenterX, sceneCenterY);
|
|
16523
|
+
const projectedHorizontalPoint = projectScenePoint(transformScenePoint(localHorizontal, center, rotationX, rotationY), size, sceneCenterX, sceneCenterY);
|
|
16524
|
+
const projectedVerticalPoint = projectScenePoint(transformScenePoint(localVertical, center, rotationX, rotationY), size, sceneCenterX, sceneCenterY);
|
|
16525
|
+
const horizontalRadius = clampNumber$1(Math.hypot(projectedHorizontalPoint.x - projectedCenterPoint.x, projectedHorizontalPoint.y - projectedCenterPoint.y) *
|
|
16526
|
+
radiusScale *
|
|
16527
|
+
0.74, size * 0.003, size * 0.018);
|
|
16528
|
+
const verticalRadius = clampNumber$1(Math.hypot(projectedVerticalPoint.x - projectedCenterPoint.x, projectedVerticalPoint.y - projectedCenterPoint.y) *
|
|
16529
|
+
radiusScale *
|
|
16530
|
+
0.52, size * 0.0024, size * 0.014);
|
|
16531
|
+
const rotation = Math.atan2(projectedHorizontalPoint.y - projectedCenterPoint.y, projectedHorizontalPoint.x - projectedCenterPoint.x);
|
|
16532
|
+
context.save();
|
|
16533
|
+
context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
|
|
16534
|
+
context.rotate(rotation);
|
|
16535
|
+
context.beginPath();
|
|
16536
|
+
context.ellipse(0, 0, horizontalRadius, verticalRadius, 0, 0, Math.PI * 2);
|
|
16537
|
+
context.fillStyle = `${palette.highlight}73`;
|
|
16538
|
+
context.fill();
|
|
16539
|
+
context.strokeStyle = `${palette.highlight}99`;
|
|
16540
|
+
context.lineWidth = Math.max(0.7, size * 0.0028);
|
|
16541
|
+
context.stroke();
|
|
16542
|
+
context.restore();
|
|
16543
|
+
}
|
|
16544
|
+
/**
|
|
16545
|
+
* Resolves a signed angular distance from the source longitude to the target longitude.
|
|
16546
|
+
*
|
|
16547
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16548
|
+
*/
|
|
16549
|
+
function resolveSignedAngularDistance$1(sourceLongitude, targetLongitude) {
|
|
16550
|
+
return Math.atan2(Math.sin(targetLongitude - sourceLongitude), Math.cos(targetLongitude - sourceLongitude));
|
|
16551
|
+
}
|
|
16552
|
+
/**
|
|
16553
|
+
* Smoothly maps a value between two bounds into `[0, 1]`.
|
|
16554
|
+
*
|
|
16555
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
16556
|
+
*/
|
|
16557
|
+
function smoothStep$1(edgeStart, edgeEnd, value) {
|
|
16558
|
+
const progress = clampNumber$1((value - edgeStart) / (edgeEnd - edgeStart), 0, 1);
|
|
16559
|
+
return progress * progress * (3 - 2 * progress);
|
|
16560
|
+
}
|
|
16561
|
+
|
|
16562
|
+
/* eslint-disable no-magic-numbers */
|
|
16563
|
+
/**
|
|
16564
|
+
* Light direction used by the continuous Octopus 3D 4 mesh shading.
|
|
16565
|
+
*
|
|
16566
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16567
|
+
*/
|
|
16568
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
16569
|
+
x: 0.32,
|
|
16570
|
+
y: -0.66,
|
|
16571
|
+
z: 1,
|
|
16572
|
+
});
|
|
16573
|
+
/**
|
|
16574
|
+
* Rim-light direction used to brighten the side of the silhouette.
|
|
16575
|
+
*
|
|
16576
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16577
|
+
*/
|
|
16578
|
+
const RIM_LIGHT_DIRECTION = normalizeVector3({
|
|
16579
|
+
x: -0.7,
|
|
16580
|
+
y: -0.18,
|
|
16581
|
+
z: 0.55,
|
|
16582
|
+
});
|
|
16583
|
+
/**
|
|
16584
|
+
* Real-octopus tentacle count used by the continuous lower mesh.
|
|
16585
|
+
*
|
|
16586
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16587
|
+
*/
|
|
16588
|
+
const OCTOPUS_TENTACLE_COUNT = 8;
|
|
16589
|
+
/**
|
|
16590
|
+
* Number of seeded skin spots painted across the octopus body.
|
|
16591
|
+
*
|
|
16592
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16593
|
+
*/
|
|
16594
|
+
const SKIN_SPOT_COUNT = 14;
|
|
16595
|
+
/**
|
|
16596
|
+
* Cache keyed by the `createRandom` factory reference, stable per mounted `<Avatar/>` component.
|
|
16597
|
+
*
|
|
16598
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16599
|
+
*/
|
|
16600
|
+
const octopus3d4StableStateCache = new WeakMap();
|
|
16601
|
+
/**
|
|
16602
|
+
* Returns the stable per-avatar state, computing it on first access and caching afterwards.
|
|
16603
|
+
*
|
|
16604
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16605
|
+
*/
|
|
16606
|
+
function getOctopus3d4StableState(createRandom) {
|
|
16607
|
+
const cached = octopus3d4StableStateCache.get(createRandom);
|
|
16608
|
+
if (cached !== undefined) {
|
|
16609
|
+
return cached;
|
|
16610
|
+
}
|
|
16611
|
+
const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
|
|
16612
|
+
const animationRandom = createRandom('octopus3d4-animation-profile');
|
|
16613
|
+
const eyeRandom = createRandom('octopus3d4-eye-profile');
|
|
16614
|
+
const leftEyePhaseOffset = eyeRandom() * 0.7;
|
|
16615
|
+
const rightEyePhaseOffset = eyeRandom() * 0.7;
|
|
16616
|
+
const state = {
|
|
16617
|
+
morphologyProfile,
|
|
16618
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
16619
|
+
leftEyePhaseOffset,
|
|
16620
|
+
rightEyePhaseOffset,
|
|
16621
|
+
tentacleProfiles: createBlobbyContinuousTentacleProfiles(createRandom, morphologyProfile),
|
|
16622
|
+
skinSpots: createBlobbySkinSpots(createRandom),
|
|
16623
|
+
};
|
|
16624
|
+
octopus3d4StableStateCache.set(createRandom, state);
|
|
16625
|
+
return state;
|
|
16626
|
+
}
|
|
16627
|
+
/**
|
|
16628
|
+
* Octopus 3D 4 avatar visual.
|
|
16629
|
+
*
|
|
16630
|
+
* @private built-in avatar visual
|
|
16631
|
+
*/
|
|
16632
|
+
const octopus3d4AvatarVisual = {
|
|
16633
|
+
id: 'octopus3d4',
|
|
16634
|
+
title: 'Octopus 3D 4',
|
|
16635
|
+
description: 'Cute blobby 3D octopus rendered as one smooth continuous mesh with naturally undulating tentacles, rich multi-pass shading, pigment spots, and cursor-aware head and eyes.',
|
|
16636
|
+
isAnimated: true,
|
|
16637
|
+
supportsPointerTracking: true,
|
|
16638
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
16639
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset, tentacleProfiles, skinSpots } = getOctopus3d4StableState(createRandom);
|
|
16640
|
+
const sceneCenterX = size * 0.5;
|
|
16641
|
+
const sceneCenterY = size * 0.535;
|
|
16642
|
+
const bob = Math.sin(timeMs / 980 + animationPhase) * size * 0.013;
|
|
16643
|
+
const meshCenter = {
|
|
16644
|
+
x: interaction.bodyOffsetX * size * 0.052 + size * morphologyProfile.body.centerXJitterRatio * 0.44,
|
|
16645
|
+
y: -size * 0.07 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
16646
|
+
z: interaction.intensity * size * 0.02,
|
|
16647
|
+
};
|
|
16648
|
+
const rotationY = -0.08 +
|
|
16649
|
+
Math.sin(timeMs / 2800 + animationPhase) * 0.04 +
|
|
16650
|
+
interaction.bodyOffsetX * 0.24 +
|
|
16651
|
+
interaction.gazeX * 0.98;
|
|
16652
|
+
const rotationX = -0.07 +
|
|
16653
|
+
Math.cos(timeMs / 3200 + animationPhase * 0.7) * 0.02 -
|
|
16654
|
+
interaction.bodyOffsetY * 0.08 -
|
|
16655
|
+
interaction.gazeY * 0.42;
|
|
16656
|
+
const surfaceOptions = {
|
|
16657
|
+
radiusX: size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch * 1.12,
|
|
16658
|
+
radiusY: size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1,
|
|
16659
|
+
radiusZ: size *
|
|
16660
|
+
morphologyProfile.body.bodyRadiusRatio *
|
|
16661
|
+
(1.04 + (morphologyProfile.body.horizontalStretch - 1) * 0.2),
|
|
16662
|
+
morphologyProfile,
|
|
16663
|
+
timeMs,
|
|
16664
|
+
animationPhase,
|
|
16665
|
+
tentacleProfiles,
|
|
16666
|
+
};
|
|
16667
|
+
const surfacePatches = resolveVisibleBlobbyContinuousPatches({
|
|
16668
|
+
...surfaceOptions,
|
|
16669
|
+
center: meshCenter,
|
|
16670
|
+
rotationX,
|
|
16671
|
+
rotationY,
|
|
16672
|
+
sceneCenterX,
|
|
16673
|
+
sceneCenterY,
|
|
16674
|
+
size,
|
|
16675
|
+
palette,
|
|
16676
|
+
});
|
|
16677
|
+
const eyeLatitude = clampNumber$1(morphologyProfile.face.eyeCenterYOffsetRatio * 4.4 - 0.04, -0.24, 0.08);
|
|
16678
|
+
const eyeLongitude = clampNumber$1(morphologyProfile.face.eyeSpacingRatio * 3.0, 0.18, 0.32);
|
|
16679
|
+
const mouthLatitude = clampNumber$1(eyeLatitude + 0.21 + morphologyProfile.face.mouthYOffsetRatio, 0.08, 0.34);
|
|
16680
|
+
const mouthCenterLongitude = clampNumber$1(morphologyProfile.face.mouthCenterOffsetRatio * 5.6, -0.08, 0.08);
|
|
16681
|
+
const mouthHalfLongitude = clampNumber$1(eyeLongitude * 0.78, 0.15, 0.28);
|
|
16682
|
+
const mouthCurveLatitude = clampNumber$1(mouthLatitude + morphologyProfile.face.mouthCurveDepthRatio * 0.78, mouthLatitude + 0.03, 0.42);
|
|
16683
|
+
const eyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.78;
|
|
16684
|
+
const eyeRadiusY = eyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.92;
|
|
16685
|
+
drawAvatarFrame(context, size, palette);
|
|
16686
|
+
drawBlobbyContinuousAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
16687
|
+
drawBlobbyContinuousShadow(context, size, palette, interaction, timeMs, morphologyProfile);
|
|
16688
|
+
for (const surfacePatch of surfacePatches.sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
16689
|
+
drawBlobbyContinuousSurfacePatch(context, surfacePatch);
|
|
16690
|
+
}
|
|
16691
|
+
drawBlobbySkinSpots({
|
|
16692
|
+
context,
|
|
16693
|
+
surfaceOptions,
|
|
16694
|
+
center: meshCenter,
|
|
16695
|
+
rotationX,
|
|
16696
|
+
rotationY,
|
|
16697
|
+
sceneCenterX,
|
|
16698
|
+
sceneCenterY,
|
|
16699
|
+
size,
|
|
16700
|
+
palette,
|
|
16701
|
+
skinSpots,
|
|
16702
|
+
});
|
|
16703
|
+
drawBlobbyContinuousCurrents({
|
|
16704
|
+
context,
|
|
16705
|
+
surfaceOptions,
|
|
16706
|
+
center: meshCenter,
|
|
16707
|
+
rotationX,
|
|
16708
|
+
rotationY,
|
|
16709
|
+
sceneCenterX,
|
|
16710
|
+
sceneCenterY,
|
|
16711
|
+
size,
|
|
16712
|
+
palette,
|
|
16713
|
+
morphologyProfile,
|
|
16714
|
+
timeMs,
|
|
16715
|
+
animationPhase,
|
|
16716
|
+
});
|
|
16717
|
+
drawBlobbyContinuousSuckers({
|
|
16718
|
+
context,
|
|
16719
|
+
surfaceOptions,
|
|
16720
|
+
center: meshCenter,
|
|
16721
|
+
rotationX,
|
|
16722
|
+
rotationY,
|
|
16723
|
+
sceneCenterX,
|
|
16724
|
+
sceneCenterY,
|
|
16725
|
+
size,
|
|
16726
|
+
palette,
|
|
16727
|
+
});
|
|
16728
|
+
drawBlobbyContinuousGloss({
|
|
16729
|
+
context,
|
|
16730
|
+
surfaceOptions,
|
|
16731
|
+
center: meshCenter,
|
|
16732
|
+
rotationX,
|
|
16733
|
+
rotationY,
|
|
16734
|
+
sceneCenterX,
|
|
16735
|
+
sceneCenterY,
|
|
16736
|
+
size,
|
|
16737
|
+
palette,
|
|
16738
|
+
});
|
|
16739
|
+
drawProjectedOrganicEye(context, sampleBlobbyContinuousSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
16740
|
+
drawProjectedOrganicEye(context, sampleBlobbyContinuousSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.85 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
16741
|
+
drawProjectedOrganicMouth(context, [
|
|
16742
|
+
sampleBlobbyContinuousSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
|
|
16743
|
+
sampleBlobbyContinuousSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
|
|
16744
|
+
sampleBlobbyContinuousSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude + mouthHalfLongitude),
|
|
16745
|
+
], meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, palette, size);
|
|
16746
|
+
},
|
|
16747
|
+
};
|
|
16748
|
+
/**
|
|
16749
|
+
* Creates seeded tentacle-lobe profiles around the visible lower octopus body.
|
|
16750
|
+
*
|
|
16751
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16752
|
+
*/
|
|
16753
|
+
function createBlobbyContinuousTentacleProfiles(createRandom, morphologyProfile) {
|
|
16754
|
+
return Array.from({ length: OCTOPUS_TENTACLE_COUNT }, (_, tentacleIndex) => {
|
|
16755
|
+
const tentacleRandom = createRandom(`octopus3d4-tentacle-${tentacleIndex}`);
|
|
16756
|
+
const progress = tentacleIndex / (OCTOPUS_TENTACLE_COUNT - 1);
|
|
16757
|
+
return {
|
|
16758
|
+
centerLongitude: -Math.PI * 0.9 +
|
|
16759
|
+
progress * Math.PI * 1.8 +
|
|
16760
|
+
(tentacleRandom() - 0.5) * (0.06 + morphologyProfile.tentacles.rootSpreadScale * 0.025),
|
|
16761
|
+
widthScale: 0.92 + tentacleRandom() * 0.3 + (morphologyProfile.tentacles.baseWidthScale - 1) * 0.18,
|
|
16762
|
+
lengthScale: 0.9 + tentacleRandom() * 0.34 + (morphologyProfile.tentacles.flowLengthScale - 1) * 0.24,
|
|
16763
|
+
swayScale: 0.86 + tentacleRandom() * 0.4 + (morphologyProfile.tentacles.swayScale - 1) * 0.22,
|
|
16764
|
+
depthScale: 0.9 + tentacleRandom() * 0.3 + (morphologyProfile.tentacles.tipReachScale - 1) * 0.22,
|
|
16765
|
+
curlScale: 0.62 + tentacleRandom() * 0.46,
|
|
16766
|
+
primaryPhase: tentacleRandom() * Math.PI * 2,
|
|
16767
|
+
secondaryPhase: tentacleRandom() * Math.PI * 2,
|
|
16768
|
+
suckerSide: tentacleRandom() > 0.5 ? 1 : -1,
|
|
16769
|
+
};
|
|
16770
|
+
});
|
|
16771
|
+
}
|
|
16772
|
+
/**
|
|
16773
|
+
* Creates seeded skin pigment spots distributed across the upper octopus mesh.
|
|
16774
|
+
*
|
|
16775
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16776
|
+
*/
|
|
16777
|
+
function createBlobbySkinSpots(createRandom) {
|
|
16778
|
+
const spotRandom = createRandom('octopus3d4-skin-spots');
|
|
16779
|
+
return Array.from({ length: SKIN_SPOT_COUNT }, () => ({
|
|
16780
|
+
latitude: -0.45 + spotRandom() * 0.7,
|
|
16781
|
+
longitude: -0.5 + spotRandom() * 1.0,
|
|
16782
|
+
radiusScale: 0.0028 + spotRandom() * 0.0052,
|
|
16783
|
+
opacity: 0.16 + spotRandom() * 0.22,
|
|
16784
|
+
}));
|
|
16785
|
+
}
|
|
16786
|
+
/**
|
|
16787
|
+
* Draws the soft underwater atmosphere behind the continuous octopus mesh.
|
|
16788
|
+
*
|
|
16789
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16790
|
+
*/
|
|
16791
|
+
function drawBlobbyContinuousAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
16792
|
+
const glowGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.12, sceneCenterY - size * 0.18 + interaction.gazeY * size * 0.05, size * 0.04, sceneCenterX, sceneCenterY, size * (0.68 + interaction.intensity * 0.025));
|
|
16793
|
+
glowGradient.addColorStop(0, `${palette.highlight}74`);
|
|
16794
|
+
glowGradient.addColorStop(0.32, `${palette.accent}32`);
|
|
16795
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
16796
|
+
context.fillStyle = glowGradient;
|
|
16797
|
+
context.fillRect(0, 0, size, size);
|
|
16798
|
+
const lowerGradient = context.createRadialGradient(sceneCenterX + Math.sin(timeMs / 1500) * size * 0.05, sceneCenterY + size * 0.3, size * 0.06, sceneCenterX, sceneCenterY + size * 0.3, size * 0.56);
|
|
16799
|
+
lowerGradient.addColorStop(0, `${palette.secondary}28`);
|
|
16800
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
16801
|
+
context.fillStyle = lowerGradient;
|
|
16802
|
+
context.fillRect(0, 0, size, size);
|
|
16803
|
+
}
|
|
16804
|
+
/**
|
|
16805
|
+
* Draws the soft lower shadow that anchors the octopus in the avatar frame.
|
|
16806
|
+
*
|
|
16807
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16808
|
+
*/
|
|
16809
|
+
function drawBlobbyContinuousShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
|
|
16810
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.046;
|
|
16811
|
+
const cy = size * 0.9 + Math.sin(timeMs / 980) * size * 0.007;
|
|
16812
|
+
const rx = size * (0.2 + morphologyProfile.tentacles.rootSpreadScale * 0.024 + interaction.intensity * 0.022);
|
|
16813
|
+
const ry = size * 0.062;
|
|
16814
|
+
context.save();
|
|
16815
|
+
context.translate(cx, cy);
|
|
16816
|
+
context.scale(1, ry / rx);
|
|
16817
|
+
const blurRadius = rx * 1.42;
|
|
16818
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
16819
|
+
shadowGradient.addColorStop(0, `${palette.shadow}82`);
|
|
16820
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}4a`);
|
|
16821
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1c`);
|
|
16822
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
16823
|
+
context.fillStyle = shadowGradient;
|
|
16824
|
+
context.beginPath();
|
|
16825
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
16826
|
+
context.fill();
|
|
16827
|
+
context.restore();
|
|
16828
|
+
}
|
|
16829
|
+
/**
|
|
16830
|
+
* Number of latitude segments used by the continuous Octopus 3D 4 mesh.
|
|
16831
|
+
*
|
|
16832
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16833
|
+
*/
|
|
16834
|
+
const LATITUDE_PATCH_COUNT = 20;
|
|
16835
|
+
/**
|
|
16836
|
+
* Number of longitude segments used by the continuous Octopus 3D 4 mesh.
|
|
16837
|
+
*
|
|
16838
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16839
|
+
*/
|
|
16840
|
+
const LONGITUDE_PATCH_COUNT = 48;
|
|
16841
|
+
/**
|
|
16842
|
+
* Resolves visible projected patches for the continuous Octopus 3D 4 mesh.
|
|
16843
|
+
*
|
|
16844
|
+
* Within a single frame, mesh corner samples and longitude-only computations (tentacle
|
|
16845
|
+
* influence and lobe wave) are quantized to the patch grid and computed once each rather
|
|
16846
|
+
* than re-evaluated for every patch corner.
|
|
16847
|
+
*
|
|
16848
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16849
|
+
*/
|
|
16850
|
+
function resolveVisibleBlobbyContinuousPatches(options) {
|
|
16851
|
+
const { center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette } = options;
|
|
16852
|
+
const latitudePatchCount = LATITUDE_PATCH_COUNT;
|
|
16853
|
+
const longitudePatchCount = LONGITUDE_PATCH_COUNT;
|
|
16854
|
+
const surfacePatches = [];
|
|
16855
|
+
const latitudeBoundaries = new Float64Array(latitudePatchCount + 1);
|
|
16856
|
+
const longitudeBoundaries = new Float64Array(longitudePatchCount + 1);
|
|
16857
|
+
for (let boundaryIndex = 0; boundaryIndex <= latitudePatchCount; boundaryIndex++) {
|
|
16858
|
+
latitudeBoundaries[boundaryIndex] = -Math.PI / 2 + (boundaryIndex / latitudePatchCount) * Math.PI;
|
|
16859
|
+
}
|
|
16860
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
16861
|
+
longitudeBoundaries[boundaryIndex] = -Math.PI + (boundaryIndex / longitudePatchCount) * Math.PI * 2;
|
|
16862
|
+
}
|
|
16863
|
+
const cachedTentacleInfluencesByCornerLongitude = new Array(longitudePatchCount + 1);
|
|
16864
|
+
const cachedLobeWavesByCornerLongitude = new Float64Array(longitudePatchCount + 1);
|
|
16865
|
+
const cachedTentacleInfluencesByPatchCenterLongitude = new Array(longitudePatchCount);
|
|
16866
|
+
const cachedLobeWavesByPatchCenterLongitude = new Float64Array(longitudePatchCount);
|
|
16867
|
+
const cachedCosByPatchCenterLongitude = new Float64Array(longitudePatchCount);
|
|
16868
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
16869
|
+
const cornerLongitude = longitudeBoundaries[boundaryIndex];
|
|
16870
|
+
cachedTentacleInfluencesByCornerLongitude[boundaryIndex] = resolveBlobbyTentacleInfluence(options, cornerLongitude);
|
|
16871
|
+
cachedLobeWavesByCornerLongitude[boundaryIndex] = resolveBlobbyLobeWave(options, cornerLongitude);
|
|
16872
|
+
}
|
|
16873
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
16874
|
+
const patchCenterLongitude = (longitudeBoundaries[longitudeIndex] + longitudeBoundaries[longitudeIndex + 1]) / 2;
|
|
16875
|
+
cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex] = resolveBlobbyTentacleInfluence(options, patchCenterLongitude);
|
|
16876
|
+
cachedLobeWavesByPatchCenterLongitude[longitudeIndex] = resolveBlobbyLobeWave(options, patchCenterLongitude);
|
|
16877
|
+
cachedCosByPatchCenterLongitude[longitudeIndex] = Math.max(0, Math.cos(patchCenterLongitude));
|
|
16878
|
+
}
|
|
16879
|
+
const cornerCount = (latitudePatchCount + 1) * (longitudePatchCount + 1);
|
|
16880
|
+
const transformedCornerSamples = new Array(cornerCount);
|
|
16881
|
+
for (let latitudeBoundaryIndex = 0; latitudeBoundaryIndex <= latitudePatchCount; latitudeBoundaryIndex++) {
|
|
16882
|
+
const cornerLatitude = latitudeBoundaries[latitudeBoundaryIndex];
|
|
16883
|
+
for (let longitudeBoundaryIndex = 0; longitudeBoundaryIndex <= longitudePatchCount; longitudeBoundaryIndex++) {
|
|
16884
|
+
const cornerLongitude = longitudeBoundaries[longitudeBoundaryIndex];
|
|
16885
|
+
const cornerIndex = latitudeBoundaryIndex * (longitudePatchCount + 1) + longitudeBoundaryIndex;
|
|
16886
|
+
const cornerSample = sampleBlobbyContinuousSurfacePointWithLongitudeCache(options, cornerLatitude, cornerLongitude, cachedTentacleInfluencesByCornerLongitude[longitudeBoundaryIndex], cachedLobeWavesByCornerLongitude[longitudeBoundaryIndex]);
|
|
16887
|
+
transformedCornerSamples[cornerIndex] = transformScenePoint(cornerSample, center, rotationX, rotationY);
|
|
16888
|
+
}
|
|
16889
|
+
}
|
|
16890
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
16891
|
+
const startLatitude = latitudeBoundaries[latitudeIndex];
|
|
16892
|
+
const endLatitude = latitudeBoundaries[latitudeIndex + 1];
|
|
16893
|
+
const centerLatitude = (startLatitude + endLatitude) / 2;
|
|
16894
|
+
const verticalProgress = (Math.sin(centerLatitude) + 1) / 2;
|
|
16895
|
+
const startCornerRowOffset = latitudeIndex * (longitudePatchCount + 1);
|
|
16896
|
+
const endCornerRowOffset = (latitudeIndex + 1) * (longitudePatchCount + 1);
|
|
16897
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
16898
|
+
const transformedCorners = [
|
|
16899
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex],
|
|
16900
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex + 1],
|
|
16901
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex + 1],
|
|
16902
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex],
|
|
16903
|
+
];
|
|
16904
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
16905
|
+
if (surfaceNormal.z <= 0.006) {
|
|
16906
|
+
continue;
|
|
16907
|
+
}
|
|
16908
|
+
const projectedCorners = [
|
|
16909
|
+
projectScenePoint(transformedCorners[0], size, sceneCenterX, sceneCenterY),
|
|
16910
|
+
projectScenePoint(transformedCorners[1], size, sceneCenterX, sceneCenterY),
|
|
16911
|
+
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
16912
|
+
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
16913
|
+
];
|
|
16914
|
+
const lightIntensity = clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1);
|
|
16915
|
+
const rimLightIntensity = Math.pow(clampNumber$1(dotProduct3D(surfaceNormal, RIM_LIGHT_DIRECTION), 0, 1), 2.6);
|
|
16916
|
+
surfacePatches.push({
|
|
16917
|
+
corners: projectedCorners,
|
|
16918
|
+
averageDepth: (transformedCorners[0].z +
|
|
16919
|
+
transformedCorners[1].z +
|
|
16920
|
+
transformedCorners[2].z +
|
|
16921
|
+
transformedCorners[3].z) /
|
|
16922
|
+
4,
|
|
16923
|
+
lightIntensity,
|
|
16924
|
+
rimLightIntensity,
|
|
16925
|
+
fillStyle: resolveBlobbySurfacePatchFillStyle(palette, verticalProgress, cachedCosByPatchCenterLongitude[longitudeIndex], cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex].core, cachedLobeWavesByPatchCenterLongitude[longitudeIndex]),
|
|
16926
|
+
outlineColor: verticalProgress < 0.52 ? `${palette.highlight}5c` : `${palette.shadow}66`,
|
|
16927
|
+
});
|
|
16928
|
+
}
|
|
16929
|
+
}
|
|
16930
|
+
return surfacePatches;
|
|
16931
|
+
}
|
|
16932
|
+
/**
|
|
16933
|
+
* Samples one point on the continuous Octopus 3D 4 surface.
|
|
16934
|
+
*
|
|
16935
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16936
|
+
*/
|
|
16937
|
+
function sampleBlobbyContinuousSurfacePoint(options, latitude, longitude) {
|
|
16938
|
+
return sampleBlobbyContinuousSurfacePointWithLongitudeCache(options, latitude, longitude, resolveBlobbyTentacleInfluence(options, longitude), resolveBlobbyLobeWave(options, longitude));
|
|
16939
|
+
}
|
|
16940
|
+
/**
|
|
16941
|
+
* Samples one point on the continuous Octopus 3D 4 surface using precomputed longitude-only values.
|
|
16942
|
+
*
|
|
16943
|
+
* The patch loop quantizes the mesh into a fixed corner grid, so the same longitude is reused
|
|
16944
|
+
* across every latitude row and each tentacle/lobe value is computed once per frame instead
|
|
16945
|
+
* of `latitudePatchCount * 4` times.
|
|
16946
|
+
*
|
|
16947
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
16948
|
+
*/
|
|
16949
|
+
function sampleBlobbyContinuousSurfacePointWithLongitudeCache(options, latitude, longitude, tentacleInfluence, lowerLobeWave) {
|
|
16950
|
+
const { radiusX, radiusY, radiusZ, morphologyProfile, timeMs, animationPhase } = options;
|
|
16951
|
+
const cosineLatitude = Math.max(0, Math.cos(latitude));
|
|
16952
|
+
const verticalProgress = (Math.sin(latitude) + 1) / 2;
|
|
16953
|
+
const upperBlend = Math.pow(1 - verticalProgress, 1.32);
|
|
16954
|
+
const lowerBlend = smoothStep(0.34, 1, verticalProgress);
|
|
16955
|
+
const tipBlend = smoothStep(0.66, 1, verticalProgress);
|
|
16956
|
+
const centerPull = resolveSignedAngularDistance(longitude, tentacleInfluence.centerLongitude);
|
|
16957
|
+
const effectiveLongitude = longitude + centerPull * lowerBlend * tentacleInfluence.core * (0.26 + tipBlend * 0.22);
|
|
16958
|
+
const mantleRipple = Math.sin(longitude * morphologyProfile.body.lobeCount +
|
|
16959
|
+
animationPhase * 0.6 +
|
|
16960
|
+
timeMs / (1700 + morphologyProfile.body.lobeCount * 28)) *
|
|
16961
|
+
(0.018 + morphologyProfile.body.wobbleAmplitudeRatio * 0.78) *
|
|
16962
|
+
(0.32 + lowerBlend * 0.7);
|
|
16963
|
+
const primaryTentacleWave = Math.sin(timeMs / 740 + tentacleInfluence.primaryPhase + verticalProgress * 2.6) *
|
|
16964
|
+
lowerBlend *
|
|
16965
|
+
tentacleInfluence.core *
|
|
16966
|
+
tentacleInfluence.swayScale;
|
|
16967
|
+
const secondaryTentacleWave = Math.sin(timeMs / 470 + tentacleInfluence.secondaryPhase + verticalProgress * 4.2) *
|
|
16968
|
+
lowerBlend *
|
|
16969
|
+
tentacleInfluence.core *
|
|
16970
|
+
tentacleInfluence.swayScale *
|
|
16971
|
+
0.42;
|
|
16972
|
+
const tentacleCurl = Math.sin(timeMs / 1180 + tentacleInfluence.primaryPhase * 0.6 + verticalProgress * 3.2) *
|
|
16973
|
+
tipBlend *
|
|
16974
|
+
tentacleInfluence.core *
|
|
16975
|
+
tentacleInfluence.curlScale *
|
|
16976
|
+
0.36;
|
|
16977
|
+
const horizontalScale = 1.06 +
|
|
16978
|
+
mantleRipple +
|
|
16979
|
+
lowerBlend * (0.18 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.12) +
|
|
16980
|
+
lowerBlend * tentacleInfluence.core * (0.22 + lowerLobeWave * 0.14) -
|
|
16981
|
+
upperBlend * 0.08;
|
|
16982
|
+
const depthScale = 1.08 +
|
|
16983
|
+
upperBlend * 0.16 +
|
|
16984
|
+
Math.max(0, Math.cos(effectiveLongitude)) * 0.12 +
|
|
16985
|
+
lowerBlend * tentacleInfluence.core * (0.12 + tentacleInfluence.depthScale * 0.07) -
|
|
16986
|
+
Math.max(0, -Math.cos(effectiveLongitude)) * 0.05;
|
|
16987
|
+
const tentacleTubeRadius = lowerBlend *
|
|
16988
|
+
tentacleInfluence.core *
|
|
16989
|
+
(0.12 + tipBlend * 0.07 + tentacleInfluence.widthScale * 0.028) *
|
|
16990
|
+
radiusX;
|
|
16991
|
+
const planarRadiusX = cosineLatitude * radiusX * horizontalScale + tentacleTubeRadius;
|
|
16992
|
+
const planarRadiusZ = cosineLatitude * radiusZ * depthScale + tentacleTubeRadius * 0.74;
|
|
16993
|
+
const lowerDrop = lowerBlend *
|
|
16994
|
+
radiusY *
|
|
16995
|
+
(0.2 +
|
|
16996
|
+
tentacleInfluence.core *
|
|
16997
|
+
(0.42 +
|
|
16998
|
+
tentacleInfluence.lengthScale * 0.24 +
|
|
16999
|
+
(morphologyProfile.tentacles.flowLengthScale - 1) * 0.1));
|
|
17000
|
+
const combinedTentacleSway = (primaryTentacleWave + secondaryTentacleWave) * radiusX * (0.06 + tipBlend * 0.06);
|
|
17001
|
+
return {
|
|
17002
|
+
x: Math.sin(effectiveLongitude) * planarRadiusX +
|
|
17003
|
+
combinedTentacleSway +
|
|
17004
|
+
tentacleCurl * radiusX * 0.18,
|
|
17005
|
+
y: Math.sin(latitude) * radiusY * (1 + upperBlend * 0.14) -
|
|
17006
|
+
upperBlend * radiusY * 0.12 +
|
|
17007
|
+
lowerDrop +
|
|
17008
|
+
Math.sin(timeMs / 1380 + animationPhase + latitude * 1.5) * lowerBlend * radiusY * 0.022 +
|
|
17009
|
+
Math.cos(timeMs / 820 + tentacleInfluence.primaryPhase) *
|
|
17010
|
+
lowerBlend *
|
|
17011
|
+
tipBlend *
|
|
17012
|
+
tentacleInfluence.core *
|
|
17013
|
+
radiusY *
|
|
17014
|
+
0.04,
|
|
17015
|
+
z: Math.cos(effectiveLongitude) * planarRadiusZ +
|
|
17016
|
+
Math.cos(timeMs / 960 + tentacleInfluence.primaryPhase + verticalProgress) *
|
|
17017
|
+
lowerBlend *
|
|
17018
|
+
tentacleInfluence.core *
|
|
17019
|
+
radiusZ *
|
|
17020
|
+
0.044 +
|
|
17021
|
+
tentacleCurl * radiusZ * 0.14,
|
|
17022
|
+
};
|
|
17023
|
+
}
|
|
17024
|
+
/**
|
|
17025
|
+
* Blends nearby seeded tentacle profiles at one mesh longitude.
|
|
17026
|
+
*
|
|
17027
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17028
|
+
*/
|
|
17029
|
+
function resolveBlobbyTentacleInfluence(options, longitude) {
|
|
17030
|
+
let totalWeight = 0;
|
|
17031
|
+
let weightedSin = 0;
|
|
17032
|
+
let weightedCos = 0;
|
|
17033
|
+
let weightedWidthScale = 0;
|
|
17034
|
+
let weightedLengthScale = 0;
|
|
17035
|
+
let weightedSwayScale = 0;
|
|
17036
|
+
let weightedDepthScale = 0;
|
|
17037
|
+
let weightedCurlScale = 0;
|
|
17038
|
+
let weightedPrimaryPhase = 0;
|
|
17039
|
+
let weightedSecondaryPhase = 0;
|
|
17040
|
+
for (const tentacleProfile of options.tentacleProfiles) {
|
|
17041
|
+
const distance = Math.abs(resolveSignedAngularDistance(longitude, tentacleProfile.centerLongitude));
|
|
17042
|
+
const width = 0.22 * tentacleProfile.widthScale;
|
|
17043
|
+
const weight = Math.exp(-(distance * distance) / (width * width));
|
|
17044
|
+
totalWeight += weight;
|
|
17045
|
+
weightedSin += Math.sin(tentacleProfile.centerLongitude) * weight;
|
|
17046
|
+
weightedCos += Math.cos(tentacleProfile.centerLongitude) * weight;
|
|
17047
|
+
weightedWidthScale += tentacleProfile.widthScale * weight;
|
|
17048
|
+
weightedLengthScale += tentacleProfile.lengthScale * weight;
|
|
17049
|
+
weightedSwayScale += tentacleProfile.swayScale * weight;
|
|
17050
|
+
weightedDepthScale += tentacleProfile.depthScale * weight;
|
|
17051
|
+
weightedCurlScale += tentacleProfile.curlScale * weight;
|
|
17052
|
+
weightedPrimaryPhase += tentacleProfile.primaryPhase * weight;
|
|
17053
|
+
weightedSecondaryPhase += tentacleProfile.secondaryPhase * weight;
|
|
17054
|
+
}
|
|
17055
|
+
if (totalWeight < 0.0001) {
|
|
17056
|
+
return {
|
|
17057
|
+
core: 0,
|
|
17058
|
+
centerLongitude: longitude,
|
|
17059
|
+
widthScale: 1,
|
|
17060
|
+
lengthScale: 1,
|
|
17061
|
+
swayScale: 1,
|
|
17062
|
+
depthScale: 1,
|
|
17063
|
+
curlScale: 1,
|
|
17064
|
+
primaryPhase: 0,
|
|
17065
|
+
secondaryPhase: 0,
|
|
17066
|
+
};
|
|
17067
|
+
}
|
|
17068
|
+
return {
|
|
17069
|
+
core: clampNumber$1(totalWeight, 0, 1),
|
|
17070
|
+
centerLongitude: Math.atan2(weightedSin / totalWeight, weightedCos / totalWeight),
|
|
17071
|
+
widthScale: weightedWidthScale / totalWeight,
|
|
17072
|
+
lengthScale: weightedLengthScale / totalWeight,
|
|
17073
|
+
swayScale: weightedSwayScale / totalWeight,
|
|
17074
|
+
depthScale: weightedDepthScale / totalWeight,
|
|
17075
|
+
curlScale: weightedCurlScale / totalWeight,
|
|
17076
|
+
primaryPhase: weightedPrimaryPhase / totalWeight,
|
|
17077
|
+
secondaryPhase: weightedSecondaryPhase / totalWeight,
|
|
17078
|
+
};
|
|
17079
|
+
}
|
|
17080
|
+
/**
|
|
17081
|
+
* Resolves the soft lower wave that makes the continuous mesh read as a set of tentacles.
|
|
17082
|
+
*
|
|
17083
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17084
|
+
*/
|
|
17085
|
+
function resolveBlobbyLobeWave(options, longitude) {
|
|
17086
|
+
const { morphologyProfile, animationPhase, timeMs } = options;
|
|
17087
|
+
return ((Math.cos(longitude * OCTOPUS_TENTACLE_COUNT +
|
|
17088
|
+
animationPhase +
|
|
17089
|
+
timeMs / (940 + morphologyProfile.body.lobeCount * 18)) +
|
|
17090
|
+
1) /
|
|
17091
|
+
2);
|
|
17092
|
+
}
|
|
17093
|
+
/**
|
|
17094
|
+
* Resolves one base fill tone for a patch on the continuous octopus mesh.
|
|
17095
|
+
*
|
|
17096
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17097
|
+
*/
|
|
17098
|
+
function resolveBlobbySurfacePatchFillStyle(palette, verticalProgress, forwardness, tentacleCore, lowerLobeWave) {
|
|
17099
|
+
const tonalProgress = clampNumber$1(verticalProgress + lowerLobeWave * 0.1 + tentacleCore * 0.08 - forwardness * 0.08, 0, 1);
|
|
17100
|
+
if (tonalProgress < 0.12) {
|
|
17101
|
+
return palette.highlight;
|
|
17102
|
+
}
|
|
17103
|
+
if (tonalProgress < 0.3) {
|
|
17104
|
+
return palette.secondary;
|
|
17105
|
+
}
|
|
17106
|
+
if (tonalProgress < 0.72) {
|
|
17107
|
+
return forwardness > 0.56 ? palette.secondary : palette.primary;
|
|
17108
|
+
}
|
|
17109
|
+
return tentacleCore > 0.44 ? `${palette.primary}f4` : `${palette.shadow}ee`;
|
|
17110
|
+
}
|
|
17111
|
+
/**
|
|
17112
|
+
* Draws one projected mesh patch with multi-pass shading and a soft edge.
|
|
17113
|
+
*
|
|
17114
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17115
|
+
*/
|
|
17116
|
+
function drawBlobbyContinuousSurfacePatch(context, surfacePatch) {
|
|
17117
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
17118
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
17119
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.2 * surfacePatch.lightIntensity})`);
|
|
17120
|
+
}
|
|
17121
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
17122
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.26 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
17123
|
+
}
|
|
17124
|
+
if (surfacePatch.rimLightIntensity > 0.04) {
|
|
17125
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 247, 230, ${0.22 * surfacePatch.rimLightIntensity})`);
|
|
17126
|
+
}
|
|
17127
|
+
context.save();
|
|
17128
|
+
context.beginPath();
|
|
17129
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
17130
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
17131
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
17132
|
+
}
|
|
17133
|
+
context.closePath();
|
|
17134
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
17135
|
+
context.lineWidth = Math.max(0.6, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0026);
|
|
17136
|
+
context.lineJoin = 'round';
|
|
17137
|
+
context.stroke();
|
|
17138
|
+
context.restore();
|
|
17139
|
+
}
|
|
17140
|
+
/**
|
|
17141
|
+
* Draws projected mantle-current lines on the front of the mesh.
|
|
17142
|
+
*
|
|
17143
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17144
|
+
*/
|
|
17145
|
+
function drawBlobbyContinuousCurrents(options) {
|
|
17146
|
+
const { context, surfaceOptions, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, morphologyProfile, timeMs, animationPhase, } = options;
|
|
17147
|
+
const currentCount = Math.min(6, morphologyProfile.details.mantleCurrentCount);
|
|
17148
|
+
const centerIndex = (currentCount - 1) / 2;
|
|
17149
|
+
context.save();
|
|
17150
|
+
context.lineCap = 'round';
|
|
17151
|
+
context.lineJoin = 'round';
|
|
17152
|
+
for (let currentIndex = 0; currentIndex < currentCount; currentIndex++) {
|
|
17153
|
+
const baseLongitude = (currentIndex - centerIndex) * 0.15;
|
|
17154
|
+
const projectedPoints = [];
|
|
17155
|
+
for (let sampleIndex = 0; sampleIndex < 9; sampleIndex++) {
|
|
17156
|
+
const progress = sampleIndex / 8;
|
|
17157
|
+
const latitude = -0.48 + progress * 0.78;
|
|
17158
|
+
const longitude = baseLongitude + Math.sin(timeMs / 1140 + animationPhase + currentIndex * 0.7 + progress * 2) * 0.038;
|
|
17159
|
+
const scenePoint = transformScenePoint(sampleBlobbyContinuousSurfacePoint(surfaceOptions, latitude, longitude), center, rotationX, rotationY);
|
|
17160
|
+
if (scenePoint.z > center.z - size * 0.016) {
|
|
17161
|
+
projectedPoints.push(projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
17162
|
+
}
|
|
17163
|
+
}
|
|
17164
|
+
if (projectedPoints.length < 3) {
|
|
17165
|
+
continue;
|
|
17166
|
+
}
|
|
17167
|
+
context.beginPath();
|
|
17168
|
+
context.moveTo(projectedPoints[0].x, projectedPoints[0].y);
|
|
17169
|
+
for (const projectedPoint of projectedPoints.slice(1)) {
|
|
17170
|
+
context.lineTo(projectedPoint.x, projectedPoint.y);
|
|
17171
|
+
}
|
|
17172
|
+
context.strokeStyle = currentIndex % 2 === 0 ? `${palette.highlight}3d` : `${palette.accent}33`;
|
|
17173
|
+
context.lineWidth = size * (0.0055 + currentIndex * 0.00045);
|
|
17174
|
+
context.stroke();
|
|
17175
|
+
}
|
|
17176
|
+
context.restore();
|
|
17177
|
+
}
|
|
17178
|
+
/**
|
|
17179
|
+
* Draws small projected sucker highlights on the waving lower mesh lobes.
|
|
17180
|
+
*
|
|
17181
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17182
|
+
*/
|
|
17183
|
+
function drawBlobbyContinuousSuckers(options) {
|
|
17184
|
+
const { surfaceOptions, size } = options;
|
|
17185
|
+
const { timeMs } = surfaceOptions;
|
|
17186
|
+
for (const tentacleProfile of surfaceOptions.tentacleProfiles) {
|
|
17187
|
+
if (Math.cos(tentacleProfile.centerLongitude) < -0.16) {
|
|
17188
|
+
continue;
|
|
17189
|
+
}
|
|
17190
|
+
for (let suckerIndex = 0; suckerIndex < 4; suckerIndex++) {
|
|
17191
|
+
const latitude = 0.5 + suckerIndex * 0.12;
|
|
17192
|
+
const sideOffset = tentacleProfile.suckerSide * (0.038 + suckerIndex * 0.014) * tentacleProfile.widthScale;
|
|
17193
|
+
const waveOffset = Math.sin(timeMs / 880 + tentacleProfile.primaryPhase + suckerIndex * 0.78) * 0.02;
|
|
17194
|
+
drawBlobbyContinuousSurfaceSpot({
|
|
17195
|
+
...options,
|
|
17196
|
+
latitude,
|
|
17197
|
+
longitude: tentacleProfile.centerLongitude + sideOffset + waveOffset,
|
|
17198
|
+
radiusScale: size * (0.0068 - suckerIndex * 0.0006),
|
|
17199
|
+
});
|
|
17200
|
+
}
|
|
17201
|
+
}
|
|
17202
|
+
}
|
|
17203
|
+
/**
|
|
17204
|
+
* Draws seeded pigment spots across the upper mesh for a richer skin texture.
|
|
17205
|
+
*
|
|
17206
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17207
|
+
*/
|
|
17208
|
+
function drawBlobbySkinSpots(options) {
|
|
17209
|
+
const { context, surfaceOptions, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, skinSpots, } = options;
|
|
17210
|
+
for (const skinSpot of skinSpots) {
|
|
17211
|
+
const localCenter = sampleBlobbyContinuousSurfacePoint(surfaceOptions, skinSpot.latitude, skinSpot.longitude);
|
|
17212
|
+
const sceneCenterPoint = transformScenePoint(localCenter, center, rotationX, rotationY);
|
|
17213
|
+
if (sceneCenterPoint.z <= center.z - size * 0.01) {
|
|
17214
|
+
continue;
|
|
17215
|
+
}
|
|
17216
|
+
const projectedCenterPoint = projectScenePoint(sceneCenterPoint, size, sceneCenterX, sceneCenterY);
|
|
17217
|
+
const spotRadius = size * skinSpot.radiusScale;
|
|
17218
|
+
context.save();
|
|
17219
|
+
context.beginPath();
|
|
17220
|
+
context.arc(projectedCenterPoint.x, projectedCenterPoint.y, spotRadius, 0, Math.PI * 2);
|
|
17221
|
+
context.fillStyle = `${palette.shadow}${formatAlphaHex(skinSpot.opacity)}`;
|
|
17222
|
+
context.fill();
|
|
17223
|
+
context.restore();
|
|
17224
|
+
}
|
|
17225
|
+
}
|
|
17226
|
+
/**
|
|
17227
|
+
* Draws one tiny projected surface spot by sampling local mesh tangents.
|
|
17228
|
+
*
|
|
17229
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17230
|
+
*/
|
|
17231
|
+
function drawBlobbyContinuousSurfaceSpot(options) {
|
|
17232
|
+
const { context, surfaceOptions, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, latitude, longitude, radiusScale, } = options;
|
|
17233
|
+
const localCenter = sampleBlobbyContinuousSurfacePoint(surfaceOptions, latitude, longitude);
|
|
17234
|
+
const localHorizontal = sampleBlobbyContinuousSurfacePoint(surfaceOptions, latitude, longitude + 0.018);
|
|
17235
|
+
const localVertical = sampleBlobbyContinuousSurfacePoint(surfaceOptions, latitude + 0.018, longitude);
|
|
17236
|
+
const sceneCenterPoint = transformScenePoint(localCenter, center, rotationX, rotationY);
|
|
17237
|
+
if (sceneCenterPoint.z <= center.z - size * 0.012) {
|
|
17238
|
+
return;
|
|
17239
|
+
}
|
|
17240
|
+
const projectedCenterPoint = projectScenePoint(sceneCenterPoint, size, sceneCenterX, sceneCenterY);
|
|
17241
|
+
const projectedHorizontalPoint = projectScenePoint(transformScenePoint(localHorizontal, center, rotationX, rotationY), size, sceneCenterX, sceneCenterY);
|
|
17242
|
+
const projectedVerticalPoint = projectScenePoint(transformScenePoint(localVertical, center, rotationX, rotationY), size, sceneCenterX, sceneCenterY);
|
|
17243
|
+
const horizontalRadius = clampNumber$1(Math.hypot(projectedHorizontalPoint.x - projectedCenterPoint.x, projectedHorizontalPoint.y - projectedCenterPoint.y) *
|
|
17244
|
+
radiusScale *
|
|
17245
|
+
0.78, size * 0.003, size * 0.02);
|
|
17246
|
+
const verticalRadius = clampNumber$1(Math.hypot(projectedVerticalPoint.x - projectedCenterPoint.x, projectedVerticalPoint.y - projectedCenterPoint.y) *
|
|
17247
|
+
radiusScale *
|
|
17248
|
+
0.54, size * 0.0024, size * 0.015);
|
|
17249
|
+
const rotation = Math.atan2(projectedHorizontalPoint.y - projectedCenterPoint.y, projectedHorizontalPoint.x - projectedCenterPoint.x);
|
|
17250
|
+
context.save();
|
|
17251
|
+
context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
|
|
17252
|
+
context.rotate(rotation);
|
|
17253
|
+
context.beginPath();
|
|
17254
|
+
context.ellipse(0, 0, horizontalRadius, verticalRadius, 0, 0, Math.PI * 2);
|
|
17255
|
+
context.fillStyle = `${palette.highlight}80`;
|
|
17256
|
+
context.fill();
|
|
17257
|
+
context.strokeStyle = `${palette.highlight}a8`;
|
|
17258
|
+
context.lineWidth = Math.max(0.7, size * 0.0028);
|
|
17259
|
+
context.stroke();
|
|
17260
|
+
context.restore();
|
|
17261
|
+
}
|
|
17262
|
+
/**
|
|
17263
|
+
* Draws a soft, slowly drifting gloss highlight on the front of the mesh.
|
|
17264
|
+
*
|
|
17265
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17266
|
+
*/
|
|
17267
|
+
function drawBlobbyContinuousGloss(options) {
|
|
17268
|
+
const { context, surfaceOptions, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size } = options;
|
|
17269
|
+
const { timeMs, animationPhase } = surfaceOptions;
|
|
17270
|
+
const glossLatitude = -0.3 + Math.sin(timeMs / 2700 + animationPhase) * 0.04;
|
|
17271
|
+
const glossLongitude = -0.18 + Math.cos(timeMs / 2300 + animationPhase * 0.8) * 0.05;
|
|
17272
|
+
const localCenter = sampleBlobbyContinuousSurfacePoint(surfaceOptions, glossLatitude, glossLongitude);
|
|
17273
|
+
const sceneCenterPoint = transformScenePoint(localCenter, center, rotationX, rotationY);
|
|
17274
|
+
if (sceneCenterPoint.z <= center.z) {
|
|
17275
|
+
return;
|
|
17276
|
+
}
|
|
17277
|
+
const projectedCenterPoint = projectScenePoint(sceneCenterPoint, size, sceneCenterX, sceneCenterY);
|
|
17278
|
+
const glossRadius = size * 0.058;
|
|
17279
|
+
context.save();
|
|
17280
|
+
const glossGradient = context.createRadialGradient(projectedCenterPoint.x - glossRadius * 0.3, projectedCenterPoint.y - glossRadius * 0.4, glossRadius * 0.04, projectedCenterPoint.x, projectedCenterPoint.y, glossRadius);
|
|
17281
|
+
glossGradient.addColorStop(0, 'rgba(255, 255, 255, 0.34)');
|
|
17282
|
+
glossGradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.1)');
|
|
17283
|
+
glossGradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
|
|
17284
|
+
context.fillStyle = glossGradient;
|
|
17285
|
+
context.beginPath();
|
|
17286
|
+
context.ellipse(projectedCenterPoint.x, projectedCenterPoint.y, glossRadius * 1.05, glossRadius * 0.78, 0, 0, Math.PI * 2);
|
|
17287
|
+
context.fill();
|
|
17288
|
+
context.restore();
|
|
17289
|
+
}
|
|
17290
|
+
/**
|
|
17291
|
+
* Resolves a signed angular distance from the source longitude to the target longitude.
|
|
17292
|
+
*
|
|
17293
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17294
|
+
*/
|
|
17295
|
+
function resolveSignedAngularDistance(sourceLongitude, targetLongitude) {
|
|
17296
|
+
return Math.atan2(Math.sin(targetLongitude - sourceLongitude), Math.cos(targetLongitude - sourceLongitude));
|
|
17297
|
+
}
|
|
17298
|
+
/**
|
|
17299
|
+
* Smoothly maps a value between two bounds into `[0, 1]`.
|
|
17300
|
+
*
|
|
17301
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17302
|
+
*/
|
|
17303
|
+
function smoothStep(edgeStart, edgeEnd, value) {
|
|
17304
|
+
const progress = clampNumber$1((value - edgeStart) / (edgeEnd - edgeStart), 0, 1);
|
|
17305
|
+
return progress * progress * (3 - 2 * progress);
|
|
17306
|
+
}
|
|
17307
|
+
/**
|
|
17308
|
+
* Converts an opacity ratio into a two-digit hexadecimal alpha suffix.
|
|
17309
|
+
*
|
|
17310
|
+
* @private helper of `octopus3d4AvatarVisual`
|
|
17311
|
+
*/
|
|
17312
|
+
function formatAlphaHex(opacity) {
|
|
17313
|
+
return Math.round(clampNumber$1(opacity, 0, 1) * 255)
|
|
17314
|
+
.toString(16)
|
|
17315
|
+
.padStart(2, '0');
|
|
17316
|
+
}
|
|
17317
|
+
|
|
15592
17318
|
/* eslint-disable no-magic-numbers */
|
|
15593
17319
|
/**
|
|
15594
17320
|
* Octopus avatar visual.
|
|
@@ -16359,6 +18085,8 @@
|
|
|
16359
18085
|
octopus3AvatarVisual,
|
|
16360
18086
|
octopus3dAvatarVisual,
|
|
16361
18087
|
octopus3d2AvatarVisual,
|
|
18088
|
+
octopus3d3AvatarVisual,
|
|
18089
|
+
octopus3d4AvatarVisual,
|
|
16362
18090
|
asciiOctopusAvatarVisual,
|
|
16363
18091
|
minecraftAvatarVisual,
|
|
16364
18092
|
minecraft2AvatarVisual,
|
|
@@ -17038,6 +18766,70 @@
|
|
|
17038
18766
|
}
|
|
17039
18767
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
17040
18768
|
|
|
18769
|
+
/**
|
|
18770
|
+
* META VISIBILITY commitment definition.
|
|
18771
|
+
*
|
|
18772
|
+
* The `META VISIBILITY` commitment stores whether an agent is public, private, or unlisted.
|
|
18773
|
+
* Agents Server mirrors this value into the database for efficient filtering, but the book
|
|
18774
|
+
* commitment remains the editable source of truth.
|
|
18775
|
+
*
|
|
18776
|
+
* @private Metadata-only commitment used by Agents Server.
|
|
18777
|
+
*/
|
|
18778
|
+
class MetaVisibilityCommitmentDefinition extends BaseCommitmentDefinition {
|
|
18779
|
+
constructor() {
|
|
18780
|
+
super('META VISIBILITY');
|
|
18781
|
+
}
|
|
18782
|
+
/**
|
|
18783
|
+
* Short one-line description of META VISIBILITY.
|
|
18784
|
+
*/
|
|
18785
|
+
get description() {
|
|
18786
|
+
return 'Set whether the agent is private, unlisted, or public.';
|
|
18787
|
+
}
|
|
18788
|
+
/**
|
|
18789
|
+
* Icon for this commitment.
|
|
18790
|
+
*/
|
|
18791
|
+
get icon() {
|
|
18792
|
+
return '👁️';
|
|
18793
|
+
}
|
|
18794
|
+
/**
|
|
18795
|
+
* Markdown documentation for META VISIBILITY commitment.
|
|
18796
|
+
*/
|
|
18797
|
+
get documentation() {
|
|
18798
|
+
return spacetrim.spaceTrim(`
|
|
18799
|
+
# META VISIBILITY
|
|
18800
|
+
|
|
18801
|
+
Sets the agent visibility used by Agents Server.
|
|
18802
|
+
|
|
18803
|
+
## Allowed values
|
|
18804
|
+
|
|
18805
|
+
- \`PRIVATE\` - accessible only to signed-in users with access.
|
|
18806
|
+
- \`UNLISTED\` - accessible by direct link but hidden from public listings.
|
|
18807
|
+
- \`PUBLIC\` - visible in public listings and accessible by anyone.
|
|
18808
|
+
|
|
18809
|
+
## Key aspects
|
|
18810
|
+
|
|
18811
|
+
- Does not modify the agent's behavior, system message, or tools.
|
|
18812
|
+
- Whitespace and letter case are normalized when persisted.
|
|
18813
|
+
- If multiple \`META VISIBILITY\` commitments are present, persistence keeps one normalized value.
|
|
18814
|
+
- Agents Server mirrors the value into the database for filtering, but the book is the source of truth.
|
|
18815
|
+
|
|
18816
|
+
## Example
|
|
18817
|
+
|
|
18818
|
+
\`\`\`book
|
|
18819
|
+
Helpful Assistant
|
|
18820
|
+
|
|
18821
|
+
GOAL Be helpful and friendly.
|
|
18822
|
+
META VISIBILITY PUBLIC
|
|
18823
|
+
\`\`\`
|
|
18824
|
+
`);
|
|
18825
|
+
}
|
|
18826
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
18827
|
+
// META VISIBILITY is metadata only and does not alter model requirements.
|
|
18828
|
+
return requirements;
|
|
18829
|
+
}
|
|
18830
|
+
}
|
|
18831
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
18832
|
+
|
|
17041
18833
|
/**
|
|
17042
18834
|
* META VOICE commitment definition
|
|
17043
18835
|
*
|
|
@@ -18647,7 +20439,15 @@
|
|
|
18647
20439
|
* Builds the teammate request text, optionally including context.
|
|
18648
20440
|
*/
|
|
18649
20441
|
function buildTeammateRequest(message, context) {
|
|
18650
|
-
|
|
20442
|
+
if (!context) {
|
|
20443
|
+
return message;
|
|
20444
|
+
}
|
|
20445
|
+
return spacetrim.spaceTrim((block) => `
|
|
20446
|
+
${block(message)}
|
|
20447
|
+
|
|
20448
|
+
Context:
|
|
20449
|
+
${block(context)}
|
|
20450
|
+
`);
|
|
18651
20451
|
}
|
|
18652
20452
|
/**
|
|
18653
20453
|
* Builds a minimal chat prompt for teammate calls.
|
|
@@ -22473,7 +24273,11 @@
|
|
|
22473
24273
|
const lineRangedContent = applyOptionalLineRange(decodedContent, args.startLine, args.endLine);
|
|
22474
24274
|
const wasCharacterTruncated = lineRangedContent.length > MAX_PROJECT_FILE_CONTENT_CHARACTERS;
|
|
22475
24275
|
const contentToReturn = wasCharacterTruncated
|
|
22476
|
-
?
|
|
24276
|
+
? spacetrim.spaceTrim((block) => `
|
|
24277
|
+
${block(lineRangedContent.slice(0, MAX_PROJECT_FILE_CONTENT_CHARACTERS))}
|
|
24278
|
+
|
|
24279
|
+
[...truncated...]
|
|
24280
|
+
`)
|
|
22477
24281
|
: lineRangedContent;
|
|
22478
24282
|
const wasTruncated = decoded.isTruncated || wasCharacterTruncated;
|
|
22479
24283
|
if (wasCharacterTruncated) {
|
|
@@ -25549,6 +27353,7 @@
|
|
|
25549
27353
|
new MetaDomainCommitmentDefinition(),
|
|
25550
27354
|
new MetaDisclaimerCommitmentDefinition(),
|
|
25551
27355
|
new MetaInputPlaceholderCommitmentDefinition(),
|
|
27356
|
+
new MetaVisibilityCommitmentDefinition(),
|
|
25552
27357
|
new MetaCommitmentDefinition(),
|
|
25553
27358
|
new MetaVoiceCommitmentDefinition(),
|
|
25554
27359
|
new NoteCommitmentDefinition('NOTE'),
|
|
@@ -26009,11 +27814,19 @@
|
|
|
26009
27814
|
try {
|
|
26010
27815
|
const json = JSON.parse(content);
|
|
26011
27816
|
const formattedJson = JSON.stringify(json, null, 4);
|
|
26012
|
-
return
|
|
27817
|
+
return spacetrim.spaceTrim((block) => `
|
|
27818
|
+
\`\`\`json
|
|
27819
|
+
${block(formattedJson)}
|
|
27820
|
+
\`\`\`
|
|
27821
|
+
`);
|
|
26013
27822
|
}
|
|
26014
27823
|
catch (error) {
|
|
26015
27824
|
// If JSON is invalid, still import it but maybe not as pretty JSON
|
|
26016
|
-
return
|
|
27825
|
+
return spacetrim.spaceTrim((block) => `
|
|
27826
|
+
\`\`\`json
|
|
27827
|
+
${block(content)}
|
|
27828
|
+
\`\`\`
|
|
27829
|
+
`);
|
|
26017
27830
|
}
|
|
26018
27831
|
},
|
|
26019
27832
|
};
|
|
@@ -26037,7 +27850,11 @@
|
|
|
26037
27850
|
import(content, mimeType) {
|
|
26038
27851
|
const extension = mimeTypeToExtension(mimeType);
|
|
26039
27852
|
const codeBlockType = extension || 'txt';
|
|
26040
|
-
return
|
|
27853
|
+
return spacetrim.spaceTrim((block) => `
|
|
27854
|
+
\`\`\`${codeBlockType}
|
|
27855
|
+
${block(content)}
|
|
27856
|
+
\`\`\`
|
|
27857
|
+
`);
|
|
26041
27858
|
},
|
|
26042
27859
|
};
|
|
26043
27860
|
|
|
@@ -26284,11 +28101,19 @@
|
|
|
26284
28101
|
const examples = [];
|
|
26285
28102
|
const initialMessage = (_a = parseResult.commitments.find((commitment) => commitment.type === 'INITIAL MESSAGE')) === null || _a === void 0 ? void 0 : _a.content;
|
|
26286
28103
|
if (initialMessage) {
|
|
26287
|
-
examples.push(
|
|
28104
|
+
examples.push(spacetrim.spaceTrim((block) => `
|
|
28105
|
+
**Agent:**
|
|
28106
|
+
${block(initialMessage)}
|
|
28107
|
+
`));
|
|
26288
28108
|
}
|
|
26289
28109
|
if (samples && samples.length > 0) {
|
|
26290
28110
|
for (const sample of samples) {
|
|
26291
|
-
examples.push(
|
|
28111
|
+
examples.push(spacetrim.spaceTrim((block) => `
|
|
28112
|
+
**User:** ${block(String(sample.question))}
|
|
28113
|
+
|
|
28114
|
+
**Agent:**
|
|
28115
|
+
${block(sample.answer)}
|
|
28116
|
+
`));
|
|
26292
28117
|
}
|
|
26293
28118
|
}
|
|
26294
28119
|
return examples;
|
|
@@ -26873,6 +28698,7 @@
|
|
|
26873
28698
|
'META COLOR': applyMetaColorContent,
|
|
26874
28699
|
'META FONT': applyMetaFontContent,
|
|
26875
28700
|
'META VOICE': applyMetaVoiceContent,
|
|
28701
|
+
'META VISIBILITY': applyMetaVisibilityContent,
|
|
26876
28702
|
};
|
|
26877
28703
|
/**
|
|
26878
28704
|
* Applies META-style commitments that mutate parsed profile metadata.
|
|
@@ -26902,6 +28728,10 @@
|
|
|
26902
28728
|
applyMetaAvatarContent(state, metaValue);
|
|
26903
28729
|
return;
|
|
26904
28730
|
}
|
|
28731
|
+
if (metaTypeRaw.toUpperCase() === 'VISIBILITY') {
|
|
28732
|
+
applyMetaVisibilityContent(state, metaValue);
|
|
28733
|
+
return;
|
|
28734
|
+
}
|
|
26905
28735
|
const metaType = normalizeTo_camelCase(metaTypeRaw);
|
|
26906
28736
|
state.meta[metaType] = metaValue;
|
|
26907
28737
|
}
|
|
@@ -26978,6 +28808,15 @@
|
|
|
26978
28808
|
function applyMetaVoiceContent(state, content) {
|
|
26979
28809
|
state.meta.voice = spacetrim.spaceTrim(content);
|
|
26980
28810
|
}
|
|
28811
|
+
/**
|
|
28812
|
+
* Applies META VISIBILITY content into the normalized `meta.visibility` field.
|
|
28813
|
+
*/
|
|
28814
|
+
function applyMetaVisibilityContent(state, content) {
|
|
28815
|
+
const visibility = normalizeAgentVisibility(content);
|
|
28816
|
+
if (visibility) {
|
|
28817
|
+
state.meta.visibility = visibility;
|
|
28818
|
+
}
|
|
28819
|
+
}
|
|
26981
28820
|
/**
|
|
26982
28821
|
* Normalizes the separator in the content
|
|
26983
28822
|
*
|
|
@@ -28003,7 +29842,11 @@
|
|
|
28003
29842
|
* @private internal utility of `createStandaloneBookLanguageMarkdown`
|
|
28004
29843
|
*/
|
|
28005
29844
|
function renderDocumentationSection(title, documentation) {
|
|
28006
|
-
return
|
|
29845
|
+
return spacetrim.spaceTrim((block) => `
|
|
29846
|
+
#### ${title}
|
|
29847
|
+
|
|
29848
|
+
${block(removeLeadingTopLevelHeading(documentation))}
|
|
29849
|
+
`);
|
|
28007
29850
|
}
|
|
28008
29851
|
/**
|
|
28009
29852
|
* Renders the documentation body for one grouped commitment entry.
|
|
@@ -28079,6 +29922,7 @@
|
|
|
28079
29922
|
'META DESCRIPTION',
|
|
28080
29923
|
'META DISCLAIMER',
|
|
28081
29924
|
'META INPUT PLACEHOLDER',
|
|
29925
|
+
'META VISIBILITY',
|
|
28082
29926
|
'META COLOR',
|
|
28083
29927
|
'META FONT',
|
|
28084
29928
|
'META VOICE',
|
|
@@ -28654,7 +30498,9 @@
|
|
|
28654
30498
|
* @private internal utility of `Book`
|
|
28655
30499
|
*/
|
|
28656
30500
|
function parseCommitmentHeader(line) {
|
|
28657
|
-
|
|
30501
|
+
// Require at least 2 characters in the first keyword word to avoid treating common
|
|
30502
|
+
// single-letter words (e.g. "V" in Czech, "I" or "A" in English) as commitment headers.
|
|
30503
|
+
const match = /^([A-Z][A-Z0-9]+(?: [A-Z0-9]+)*)(?:\s+(.*))?$/u.exec(line);
|
|
28658
30504
|
if (!match) {
|
|
28659
30505
|
return null;
|
|
28660
30506
|
}
|
|
@@ -28752,18 +30598,23 @@
|
|
|
28752
30598
|
*
|
|
28753
30599
|
* @private shared persistence helper for `AgentCollectionInSupabase`
|
|
28754
30600
|
*/
|
|
28755
|
-
function prepareAgentSourceForPersistence(agentSource) {
|
|
28756
|
-
|
|
28757
|
-
const
|
|
28758
|
-
const
|
|
28759
|
-
|
|
28760
|
-
|
|
28761
|
-
|
|
28762
|
-
|
|
30601
|
+
function prepareAgentSourceForPersistence(agentSource, options = {}) {
|
|
30602
|
+
var _a, _b, _c;
|
|
30603
|
+
const originalAgentProfile = parseAgentSource(agentSource);
|
|
30604
|
+
const permanentId = originalAgentProfile.permanentId;
|
|
30605
|
+
agentSource = stripMetaIdLines(agentSource);
|
|
30606
|
+
const sourceVisibility = parseAgentSourceVisibility(agentSource, { isStrict: true });
|
|
30607
|
+
const resolvedVisibility = options.isVisibilityOverride || !sourceVisibility
|
|
30608
|
+
? (_b = (_a = options.visibility) !== null && _a !== void 0 ? _a : sourceVisibility) !== null && _b !== void 0 ? _b : DEFAULT_AGENT_VISIBILITY
|
|
30609
|
+
: sourceVisibility;
|
|
30610
|
+
agentSource = setAgentSourceVisibility(agentSource, resolvedVisibility);
|
|
30611
|
+
const agentProfile = parseAgentSource(agentSource);
|
|
30612
|
+
const visibility = (_c = parseAgentSourceVisibility(agentSource, { isStrict: true })) !== null && _c !== void 0 ? _c : undefined;
|
|
28763
30613
|
return {
|
|
28764
30614
|
agentProfile,
|
|
28765
30615
|
agentSource,
|
|
28766
30616
|
permanentId,
|
|
30617
|
+
visibility,
|
|
28767
30618
|
};
|
|
28768
30619
|
}
|
|
28769
30620
|
/**
|
|
@@ -28794,8 +30645,11 @@
|
|
|
28794
30645
|
* @private shared persistence helper for `AgentCollectionInSupabase`
|
|
28795
30646
|
*/
|
|
28796
30647
|
function createAgentPersistenceRecords(agentSource, options = {}, createdAt = new Date().toISOString()) {
|
|
28797
|
-
const preparedAgentSource = prepareAgentSourceForPersistence(agentSource
|
|
28798
|
-
|
|
30648
|
+
const preparedAgentSource = prepareAgentSourceForPersistence(agentSource, {
|
|
30649
|
+
visibility: options.visibility,
|
|
30650
|
+
isVisibilityOverride: options.visibility !== undefined,
|
|
30651
|
+
});
|
|
30652
|
+
const { agentProfile, agentSource: normalizedAgentSource, visibility } = preparedAgentSource;
|
|
28799
30653
|
const permanentId = preparedAgentSource.permanentId || $randomBase58(14);
|
|
28800
30654
|
const { agentName, agentHash } = agentProfile;
|
|
28801
30655
|
const agentInsertRecord = {
|
|
@@ -28815,8 +30669,8 @@
|
|
|
28815
30669
|
if (options.sortOrder !== undefined) {
|
|
28816
30670
|
agentInsertRecord.sortOrder = options.sortOrder;
|
|
28817
30671
|
}
|
|
28818
|
-
if (
|
|
28819
|
-
agentInsertRecord.visibility =
|
|
30672
|
+
if (visibility !== undefined) {
|
|
30673
|
+
agentInsertRecord.visibility = visibility;
|
|
28820
30674
|
}
|
|
28821
30675
|
return {
|
|
28822
30676
|
createdAgent: {
|
|
@@ -28850,6 +30704,18 @@
|
|
|
28850
30704
|
const normalizedVersionName = versionName.trim();
|
|
28851
30705
|
return normalizedVersionName.length > 0 ? normalizedVersionName : null;
|
|
28852
30706
|
}
|
|
30707
|
+
/**
|
|
30708
|
+
* Builds a Supabase `.or()` filter for agent name or permanent id lookups.
|
|
30709
|
+
*
|
|
30710
|
+
* @param agentNameOrPermanentId - Agent name or stable permanent identifier to match.
|
|
30711
|
+
* @returns `.or()` filter string safe to pass to Supabase.
|
|
30712
|
+
*
|
|
30713
|
+
* @private internal helper of `AgentCollectionInSupabase`
|
|
30714
|
+
*/
|
|
30715
|
+
function buildAgentNameOrPermanentIdFilter(agentNameOrPermanentId) {
|
|
30716
|
+
const encodedAgentIdentifier = encodeURIComponent(agentNameOrPermanentId);
|
|
30717
|
+
return `agentName.eq.${encodedAgentIdentifier},permanentId.eq.${encodedAgentIdentifier}`;
|
|
30718
|
+
}
|
|
28853
30719
|
/**
|
|
28854
30720
|
* Agent collection stored in a Supabase table.
|
|
28855
30721
|
*
|
|
@@ -28897,21 +30763,63 @@
|
|
|
28897
30763
|
if (isVerbose) {
|
|
28898
30764
|
console.info(`Found ${selectResult.data.length} agents in directory`);
|
|
28899
30765
|
}
|
|
28900
|
-
return selectResult.data.map((
|
|
28901
|
-
|
|
28902
|
-
|
|
30766
|
+
return selectResult.data.map((row) => this.mapAgentBasicInformationRow(row, isVerbose));
|
|
30767
|
+
}
|
|
30768
|
+
/**
|
|
30769
|
+
* Finds one active agent profile by its human-readable name or permanent id.
|
|
30770
|
+
*
|
|
30771
|
+
* This keeps route-level lookups from loading the whole agent collection when only
|
|
30772
|
+
* one canonical route identifier is needed.
|
|
30773
|
+
*
|
|
30774
|
+
* @param agentNameOrPermanentId - Agent name or stable permanent identifier.
|
|
30775
|
+
* @returns Matching active agent profile or `null` when not found.
|
|
30776
|
+
*
|
|
30777
|
+
* @public exported from `@promptbook/core`
|
|
30778
|
+
*/
|
|
30779
|
+
async findAgentBasicInformation(agentNameOrPermanentId) {
|
|
30780
|
+
var _a;
|
|
30781
|
+
const { isVerbose = exports.DEFAULT_IS_VERBOSE } = this.options || {};
|
|
30782
|
+
const selectResult = await this.supabaseClient
|
|
30783
|
+
.from(this.getTableName('Agent'))
|
|
30784
|
+
.select('agentName,agentProfile,permanentId')
|
|
30785
|
+
.or(buildAgentNameOrPermanentIdFilter(agentNameOrPermanentId))
|
|
30786
|
+
.is('deletedAt', null)
|
|
30787
|
+
.order('createdAt', { ascending: true })
|
|
30788
|
+
.limit(1);
|
|
30789
|
+
if (selectResult.error) {
|
|
30790
|
+
throw new DatabaseError(spaceTrim((block) => `
|
|
30791
|
+
|
|
30792
|
+
Error fetching agent "${agentNameOrPermanentId}" from Supabase:
|
|
30793
|
+
|
|
30794
|
+
${block(selectResult.error.message)}
|
|
30795
|
+
`));
|
|
30796
|
+
}
|
|
30797
|
+
const row = (_a = selectResult.data) === null || _a === void 0 ? void 0 : _a[0];
|
|
30798
|
+
return row ? this.mapAgentBasicInformationRow(row, isVerbose) : null;
|
|
30799
|
+
}
|
|
30800
|
+
/**
|
|
30801
|
+
* Converts one database row into public agent information.
|
|
30802
|
+
*
|
|
30803
|
+
* @param row - Database row carrying the persisted profile snapshot.
|
|
30804
|
+
* @param isVerbose - Whether profile-name mismatches should be logged.
|
|
30805
|
+
* @returns Agent profile with canonical database name and permanent id.
|
|
30806
|
+
*
|
|
30807
|
+
* @private internal helper of `AgentCollectionInSupabase`
|
|
30808
|
+
*/
|
|
30809
|
+
mapAgentBasicInformationRow({ agentName, agentProfile, permanentId }, isVerbose) {
|
|
30810
|
+
if (isVerbose && agentProfile.agentName !== agentName) {
|
|
30811
|
+
console.warn(spaceTrim(`
|
|
28903
30812
|
Agent name mismatch for agent "${agentName}". Using name from database.
|
|
28904
30813
|
|
|
28905
30814
|
agentName: "${agentName}"
|
|
28906
30815
|
agentProfile.agentName: "${agentProfile.agentName}"
|
|
28907
30816
|
`));
|
|
28908
|
-
|
|
28909
|
-
|
|
28910
|
-
|
|
28911
|
-
|
|
28912
|
-
|
|
28913
|
-
|
|
28914
|
-
});
|
|
30817
|
+
}
|
|
30818
|
+
return {
|
|
30819
|
+
...agentProfile,
|
|
30820
|
+
agentName,
|
|
30821
|
+
permanentId: permanentId || agentProfile.permanentId,
|
|
30822
|
+
};
|
|
28915
30823
|
}
|
|
28916
30824
|
/**
|
|
28917
30825
|
* Retrieves the permanent ID of an agent by its name or permanent ID.
|
|
@@ -28920,7 +30828,7 @@
|
|
|
28920
30828
|
const selectResult = await this.supabaseClient
|
|
28921
30829
|
.from(this.getTableName('Agent'))
|
|
28922
30830
|
.select('permanentId')
|
|
28923
|
-
.or(
|
|
30831
|
+
.or(buildAgentNameOrPermanentIdFilter(agentNameOrPermanentId))
|
|
28924
30832
|
.order('createdAt', { ascending: true }) // Pick oldest if multiple match by name
|
|
28925
30833
|
.limit(1);
|
|
28926
30834
|
if (selectResult.error || !selectResult.data || selectResult.data.length === 0) {
|
|
@@ -28935,7 +30843,7 @@
|
|
|
28935
30843
|
const selectResult = await this.supabaseClient
|
|
28936
30844
|
.from(this.getTableName('Agent'))
|
|
28937
30845
|
.select('agentSource')
|
|
28938
|
-
.or(
|
|
30846
|
+
.or(buildAgentNameOrPermanentIdFilter(agentNameOrPermanentId))
|
|
28939
30847
|
.is('deletedAt', null)
|
|
28940
30848
|
.order('createdAt', { ascending: true }) // Pick oldest if multiple match by name
|
|
28941
30849
|
.limit(1);
|
|
@@ -28979,7 +30887,7 @@
|
|
|
28979
30887
|
async updateAgentSource(permanentId, agentSource, options = {}) {
|
|
28980
30888
|
const selectPreviousAgentResult = await this.supabaseClient
|
|
28981
30889
|
.from(this.getTableName('Agent'))
|
|
28982
|
-
.select('agentHash,agentName,permanentId')
|
|
30890
|
+
.select('agentHash,agentName,permanentId,visibility')
|
|
28983
30891
|
.eq('permanentId', permanentId)
|
|
28984
30892
|
.single();
|
|
28985
30893
|
if (selectPreviousAgentResult.error) {
|
|
@@ -28994,8 +30902,11 @@
|
|
|
28994
30902
|
selectPreviousAgentResult.data.agentName;
|
|
28995
30903
|
const previousAgentHash = selectPreviousAgentResult.data.agentHash;
|
|
28996
30904
|
const previousPermanentId = selectPreviousAgentResult.data.permanentId;
|
|
28997
|
-
const
|
|
28998
|
-
const
|
|
30905
|
+
const previousVisibility = selectPreviousAgentResult.data.visibility;
|
|
30906
|
+
const preparedAgentSource = prepareAgentSourceForPersistence(agentSource, {
|
|
30907
|
+
visibility: previousVisibility,
|
|
30908
|
+
});
|
|
30909
|
+
const { agentProfile, agentSource: normalizedAgentSource, visibility } = preparedAgentSource;
|
|
28999
30910
|
let { permanentId: newPermanentId } = preparedAgentSource;
|
|
29000
30911
|
const { agentHash, agentName } = agentProfile;
|
|
29001
30912
|
if (!newPermanentId && previousPermanentId) {
|
|
@@ -29017,6 +30928,7 @@
|
|
|
29017
30928
|
updatedAt: new Date().toISOString(),
|
|
29018
30929
|
agentHash: agentProfile.agentHash,
|
|
29019
30930
|
agentSource: normalizedAgentSource,
|
|
30931
|
+
visibility: visibility !== null && visibility !== void 0 ? visibility : previousVisibility,
|
|
29020
30932
|
promptbookEngineVersion: PROMPTBOOK_ENGINE_VERSION,
|
|
29021
30933
|
})
|
|
29022
30934
|
.eq('permanentId', permanentId);
|
|
@@ -34416,7 +36328,8 @@
|
|
|
34416
36328
|
* @private internal function of `$registeredLlmToolsMessage`
|
|
34417
36329
|
*/
|
|
34418
36330
|
function createUsedEnvMessage() {
|
|
34419
|
-
return `Unknown \`.env\` file`
|
|
36331
|
+
return `Unknown \`.env\` file`
|
|
36332
|
+
;
|
|
34420
36333
|
}
|
|
34421
36334
|
// TODO: [®] DRY Register logic
|
|
34422
36335
|
// TODO: [🧠][⚛] Maybe pass env as argument
|
|
@@ -35729,7 +37642,9 @@
|
|
|
35729
37642
|
if (!executionTools || !executionTools.script) {
|
|
35730
37643
|
throw new PipelineExecutionError(`Model requested tools but no executionTools.script were provided in OpenAiAgentKitExecutionTools options`);
|
|
35731
37644
|
}
|
|
35732
|
-
return Array.isArray(executionTools.script)
|
|
37645
|
+
return Array.isArray(executionTools.script)
|
|
37646
|
+
? executionTools.script
|
|
37647
|
+
: [executionTools.script];
|
|
35733
37648
|
}
|
|
35734
37649
|
/**
|
|
35735
37650
|
* Resolves the assistant-visible AgentKit tool response while preserving structured tool result data.
|
|
@@ -38791,7 +40706,7 @@
|
|
|
38791
40706
|
return { skippedReason: 'invalid_data_url' };
|
|
38792
40707
|
}
|
|
38793
40708
|
return {
|
|
38794
|
-
file: new File([parsed.buffer], parsed.filename, {
|
|
40709
|
+
file: new File([new Uint8Array(parsed.buffer)], parsed.filename, {
|
|
38795
40710
|
type: parsed.mimeType,
|
|
38796
40711
|
}),
|
|
38797
40712
|
sizeBytes: parsed.buffer.length,
|
|
@@ -40554,7 +42469,7 @@
|
|
|
40554
42469
|
* Computes one stable hash from a JSON-serializable value.
|
|
40555
42470
|
*/
|
|
40556
42471
|
function computeJsonHash$1(value) {
|
|
40557
|
-
return
|
|
42472
|
+
return CryptoJS__default["default"].SHA256(JSON.stringify(value)).toString();
|
|
40558
42473
|
}
|
|
40559
42474
|
/**
|
|
40560
42475
|
* Handles OpenAI AgentKit-backed executions for `AgentLlmExecutionTools`.
|
|
@@ -40712,7 +42627,7 @@
|
|
|
40712
42627
|
* Computes one stable hash from a JSON-serializable value.
|
|
40713
42628
|
*/
|
|
40714
42629
|
function computeJsonHash(value) {
|
|
40715
|
-
return
|
|
42630
|
+
return CryptoJS__default["default"].SHA256(JSON.stringify(value)).toString();
|
|
40716
42631
|
}
|
|
40717
42632
|
/**
|
|
40718
42633
|
* Removes assistant-managed requirements before the prompt is executed via OpenAI Assistants.
|
|
@@ -41102,7 +43017,11 @@
|
|
|
41102
43017
|
};
|
|
41103
43018
|
}
|
|
41104
43019
|
return {
|
|
41105
|
-
content:
|
|
43020
|
+
content: spacetrim.spaceTrim((block) => `
|
|
43021
|
+
${block(content.slice(0, Math.max(0, maxCharacters)))}
|
|
43022
|
+
|
|
43023
|
+
[...truncated...]
|
|
43024
|
+
`),
|
|
41106
43025
|
isTruncated: true,
|
|
41107
43026
|
};
|
|
41108
43027
|
}
|
|
@@ -41568,7 +43487,7 @@
|
|
|
41568
43487
|
* Returns a virtual model name representing the agent behavior.
|
|
41569
43488
|
*/
|
|
41570
43489
|
get modelName() {
|
|
41571
|
-
const hash =
|
|
43490
|
+
const hash = CryptoJS__default["default"].SHA256(hexEncoder__default["default"].parse(this.options.agentSource)).toString( /* hex */);
|
|
41572
43491
|
const agentId = hash.substring(0, 10);
|
|
41573
43492
|
return (normalizeToKebabCase(this.title) + '-' + agentId);
|
|
41574
43493
|
}
|
|
@@ -45279,7 +47198,7 @@
|
|
|
45279
47198
|
title: 'Anthropic Claude',
|
|
45280
47199
|
packageName: '@promptbook/anthropic-claude',
|
|
45281
47200
|
className: 'AnthropicClaudeExecutionTools',
|
|
45282
|
-
envVariables: ['ANTHROPIC_CLAUDE_API_KEY'],
|
|
47201
|
+
envVariables: ['ANTHROPIC_API_KEY', 'ANTHROPIC_CLAUDE_API_KEY'],
|
|
45283
47202
|
trustLevel: 'CLOSED',
|
|
45284
47203
|
order: MODEL_ORDERS.TOP_TIER,
|
|
45285
47204
|
getBoilerplateConfiguration() {
|
|
@@ -45296,14 +47215,17 @@
|
|
|
45296
47215
|
};
|
|
45297
47216
|
},
|
|
45298
47217
|
createConfigurationFromEnv(env) {
|
|
47218
|
+
var _a;
|
|
45299
47219
|
// Note: Note using `process.env` BUT `env` to pass in the environment variables dynamically
|
|
45300
|
-
|
|
47220
|
+
// Note: `ANTHROPIC_API_KEY` takes precedence over the deprecated `ANTHROPIC_CLAUDE_API_KEY`
|
|
47221
|
+
const apiKey = (_a = env.ANTHROPIC_API_KEY) !== null && _a !== void 0 ? _a : env.ANTHROPIC_CLAUDE_API_KEY;
|
|
47222
|
+
if (typeof apiKey === 'string') {
|
|
45301
47223
|
return {
|
|
45302
47224
|
title: 'Claude (from env)',
|
|
45303
47225
|
packageName: '@promptbook/anthropic-claude',
|
|
45304
47226
|
className: 'AnthropicClaudeExecutionTools',
|
|
45305
47227
|
options: {
|
|
45306
|
-
apiKey
|
|
47228
|
+
apiKey,
|
|
45307
47229
|
},
|
|
45308
47230
|
};
|
|
45309
47231
|
}
|
|
@@ -48714,20 +50636,7 @@
|
|
|
48714
50636
|
}
|
|
48715
50637
|
|
|
48716
50638
|
/**
|
|
48717
|
-
*
|
|
48718
|
-
*
|
|
48719
|
-
* Used for "Adam" agent which is built in as default ancestor for new agents and other well known agents
|
|
48720
|
-
*
|
|
48721
|
-
* @public exported from `@promptbook/core`
|
|
48722
|
-
*/
|
|
48723
|
-
const CORE_AGENTS_SERVER = {
|
|
48724
|
-
title: 'Promptbook Core',
|
|
48725
|
-
description: `Core Promptbook server used for Adam agent which is built in as default ancestor for new agents and other well known agents.`,
|
|
48726
|
-
owner: PROMPTBOOK_LEGAL_ENTITY,
|
|
48727
|
-
url: 'https://core.ptbk.io/',
|
|
48728
|
-
};
|
|
48729
|
-
/**
|
|
48730
|
-
* Names of well known agents hosted on Core Promptbook server
|
|
50639
|
+
* Names of well known agents bundled in the local `.core` folder of every Agents Server
|
|
48731
50640
|
*
|
|
48732
50641
|
* - `Adam`: The default ancestor agent for new agents
|
|
48733
50642
|
* - `Teacher`: Agent that knows book syntax and can help with self-learning
|
|
@@ -48753,7 +50662,6 @@
|
|
|
48753
50662
|
* @public exported from `@promptbook/core`
|
|
48754
50663
|
*/
|
|
48755
50664
|
const PUBLIC_AGENTS_SERVERS = [
|
|
48756
|
-
CORE_AGENTS_SERVER,
|
|
48757
50665
|
{
|
|
48758
50666
|
title: 'Promptbook Gallery',
|
|
48759
50667
|
description: `Gallery of ideas, AI professions,... like AI Agenta photobank.`,
|
|
@@ -49211,6 +51119,7 @@
|
|
|
49211
51119
|
exports.$scrapersRegister = $scrapersRegister;
|
|
49212
51120
|
exports.ADMIN_EMAIL = ADMIN_EMAIL;
|
|
49213
51121
|
exports.ADMIN_GITHUB_NAME = ADMIN_GITHUB_NAME;
|
|
51122
|
+
exports.AGENT_VISIBILITY_VALUES = AGENT_VISIBILITY_VALUES;
|
|
49214
51123
|
exports.API_REQUEST_TIMEOUT = API_REQUEST_TIMEOUT;
|
|
49215
51124
|
exports.AbstractFormatError = AbstractFormatError;
|
|
49216
51125
|
exports.Agent = Agent;
|
|
@@ -49229,7 +51138,6 @@
|
|
|
49229
51138
|
exports.CLAIM = CLAIM;
|
|
49230
51139
|
exports.CLI_APP_ID = CLI_APP_ID;
|
|
49231
51140
|
exports.COLOR_CONSTANTS = COLOR_CONSTANTS;
|
|
49232
|
-
exports.CORE_AGENTS_SERVER = CORE_AGENTS_SERVER;
|
|
49233
51141
|
exports.CORE_AGENTS_SERVER_WELL_KNOWN_AGENT_NAMES = CORE_AGENTS_SERVER_WELL_KNOWN_AGENT_NAMES;
|
|
49234
51142
|
exports.CallbackInterfaceTools = CallbackInterfaceTools;
|
|
49235
51143
|
exports.ChatbotFormfactorDefinition = ChatbotFormfactorDefinition;
|
|
@@ -49239,6 +51147,7 @@
|
|
|
49239
51147
|
exports.CsvFormatError = CsvFormatError;
|
|
49240
51148
|
exports.CsvFormatParser = CsvFormatParser;
|
|
49241
51149
|
exports.DEFAULT_AGENTS_DIRNAME = DEFAULT_AGENTS_DIRNAME;
|
|
51150
|
+
exports.DEFAULT_AGENT_VISIBILITY = DEFAULT_AGENT_VISIBILITY;
|
|
49242
51151
|
exports.DEFAULT_BOOK = DEFAULT_BOOK;
|
|
49243
51152
|
exports.DEFAULT_BOOKS_DIRNAME = DEFAULT_BOOKS_DIRNAME;
|
|
49244
51153
|
exports.DEFAULT_BOOK_OUTPUT_PARAMETER_NAME = DEFAULT_BOOK_OUTPUT_PARAMETER_NAME;
|
|
@@ -49385,14 +51294,17 @@
|
|
|
49385
51294
|
exports.getAllCommitmentsToolTitles = getAllCommitmentsToolTitles;
|
|
49386
51295
|
exports.getCommitmentDefinition = getCommitmentDefinition;
|
|
49387
51296
|
exports.getGroupedCommitmentDefinitions = getGroupedCommitmentDefinitions;
|
|
51297
|
+
exports.getNextAgentVisibility = getNextAgentVisibility;
|
|
49388
51298
|
exports.getPipelineInterface = getPipelineInterface;
|
|
49389
51299
|
exports.getSingleLlmExecutionTools = getSingleLlmExecutionTools;
|
|
49390
51300
|
exports.identificationToPromptbookToken = identificationToPromptbookToken;
|
|
51301
|
+
exports.isAgentVisibility = isAgentVisibility;
|
|
49391
51302
|
exports.isCommitmentSupported = isCommitmentSupported;
|
|
49392
51303
|
exports.isPassingExpectations = isPassingExpectations;
|
|
49393
51304
|
exports.isPipelineImplementingInterface = isPipelineImplementingInterface;
|
|
49394
51305
|
exports.isPipelineInterfacesEqual = isPipelineInterfacesEqual;
|
|
49395
51306
|
exports.isPipelinePrepared = isPipelinePrepared;
|
|
51307
|
+
exports.isPublicAgentVisibility = isPublicAgentVisibility;
|
|
49396
51308
|
exports.isValidBook = isValidBook;
|
|
49397
51309
|
exports.isValidPipelineString = isValidPipelineString;
|
|
49398
51310
|
exports.joinLlmExecutionTools = joinLlmExecutionTools;
|
|
@@ -49400,9 +51312,13 @@
|
|
|
49400
51312
|
exports.makeKnowledgeSourceHandler = makeKnowledgeSourceHandler;
|
|
49401
51313
|
exports.migratePipeline = migratePipeline;
|
|
49402
51314
|
exports.normalizeAgentName = normalizeAgentName;
|
|
51315
|
+
exports.normalizeAgentVisibility = normalizeAgentVisibility;
|
|
49403
51316
|
exports.normalizeChatAttachments = normalizeChatAttachments;
|
|
49404
51317
|
exports.padBook = padBook;
|
|
49405
51318
|
exports.parseAgentSource = parseAgentSource;
|
|
51319
|
+
exports.parseAgentSourceVisibility = parseAgentSourceVisibility;
|
|
51320
|
+
exports.parseAgentVisibility = parseAgentVisibility;
|
|
51321
|
+
exports.parseAgentVisibilityStrict = parseAgentVisibilityStrict;
|
|
49406
51322
|
exports.parseParameters = parseParameters;
|
|
49407
51323
|
exports.parsePipeline = parsePipeline;
|
|
49408
51324
|
exports.pipelineCollectionToJson = pipelineCollectionToJson;
|
|
@@ -49414,6 +51330,7 @@
|
|
|
49414
51330
|
exports.promptbookFetch = promptbookFetch;
|
|
49415
51331
|
exports.promptbookTokenToIdentification = promptbookTokenToIdentification;
|
|
49416
51332
|
exports.resolveChatAttachmentContents = resolveChatAttachmentContents;
|
|
51333
|
+
exports.setAgentSourceVisibility = setAgentSourceVisibility;
|
|
49417
51334
|
exports.unpreparePipeline = unpreparePipeline;
|
|
49418
51335
|
exports.usageToHuman = usageToHuman;
|
|
49419
51336
|
exports.usageToWorktime = usageToWorktime;
|