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