@promptbook/cli 0.112.0-125 → 0.112.0-127
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 +5 -5
- package/apps/agents-server/README.md +3 -0
- package/apps/agents-server/playwright.config.ts +1 -0
- package/apps/agents-server/public/promptbook-logo-blue.png +0 -0
- package/apps/agents-server/public/promptbook-logo-white.png +0 -0
- package/apps/agents-server/src/app/[agentName]/layout.tsx +1 -0
- package/apps/agents-server/src/app/actions.ts +2 -2
- package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +68 -36
- package/apps/agents-server/src/app/agents/[agentName]/ActiveAgentBreadcrumbBinder.tsx +30 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +2 -0
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistoryPayloadState.ts +38 -4
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistorySyncOperations.ts +4 -1
- package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +19 -15
- package/apps/agents-server/src/app/agents/[agentName]/chat/useCanonicalAgentChatPanelState.ts +58 -7
- package/apps/agents-server/src/app/agents/[agentName]/layout.tsx +47 -1
- package/apps/agents-server/src/app/api/chat/citation-label/route.ts +133 -0
- package/apps/agents-server/src/app/globals.css +78 -0
- package/apps/agents-server/src/components/Header/ActiveAgentBreadcrumbContext.tsx +82 -0
- package/apps/agents-server/src/components/Header/useHeaderActiveAgent.ts +26 -7
- package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +35 -32
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoNewAgentWizard.tsx +151 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoOnboardingNavigation.tsx +50 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/BookLanguagePanel.tsx +125 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/DropZone.tsx +83 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/EmailTestRun.tsx +216 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/KnowledgeList.tsx +79 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/Logo.tsx +20 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownBookEditor.tsx +154 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownPreview.tsx +188 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/RailStepper.tsx +115 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/StepFrame.tsx +47 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/TestChat.tsx +159 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/WizardShell.tsx +114 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/brand/RailArtwork.tsx +60 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/BookStep.tsx +135 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/DoneStep.tsx +215 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/KnowledgeStep.tsx +152 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/TestStep.tsx +262 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/ZadaniStep.tsx +64 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Badge.tsx +41 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Banner.tsx +69 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Button.tsx +77 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Card.tsx +33 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Field.tsx +103 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/IconButton.tsx +40 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Spinner.tsx +14 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/tokens.ts +37 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/bookSections.ts +62 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/emailScenarios.ts +22 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/steps.ts +46 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/index.ts +11 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/cn.ts +4 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/format.ts +9 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/id.ts +11 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentEvalService.ts +30 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentTestService.ts +69 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/bookService.ts +21 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/createManGoAgentSource.ts +107 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/draftService.ts +45 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/uploadService.ts +27 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/state/OnboardingProvider.tsx +121 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/types.ts +52 -0
- package/apps/agents-server/src/components/NewAgentDialog/createNewAgentWizardSource.ts +1 -1
- package/apps/agents-server/src/components/NewAgentDialog/trackNewAgentCreationEvent.ts +1 -1
- package/apps/agents-server/src/components/NewAgentDialog/useNewAgentDialog.tsx +76 -0
- package/apps/agents-server/src/constants/newAgentWizard.ts +17 -8
- package/apps/agents-server/src/database/getMetadata.ts +37 -1
- package/apps/agents-server/src/database/metadataDefaults.ts +18 -7
- package/apps/agents-server/src/database/migrations/2026-06-2200-new-agent-wizard-metadata-key.sql +27 -0
- package/apps/agents-server/src/database/migrations/2026-06-2201-new-agent-wizard-mango-default.sql +11 -0
- package/apps/agents-server/src/generated/reservedPaths.ts +2 -0
- package/apps/agents-server/src/languages/translations/english.yaml +1 -1
- package/apps/agents-server/src/tools/createChatAttachmentToolFunctions.ts +8 -4
- package/apps/agents-server/src/utils/chat/resolveAgentsServerCitationLabel.ts +130 -0
- package/apps/agents-server/src/utils/chat/resolveCitationSourceLabel.ts +436 -0
- package/apps/agents-server/src/utils/knowledge/resolveWebsiteKnowledgeSourcesForServer.ts +10 -1
- package/apps/agents-server/src/utils/session.ts +62 -5
- package/apps/agents-server/src/utils/transpilers/resolveTranspiledTeamExport.ts +10 -10
- package/apps/agents-server/src/utils/userChat/userChatProgressCard.ts +198 -63
- package/apps/agents-server/src/utils/vpsConfiguration.ts +1 -0
- package/apps/agents-server/src/utils/vpsSelfUpdate.ts +81 -8
- package/esm/index.es.js +1052 -455
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
- package/esm/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
- package/esm/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
- package/esm/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
- package/esm/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
- package/esm/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
- package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
- package/esm/src/_packages/components.index.d.ts +2 -0
- package/esm/src/_packages/types.index.d.ts +2 -0
- package/esm/src/avatars/avatarAnimationScheduler.d.ts +4 -0
- 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/TeamToolCallModalContent.d.ts +2 -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/parseCitationsFromContent.d.ts +4 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/_packages/components.index.ts +2 -0
- package/src/_packages/types.index.ts +2 -0
- package/src/avatars/avatarAnimationScheduler.ts +61 -20
- package/src/avatars/visuals/octopus3d2AvatarVisual.ts +106 -21
- package/src/avatars/visuals/octopus3d3AvatarVisual.ts +131 -28
- package/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.ts +18 -2
- package/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.ts +7 -1
- package/src/book-components/Chat/Chat/Chat.tsx +4 -0
- package/src/book-components/Chat/Chat/ChatCitationModal.tsx +17 -3
- package/src/book-components/Chat/Chat/ChatMessageItem.tsx +22 -2
- package/src/book-components/Chat/Chat/ChatMessageList.tsx +6 -0
- package/src/book-components/Chat/Chat/ChatProps.tsx +6 -0
- package/src/book-components/Chat/Chat/ChatToolCallModal.tsx +4 -0
- package/src/book-components/Chat/Chat/ChatToolCallModalContent.tsx +4 -0
- package/src/book-components/Chat/Chat/TeamToolCallModalContent.tsx +16 -3
- package/src/book-components/Chat/Chat/useChatPostprocessedMessages.ts +13 -2
- package/src/book-components/Chat/SourceChip/SourceChip.module.css +8 -0
- package/src/book-components/Chat/SourceChip/SourceChip.tsx +19 -5
- package/src/book-components/Chat/hooks/useResolvedCitationLabel.ts +65 -0
- package/src/book-components/Chat/save/html/htmlSaveFormatDefinition.ts +315 -88
- package/src/book-components/Chat/save/react/reactSaveFormatDefinition.ts +7 -1
- package/src/book-components/Chat/types/ChatMessage.ts +5 -0
- package/src/book-components/Chat/types/ChatParticipant.ts +1 -1
- package/src/book-components/Chat/types/CitationLabelResolver.ts +9 -0
- package/src/book-components/Chat/utils/citationHelpers.ts +90 -2
- package/src/book-components/Chat/utils/createCitationFootnoteRenderModel.ts +3 -0
- package/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.ts +178 -0
- package/src/book-components/Chat/utils/parseCitationsFromContent.ts +6 -0
- package/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.ts +13 -2
- package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
- package/src/cli/cli-commands/coder/run.ts +17 -20
- package/src/cli/cli-commands/coder/server.ts +13 -16
- package/src/cli/common/$deprecateCliCommand.ts +10 -1
- package/src/commitments/GOAL/GOAL.ts +7 -2
- package/src/commitments/LANGUAGE/LANGUAGE.ts +7 -2
- package/src/commitments/TEAM/TEAM.ts +12 -1
- package/src/commitments/USE_PROJECT/createUseProjectToolFunctions.ts +8 -1
- package/src/import-plugins/JsonFileImportPlugin.ts +15 -2
- package/src/import-plugins/TextFileImportPlugin.ts +8 -1
- package/src/llm-providers/_common/register/$registeredLlmToolsMessage.ts +6 -1
- package/src/other/templates/getTemplatesPipelineCollection.ts +696 -941
- package/src/utils/chat/chatAttachments/resolveChatAttachmentContent.ts +8 -1
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -1
- package/umd/index.umd.js +1055 -458
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
- package/umd/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
- package/umd/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
- package/umd/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
- package/umd/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
- package/umd/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
- package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
- package/umd/src/_packages/components.index.d.ts +2 -0
- package/umd/src/_packages/types.index.d.ts +2 -0
- package/umd/src/avatars/avatarAnimationScheduler.d.ts +4 -0
- 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/TeamToolCallModalContent.d.ts +2 -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/parseCitationsFromContent.d.ts +4 -0
- package/umd/src/version.d.ts +1 -1
|
@@ -8,56 +8,75 @@
|
|
|
8
8
|
type AvatarAnimationListener = (now: number) => void;
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* One scheduled avatar animation entry tracked by the shared loop.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
* @private utility of the avatar rendering system
|
|
14
|
+
*/
|
|
15
|
+
type AvatarAnimationListenerEntry = {
|
|
16
|
+
readonly listener: AvatarAnimationListener;
|
|
17
|
+
lastRunAtMs: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Target frames per second for a single animated avatar.
|
|
22
|
+
*
|
|
23
|
+
* Animated octopus visuals change slowly enough that ~24 fps per avatar is indistinguishable
|
|
24
|
+
* from 60 fps in practice. Combined with `MAX_AVATAR_LISTENERS_PER_FRAME` this bounds total
|
|
25
|
+
* rendering work even when many avatars are visible.
|
|
16
26
|
*
|
|
17
27
|
* @private utility of the avatar rendering system
|
|
18
28
|
*/
|
|
19
29
|
const AVATAR_TARGET_FPS = 24;
|
|
20
30
|
|
|
21
31
|
/**
|
|
22
|
-
* Minimum elapsed time in milliseconds required between
|
|
32
|
+
* Minimum elapsed time in milliseconds required between two consecutive renders of the same avatar.
|
|
23
33
|
*
|
|
24
34
|
* @private utility of the avatar rendering system
|
|
25
35
|
*/
|
|
26
36
|
const AVATAR_TARGET_FRAME_INTERVAL_MS = 1000 / AVATAR_TARGET_FPS;
|
|
27
37
|
|
|
28
38
|
/**
|
|
29
|
-
*
|
|
39
|
+
* Hard cap on how many avatar listeners can run inside the same animation frame.
|
|
40
|
+
*
|
|
41
|
+
* The default visual takes several milliseconds to render, so firing every visible avatar
|
|
42
|
+
* on the same animation frame stalls the main thread for tens of milliseconds and drops the
|
|
43
|
+
* overall page FPS to single digits. Bounding the number of listeners that fire per frame
|
|
44
|
+
* spreads the work across animation frames and keeps the UI responsive even with many
|
|
45
|
+
* visible avatars — each individual avatar still reaches `AVATAR_TARGET_FPS` because work
|
|
46
|
+
* is interleaved instead of skipped.
|
|
30
47
|
*
|
|
31
48
|
* @private utility of the avatar rendering system
|
|
32
49
|
*/
|
|
33
|
-
|
|
50
|
+
const MAX_AVATAR_LISTENERS_PER_FRAME = 2;
|
|
34
51
|
|
|
35
52
|
/**
|
|
36
|
-
*
|
|
53
|
+
* Next registration id used by the shared avatar animation scheduler.
|
|
37
54
|
*
|
|
38
55
|
* @private utility of the avatar rendering system
|
|
39
56
|
*/
|
|
40
|
-
|
|
57
|
+
let nextAvatarAnimationListenerId = 1;
|
|
41
58
|
|
|
42
59
|
/**
|
|
43
|
-
* Active
|
|
60
|
+
* Active avatar animation callbacks keyed by their registration id.
|
|
44
61
|
*
|
|
45
62
|
* @private utility of the avatar rendering system
|
|
46
63
|
*/
|
|
47
|
-
|
|
64
|
+
const avatarAnimationListeners = new Map<number, AvatarAnimationListenerEntry>();
|
|
48
65
|
|
|
49
66
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* Used to throttle callbacks to `AVATAR_TARGET_FRAME_INTERVAL_MS`.
|
|
67
|
+
* Active shared animation-frame handle.
|
|
53
68
|
*
|
|
54
69
|
* @private utility of the avatar rendering system
|
|
55
70
|
*/
|
|
56
|
-
let
|
|
71
|
+
let avatarAnimationFrameId: number | null = null;
|
|
57
72
|
|
|
58
73
|
/**
|
|
59
74
|
* Registers one avatar animation callback in the shared animation loop.
|
|
60
75
|
*
|
|
76
|
+
* Each listener is staggered at registration time so it does not fire on the same animation
|
|
77
|
+
* frame as the existing listeners, and the shared loop further caps how many listeners run
|
|
78
|
+
* per frame, keeping the main thread responsive when many avatars are mounted.
|
|
79
|
+
*
|
|
61
80
|
* @param avatarAnimationListener Frame callback invoked on every animation frame.
|
|
62
81
|
* @returns Cleanup function that unregisters the callback.
|
|
63
82
|
*
|
|
@@ -69,7 +88,15 @@ export function retainAvatarAnimationListener(avatarAnimationListener: AvatarAni
|
|
|
69
88
|
}
|
|
70
89
|
|
|
71
90
|
const listenerId = nextAvatarAnimationListenerId++;
|
|
72
|
-
avatarAnimationListeners.
|
|
91
|
+
const existingListenerCount = avatarAnimationListeners.size;
|
|
92
|
+
const staggerOffsetMs =
|
|
93
|
+
((existingListenerCount % Math.max(1, MAX_AVATAR_LISTENERS_PER_FRAME)) * AVATAR_TARGET_FRAME_INTERVAL_MS) /
|
|
94
|
+
Math.max(1, MAX_AVATAR_LISTENERS_PER_FRAME);
|
|
95
|
+
avatarAnimationListeners.set(listenerId, {
|
|
96
|
+
listener: avatarAnimationListener,
|
|
97
|
+
// Phase the listener so multiple new listeners do not synchronize on the same frame.
|
|
98
|
+
lastRunAtMs: performance.now() - AVATAR_TARGET_FRAME_INTERVAL_MS + staggerOffsetMs,
|
|
99
|
+
});
|
|
73
100
|
ensureAvatarAnimationLoop();
|
|
74
101
|
|
|
75
102
|
return () => {
|
|
@@ -95,14 +122,28 @@ function ensureAvatarAnimationLoop(): void {
|
|
|
95
122
|
const runFrame = (now: number) => {
|
|
96
123
|
avatarAnimationFrameId = null;
|
|
97
124
|
|
|
98
|
-
|
|
99
|
-
lastAvatarFrameTime = now;
|
|
125
|
+
const dueListenerEntries: Array<AvatarAnimationListenerEntry> = [];
|
|
100
126
|
|
|
101
|
-
|
|
102
|
-
|
|
127
|
+
for (const listenerEntry of avatarAnimationListeners.values()) {
|
|
128
|
+
if (now - listenerEntry.lastRunAtMs >= AVATAR_TARGET_FRAME_INTERVAL_MS) {
|
|
129
|
+
dueListenerEntries.push(listenerEntry);
|
|
103
130
|
}
|
|
104
131
|
}
|
|
105
132
|
|
|
133
|
+
// Run the most stale listeners first so each avatar keeps its target FPS even when
|
|
134
|
+
// total work exceeds the per-frame budget.
|
|
135
|
+
dueListenerEntries.sort(
|
|
136
|
+
(firstListenerEntry, secondListenerEntry) => firstListenerEntry.lastRunAtMs - secondListenerEntry.lastRunAtMs,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const listenersToRunCount = Math.min(dueListenerEntries.length, MAX_AVATAR_LISTENERS_PER_FRAME);
|
|
140
|
+
|
|
141
|
+
for (let listenerIndex = 0; listenerIndex < listenersToRunCount; listenerIndex++) {
|
|
142
|
+
const listenerEntry = dueListenerEntries[listenerIndex]!;
|
|
143
|
+
listenerEntry.lastRunAtMs = now;
|
|
144
|
+
listenerEntry.listener(now);
|
|
145
|
+
}
|
|
146
|
+
|
|
106
147
|
ensureAvatarAnimationLoop();
|
|
107
148
|
};
|
|
108
149
|
|
|
@@ -331,9 +331,29 @@ function drawBlobbyOctopusShadow(
|
|
|
331
331
|
context.restore();
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
+
/**
|
|
335
|
+
* Number of latitude segments used by the single blobby octopus mesh.
|
|
336
|
+
*
|
|
337
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
338
|
+
*/
|
|
339
|
+
const LATITUDE_PATCH_COUNT = 12;
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Number of longitude segments used by the single blobby octopus mesh.
|
|
343
|
+
*
|
|
344
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
345
|
+
*/
|
|
346
|
+
const LONGITUDE_PATCH_COUNT = 24;
|
|
347
|
+
|
|
334
348
|
/**
|
|
335
349
|
* Resolves all visible projected patches for the single blobby octopus mesh.
|
|
336
350
|
*
|
|
351
|
+
* Within a single frame, mesh corner samples and longitude-only lobe-wave values are
|
|
352
|
+
* quantized to the patch grid and computed once each rather than re-evaluated for every
|
|
353
|
+
* patch corner — the patch loop alone would call `sampleBlobbyOctopusSurfacePoint`
|
|
354
|
+
* `latitudePatchCount * longitudePatchCount * 4` times without caching, even though most
|
|
355
|
+
* corners are shared between neighboring patches.
|
|
356
|
+
*
|
|
337
357
|
* @private helper of `octopus3d2AvatarVisual`
|
|
338
358
|
*/
|
|
339
359
|
function resolveVisibleBlobbyOctopusPatches(options: {
|
|
@@ -363,29 +383,68 @@ function resolveVisibleBlobbyOctopusPatches(options: {
|
|
|
363
383
|
animationPhase,
|
|
364
384
|
timeMs,
|
|
365
385
|
} = options;
|
|
366
|
-
const latitudePatchCount =
|
|
367
|
-
const longitudePatchCount =
|
|
386
|
+
const latitudePatchCount = LATITUDE_PATCH_COUNT;
|
|
387
|
+
const longitudePatchCount = LONGITUDE_PATCH_COUNT;
|
|
368
388
|
const surfacePatches: Array<BlobbyOctopusSurfacePatch> = [];
|
|
389
|
+
const latitudeBoundaries = new Float64Array(latitudePatchCount + 1);
|
|
390
|
+
const longitudeBoundaries = new Float64Array(longitudePatchCount + 1);
|
|
391
|
+
|
|
392
|
+
for (let boundaryIndex = 0; boundaryIndex <= latitudePatchCount; boundaryIndex++) {
|
|
393
|
+
latitudeBoundaries[boundaryIndex] = -Math.PI / 2 + (boundaryIndex / latitudePatchCount) * Math.PI;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
397
|
+
longitudeBoundaries[boundaryIndex] = -Math.PI + (boundaryIndex / longitudePatchCount) * Math.PI * 2;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const cachedLobeWavesByCornerLongitude = new Float64Array(longitudePatchCount + 1);
|
|
401
|
+
|
|
402
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
403
|
+
cachedLobeWavesByCornerLongitude[boundaryIndex] = resolveLowerLobeWave(
|
|
404
|
+
longitudeBoundaries[boundaryIndex]!,
|
|
405
|
+
morphologyProfile,
|
|
406
|
+
animationPhase,
|
|
407
|
+
timeMs,
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const cornerCount = (latitudePatchCount + 1) * (longitudePatchCount + 1);
|
|
412
|
+
const transformedCornerSamples = new Array<Point3D>(cornerCount);
|
|
413
|
+
|
|
414
|
+
for (let latitudeBoundaryIndex = 0; latitudeBoundaryIndex <= latitudePatchCount; latitudeBoundaryIndex++) {
|
|
415
|
+
const cornerLatitude = latitudeBoundaries[latitudeBoundaryIndex]!;
|
|
416
|
+
|
|
417
|
+
for (let longitudeBoundaryIndex = 0; longitudeBoundaryIndex <= longitudePatchCount; longitudeBoundaryIndex++) {
|
|
418
|
+
const cornerLongitude = longitudeBoundaries[longitudeBoundaryIndex]!;
|
|
419
|
+
const cornerIndex = latitudeBoundaryIndex * (longitudePatchCount + 1) + longitudeBoundaryIndex;
|
|
420
|
+
const cornerSample = sampleBlobbyOctopusSurfacePointWithLongitudeCache(
|
|
421
|
+
options,
|
|
422
|
+
cornerLatitude,
|
|
423
|
+
cornerLongitude,
|
|
424
|
+
cachedLobeWavesByCornerLongitude[longitudeBoundaryIndex]!,
|
|
425
|
+
);
|
|
426
|
+
transformedCornerSamples[cornerIndex] = transformScenePoint(cornerSample, center, rotationX, rotationY);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
369
429
|
|
|
370
430
|
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
371
|
-
const startLatitude =
|
|
372
|
-
const endLatitude =
|
|
431
|
+
const startLatitude = latitudeBoundaries[latitudeIndex]!;
|
|
432
|
+
const endLatitude = latitudeBoundaries[latitudeIndex + 1]!;
|
|
373
433
|
const centerLatitude = (startLatitude + endLatitude) / 2;
|
|
374
434
|
const verticalProgress = (Math.sin(centerLatitude) + 1) / 2;
|
|
435
|
+
const startCornerRowOffset = latitudeIndex * (longitudePatchCount + 1);
|
|
436
|
+
const endCornerRowOffset = (latitudeIndex + 1) * (longitudePatchCount + 1);
|
|
375
437
|
|
|
376
438
|
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
377
|
-
const startLongitude =
|
|
378
|
-
const endLongitude =
|
|
439
|
+
const startLongitude = longitudeBoundaries[longitudeIndex]!;
|
|
440
|
+
const endLongitude = longitudeBoundaries[longitudeIndex + 1]!;
|
|
379
441
|
const centerLongitude = (startLongitude + endLongitude) / 2;
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
]
|
|
386
|
-
const transformedCorners = localCorners.map((localCorner) =>
|
|
387
|
-
transformScenePoint(localCorner, center, rotationX, rotationY),
|
|
388
|
-
) as [Point3D, Point3D, Point3D, Point3D];
|
|
442
|
+
const transformedCorners: [Point3D, Point3D, Point3D, Point3D] = [
|
|
443
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex]!,
|
|
444
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex + 1]!,
|
|
445
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex + 1]!,
|
|
446
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex]!,
|
|
447
|
+
];
|
|
389
448
|
const surfaceNormal = normalizeVector3(
|
|
390
449
|
crossProduct3D(
|
|
391
450
|
subtractPoint3D(transformedCorners[1], transformedCorners[0]),
|
|
@@ -397,14 +456,20 @@ function resolveVisibleBlobbyOctopusPatches(options: {
|
|
|
397
456
|
continue;
|
|
398
457
|
}
|
|
399
458
|
|
|
400
|
-
const projectedCorners =
|
|
401
|
-
projectScenePoint(
|
|
402
|
-
|
|
459
|
+
const projectedCorners: [ProjectedPoint, ProjectedPoint, ProjectedPoint, ProjectedPoint] = [
|
|
460
|
+
projectScenePoint(transformedCorners[0], size, sceneCenterX, sceneCenterY),
|
|
461
|
+
projectScenePoint(transformedCorners[1], size, sceneCenterX, sceneCenterY),
|
|
462
|
+
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
463
|
+
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
464
|
+
];
|
|
403
465
|
surfacePatches.push({
|
|
404
466
|
corners: projectedCorners,
|
|
405
467
|
averageDepth:
|
|
406
|
-
transformedCorners.
|
|
407
|
-
|
|
468
|
+
(transformedCorners[0].z +
|
|
469
|
+
transformedCorners[1].z +
|
|
470
|
+
transformedCorners[2].z +
|
|
471
|
+
transformedCorners[3].z) /
|
|
472
|
+
4,
|
|
408
473
|
lightIntensity: clampNumber(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
409
474
|
fillStyle: resolveBlobbySurfacePatchFillStyle(
|
|
410
475
|
palette,
|
|
@@ -432,13 +497,33 @@ function sampleBlobbyOctopusSurfacePoint(
|
|
|
432
497
|
options: BlobbyOctopusSurfaceOptions,
|
|
433
498
|
latitude: number,
|
|
434
499
|
longitude: number,
|
|
500
|
+
): Point3D {
|
|
501
|
+
const { morphologyProfile, animationPhase, timeMs } = options;
|
|
502
|
+
return sampleBlobbyOctopusSurfacePointWithLongitudeCache(
|
|
503
|
+
options,
|
|
504
|
+
latitude,
|
|
505
|
+
longitude,
|
|
506
|
+
resolveLowerLobeWave(longitude, morphologyProfile, animationPhase, timeMs),
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Samples one point on the continuous Octopus 3D 2 surface using a precomputed lower-lobe wave
|
|
512
|
+
* to skip the per-call trig evaluation for `latitudePatchCount + 1` longitude-shared corners.
|
|
513
|
+
*
|
|
514
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
515
|
+
*/
|
|
516
|
+
function sampleBlobbyOctopusSurfacePointWithLongitudeCache(
|
|
517
|
+
options: BlobbyOctopusSurfaceOptions,
|
|
518
|
+
latitude: number,
|
|
519
|
+
longitude: number,
|
|
520
|
+
lowerLobeWave: number,
|
|
435
521
|
): Point3D {
|
|
436
522
|
const { radiusX, radiusY, radiusZ, morphologyProfile, timeMs, animationPhase } = options;
|
|
437
523
|
const cosineLatitude = Math.max(0, Math.cos(latitude));
|
|
438
524
|
const verticalProgress = (Math.sin(latitude) + 1) / 2;
|
|
439
525
|
const upperBlend = Math.pow(1 - verticalProgress, 1.2);
|
|
440
526
|
const lowerBlend = Math.pow(verticalProgress, 1.42);
|
|
441
|
-
const lowerLobeWave = resolveLowerLobeWave(longitude, morphologyProfile, animationPhase, timeMs);
|
|
442
527
|
const skirtEnvelope = Math.pow(cosineLatitude, 0.5) * lowerBlend;
|
|
443
528
|
const horizontalScale =
|
|
444
529
|
1.02 +
|
|
@@ -431,9 +431,29 @@ function drawContinuousOctopusShadow(
|
|
|
431
431
|
context.restore();
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Number of latitude segments used by the continuous Octopus 3D 3 mesh.
|
|
436
|
+
*
|
|
437
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
438
|
+
*/
|
|
439
|
+
const LATITUDE_PATCH_COUNT = 16;
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Number of longitude segments used by the continuous Octopus 3D 3 mesh.
|
|
443
|
+
*
|
|
444
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
445
|
+
*/
|
|
446
|
+
const LONGITUDE_PATCH_COUNT = 40;
|
|
447
|
+
|
|
434
448
|
/**
|
|
435
449
|
* Resolves visible projected patches for the continuous octopus mesh.
|
|
436
450
|
*
|
|
451
|
+
* Within a single frame, mesh corner samples and longitude-only computations (tentacle
|
|
452
|
+
* influence and lobe wave) are quantized to the patch grid and computed once each rather
|
|
453
|
+
* than re-evaluated for every patch corner — the patch loop alone calls `sampleContinuousOctopusSurfacePoint`
|
|
454
|
+
* for `latitudePatchCount * longitudePatchCount * 4` corners without caching, and each call
|
|
455
|
+
* triggers an inner 8-iteration `Math.exp` loop, which dominates the per-frame cost.
|
|
456
|
+
*
|
|
437
457
|
* @private helper of `octopus3d3AvatarVisual`
|
|
438
458
|
*/
|
|
439
459
|
function resolveVisibleContinuousOctopusPatches(
|
|
@@ -448,29 +468,84 @@ function resolveVisibleContinuousOctopusPatches(
|
|
|
448
468
|
},
|
|
449
469
|
): Array<ContinuousOctopusSurfacePatch> {
|
|
450
470
|
const { center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette } = options;
|
|
451
|
-
const latitudePatchCount =
|
|
452
|
-
const longitudePatchCount =
|
|
471
|
+
const latitudePatchCount = LATITUDE_PATCH_COUNT;
|
|
472
|
+
const longitudePatchCount = LONGITUDE_PATCH_COUNT;
|
|
453
473
|
const surfacePatches: Array<ContinuousOctopusSurfacePatch> = [];
|
|
474
|
+
const latitudeBoundaries = new Float64Array(latitudePatchCount + 1);
|
|
475
|
+
const longitudeBoundaries = new Float64Array(longitudePatchCount + 1);
|
|
476
|
+
|
|
477
|
+
for (let boundaryIndex = 0; boundaryIndex <= latitudePatchCount; boundaryIndex++) {
|
|
478
|
+
latitudeBoundaries[boundaryIndex] = -Math.PI / 2 + (boundaryIndex / latitudePatchCount) * Math.PI;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
482
|
+
longitudeBoundaries[boundaryIndex] = -Math.PI + (boundaryIndex / longitudePatchCount) * Math.PI * 2;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const cachedTentacleInfluencesByCornerLongitude = new Array<ContinuousOctopusTentacleInfluence>(
|
|
486
|
+
longitudePatchCount + 1,
|
|
487
|
+
);
|
|
488
|
+
const cachedLobeWavesByCornerLongitude = new Float64Array(longitudePatchCount + 1);
|
|
489
|
+
const cachedTentacleInfluencesByPatchCenterLongitude = new Array<ContinuousOctopusTentacleInfluence>(
|
|
490
|
+
longitudePatchCount,
|
|
491
|
+
);
|
|
492
|
+
const cachedLobeWavesByPatchCenterLongitude = new Float64Array(longitudePatchCount);
|
|
493
|
+
const cachedCosByPatchCenterLongitude = new Float64Array(longitudePatchCount);
|
|
494
|
+
|
|
495
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
496
|
+
const cornerLongitude = longitudeBoundaries[boundaryIndex]!;
|
|
497
|
+
cachedTentacleInfluencesByCornerLongitude[boundaryIndex] = resolveContinuousTentacleInfluence(
|
|
498
|
+
options,
|
|
499
|
+
cornerLongitude,
|
|
500
|
+
);
|
|
501
|
+
cachedLobeWavesByCornerLongitude[boundaryIndex] = resolveContinuousLobeWave(options, cornerLongitude);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
505
|
+
const patchCenterLongitude = (longitudeBoundaries[longitudeIndex]! + longitudeBoundaries[longitudeIndex + 1]!) / 2;
|
|
506
|
+
cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex] = resolveContinuousTentacleInfluence(
|
|
507
|
+
options,
|
|
508
|
+
patchCenterLongitude,
|
|
509
|
+
);
|
|
510
|
+
cachedLobeWavesByPatchCenterLongitude[longitudeIndex] = resolveContinuousLobeWave(options, patchCenterLongitude);
|
|
511
|
+
cachedCosByPatchCenterLongitude[longitudeIndex] = Math.max(0, Math.cos(patchCenterLongitude));
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const cornerCount = (latitudePatchCount + 1) * (longitudePatchCount + 1);
|
|
515
|
+
const transformedCornerSamples = new Array<Point3D>(cornerCount);
|
|
516
|
+
|
|
517
|
+
for (let latitudeBoundaryIndex = 0; latitudeBoundaryIndex <= latitudePatchCount; latitudeBoundaryIndex++) {
|
|
518
|
+
const cornerLatitude = latitudeBoundaries[latitudeBoundaryIndex]!;
|
|
519
|
+
|
|
520
|
+
for (let longitudeBoundaryIndex = 0; longitudeBoundaryIndex <= longitudePatchCount; longitudeBoundaryIndex++) {
|
|
521
|
+
const cornerLongitude = longitudeBoundaries[longitudeBoundaryIndex]!;
|
|
522
|
+
const cornerIndex = latitudeBoundaryIndex * (longitudePatchCount + 1) + longitudeBoundaryIndex;
|
|
523
|
+
const cornerSample = sampleContinuousOctopusSurfacePointWithLongitudeCache(
|
|
524
|
+
options,
|
|
525
|
+
cornerLatitude,
|
|
526
|
+
cornerLongitude,
|
|
527
|
+
cachedTentacleInfluencesByCornerLongitude[longitudeBoundaryIndex]!,
|
|
528
|
+
cachedLobeWavesByCornerLongitude[longitudeBoundaryIndex]!,
|
|
529
|
+
);
|
|
530
|
+
transformedCornerSamples[cornerIndex] = transformScenePoint(cornerSample, center, rotationX, rotationY);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
454
533
|
|
|
455
534
|
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
456
|
-
const startLatitude =
|
|
457
|
-
const endLatitude =
|
|
535
|
+
const startLatitude = latitudeBoundaries[latitudeIndex]!;
|
|
536
|
+
const endLatitude = latitudeBoundaries[latitudeIndex + 1]!;
|
|
458
537
|
const centerLatitude = (startLatitude + endLatitude) / 2;
|
|
459
538
|
const verticalProgress = (Math.sin(centerLatitude) + 1) / 2;
|
|
539
|
+
const startCornerRowOffset = latitudeIndex * (longitudePatchCount + 1);
|
|
540
|
+
const endCornerRowOffset = (latitudeIndex + 1) * (longitudePatchCount + 1);
|
|
460
541
|
|
|
461
542
|
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
sampleContinuousOctopusSurfacePoint(options, endLatitude, endLongitude),
|
|
469
|
-
sampleContinuousOctopusSurfacePoint(options, endLatitude, startLongitude),
|
|
470
|
-
] as const;
|
|
471
|
-
const transformedCorners = localCorners.map((localCorner) =>
|
|
472
|
-
transformScenePoint(localCorner, center, rotationX, rotationY),
|
|
473
|
-
) as [Point3D, Point3D, Point3D, Point3D];
|
|
543
|
+
const transformedCorners: [Point3D, Point3D, Point3D, Point3D] = [
|
|
544
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex]!,
|
|
545
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex + 1]!,
|
|
546
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex + 1]!,
|
|
547
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex]!,
|
|
548
|
+
];
|
|
474
549
|
const surfaceNormal = normalizeVector3(
|
|
475
550
|
crossProduct3D(
|
|
476
551
|
subtractPoint3D(transformedCorners[1], transformedCorners[0]),
|
|
@@ -482,24 +557,28 @@ function resolveVisibleContinuousOctopusPatches(
|
|
|
482
557
|
continue;
|
|
483
558
|
}
|
|
484
559
|
|
|
485
|
-
const projectedCorners =
|
|
486
|
-
projectScenePoint(
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
560
|
+
const projectedCorners: [ProjectedPoint, ProjectedPoint, ProjectedPoint, ProjectedPoint] = [
|
|
561
|
+
projectScenePoint(transformedCorners[0], size, sceneCenterX, sceneCenterY),
|
|
562
|
+
projectScenePoint(transformedCorners[1], size, sceneCenterX, sceneCenterY),
|
|
563
|
+
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
564
|
+
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
565
|
+
];
|
|
490
566
|
|
|
491
567
|
surfacePatches.push({
|
|
492
568
|
corners: projectedCorners,
|
|
493
569
|
averageDepth:
|
|
494
|
-
transformedCorners.
|
|
495
|
-
|
|
570
|
+
(transformedCorners[0].z +
|
|
571
|
+
transformedCorners[1].z +
|
|
572
|
+
transformedCorners[2].z +
|
|
573
|
+
transformedCorners[3].z) /
|
|
574
|
+
4,
|
|
496
575
|
lightIntensity: clampNumber(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
497
576
|
fillStyle: resolveContinuousSurfacePatchFillStyle(
|
|
498
577
|
palette,
|
|
499
578
|
verticalProgress,
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
579
|
+
cachedCosByPatchCenterLongitude[longitudeIndex]!,
|
|
580
|
+
cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex]!.core,
|
|
581
|
+
cachedLobeWavesByPatchCenterLongitude[longitudeIndex]!,
|
|
503
582
|
),
|
|
504
583
|
outlineColor: verticalProgress < 0.54 ? `${palette.highlight}69` : `${palette.shadow}78`,
|
|
505
584
|
});
|
|
@@ -521,6 +600,32 @@ function sampleContinuousOctopusSurfacePoint(
|
|
|
521
600
|
options: ContinuousOctopusSurfaceOptions,
|
|
522
601
|
latitude: number,
|
|
523
602
|
longitude: number,
|
|
603
|
+
): Point3D {
|
|
604
|
+
return sampleContinuousOctopusSurfacePointWithLongitudeCache(
|
|
605
|
+
options,
|
|
606
|
+
latitude,
|
|
607
|
+
longitude,
|
|
608
|
+
resolveContinuousTentacleInfluence(options, longitude),
|
|
609
|
+
resolveContinuousLobeWave(options, longitude),
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Samples one point on the continuous Octopus 3D 3 surface using precomputed longitude-only
|
|
615
|
+
* values to skip the per-call `Math.exp` tentacle-influence loop and the lobe-wave trig call.
|
|
616
|
+
*
|
|
617
|
+
* The patch loop quantizes the mesh into a fixed `(latitudePatchCount + 1) * (longitudePatchCount + 1)`
|
|
618
|
+
* corner grid, so the same longitude is reused across every latitude row and each
|
|
619
|
+
* tentacle/lobe value can be computed once per frame instead of `latitudePatchCount * 4` times.
|
|
620
|
+
*
|
|
621
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
622
|
+
*/
|
|
623
|
+
function sampleContinuousOctopusSurfacePointWithLongitudeCache(
|
|
624
|
+
options: ContinuousOctopusSurfaceOptions,
|
|
625
|
+
latitude: number,
|
|
626
|
+
longitude: number,
|
|
627
|
+
tentacleInfluence: ContinuousOctopusTentacleInfluence,
|
|
628
|
+
lowerLobeWave: number,
|
|
524
629
|
): Point3D {
|
|
525
630
|
const { radiusX, radiusY, radiusZ, morphologyProfile, timeMs, animationPhase } = options;
|
|
526
631
|
const cosineLatitude = Math.max(0, Math.cos(latitude));
|
|
@@ -528,10 +633,8 @@ function sampleContinuousOctopusSurfacePoint(
|
|
|
528
633
|
const upperBlend = Math.pow(1 - verticalProgress, 1.28);
|
|
529
634
|
const lowerBlend = smoothStep(0.38, 1, verticalProgress);
|
|
530
635
|
const tipBlend = smoothStep(0.68, 1, verticalProgress);
|
|
531
|
-
const tentacleInfluence = resolveContinuousTentacleInfluence(options, longitude);
|
|
532
636
|
const centerPull = resolveSignedAngularDistance(longitude, tentacleInfluence.centerLongitude);
|
|
533
637
|
const effectiveLongitude = longitude + centerPull * lowerBlend * tentacleInfluence.core * (0.24 + tipBlend * 0.2);
|
|
534
|
-
const lowerLobeWave = resolveContinuousLobeWave(options, longitude);
|
|
535
638
|
const mantleRipple =
|
|
536
639
|
Math.sin(
|
|
537
640
|
longitude * morphologyProfile.body.lobeCount +
|
|
@@ -282,12 +282,28 @@ function collectExampleInteractionLines(
|
|
|
282
282
|
const initialMessage = parseResult.commitments.find((commitment) => commitment.type === 'INITIAL MESSAGE')?.content;
|
|
283
283
|
|
|
284
284
|
if (initialMessage) {
|
|
285
|
-
examples.push(
|
|
285
|
+
examples.push(
|
|
286
|
+
spaceTrim(
|
|
287
|
+
(block) => `
|
|
288
|
+
**Agent:**
|
|
289
|
+
${block(initialMessage)}
|
|
290
|
+
`,
|
|
291
|
+
),
|
|
292
|
+
);
|
|
286
293
|
}
|
|
287
294
|
|
|
288
295
|
if (samples && samples.length > 0) {
|
|
289
296
|
for (const sample of samples) {
|
|
290
|
-
examples.push(
|
|
297
|
+
examples.push(
|
|
298
|
+
spaceTrim(
|
|
299
|
+
(block) => `
|
|
300
|
+
**User:** ${block(String(sample.question))}
|
|
301
|
+
|
|
302
|
+
**Agent:**
|
|
303
|
+
${block(sample.answer)}
|
|
304
|
+
`,
|
|
305
|
+
),
|
|
306
|
+
);
|
|
291
307
|
}
|
|
292
308
|
}
|
|
293
309
|
|
package/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.ts
CHANGED
|
@@ -69,7 +69,13 @@ function removeLeadingTopLevelHeading(markdown: string): string {
|
|
|
69
69
|
* @private internal utility of `createStandaloneBookLanguageMarkdown`
|
|
70
70
|
*/
|
|
71
71
|
function renderDocumentationSection(title: string, documentation: string): string {
|
|
72
|
-
return
|
|
72
|
+
return spaceTrim(
|
|
73
|
+
(block) => `
|
|
74
|
+
#### ${title}
|
|
75
|
+
|
|
76
|
+
${block(removeLeadingTopLevelHeading(documentation))}
|
|
77
|
+
`,
|
|
78
|
+
);
|
|
73
79
|
}
|
|
74
80
|
|
|
75
81
|
/**
|
|
@@ -88,6 +88,7 @@ export function Chat(props: ChatProps) {
|
|
|
88
88
|
feedbackMode = 'stars',
|
|
89
89
|
feedbackTranslations,
|
|
90
90
|
timingTranslations,
|
|
91
|
+
resolveCitationLabel,
|
|
91
92
|
onFileUpload,
|
|
92
93
|
chatLocale,
|
|
93
94
|
speechRecognition,
|
|
@@ -337,6 +338,7 @@ export function Chat(props: ChatProps) {
|
|
|
337
338
|
feedbackMode={feedbackMode}
|
|
338
339
|
feedbackTranslations={feedbackTranslations}
|
|
339
340
|
timingTranslations={timingTranslations}
|
|
341
|
+
resolveCitationLabel={resolveCitationLabel}
|
|
340
342
|
chatLocale={chatLocale}
|
|
341
343
|
onCopy={handleCopy}
|
|
342
344
|
onMessage={onMessage}
|
|
@@ -404,6 +406,7 @@ export function Chat(props: ChatProps) {
|
|
|
404
406
|
toolCallIdentity={selectedToolCallIdentity}
|
|
405
407
|
onClose={closeToolCallModal}
|
|
406
408
|
toolTitles={toolTitles}
|
|
409
|
+
resolveCitationLabel={resolveCitationLabel}
|
|
407
410
|
agentParticipant={agentParticipant}
|
|
408
411
|
buttonColor={buttonColor}
|
|
409
412
|
teamAgentProfiles={teamAgentProfiles}
|
|
@@ -417,6 +420,7 @@ export function Chat(props: ChatProps) {
|
|
|
417
420
|
isOpen={citationModalOpen}
|
|
418
421
|
citation={selectedCitation}
|
|
419
422
|
participants={participants}
|
|
423
|
+
resolveCitationLabel={resolveCitationLabel}
|
|
420
424
|
soundSystem={soundSystem}
|
|
421
425
|
onClose={closeCitationModal}
|
|
422
426
|
/>
|
|
@@ -5,7 +5,9 @@ import { DownloadIcon } from '../../icons/DownloadIcon';
|
|
|
5
5
|
import { classNames } from '../../_common/react-utils/classNames';
|
|
6
6
|
import { MarkdownContent } from '../MarkdownContent/MarkdownContent';
|
|
7
7
|
import type { ChatParticipant } from '../types/ChatParticipant';
|
|
8
|
-
import {
|
|
8
|
+
import type { CitationLabelResolver } from '../types/CitationLabelResolver';
|
|
9
|
+
import { useResolvedCitationLabel } from '../hooks/useResolvedCitationLabel';
|
|
10
|
+
import { isPlainTextCitation, resolveCitationPreviewUrl } from '../utils/citationHelpers';
|
|
9
11
|
import type { ParsedCitation } from '../utils/parseCitationsFromContent';
|
|
10
12
|
import styles from './Chat.module.css';
|
|
11
13
|
import { CitationIframePreview } from './CitationIframePreview';
|
|
@@ -20,17 +22,30 @@ export type ChatCitationModalProps = {
|
|
|
20
22
|
isOpen: boolean;
|
|
21
23
|
citation: ParsedCitation | null;
|
|
22
24
|
participants: ReadonlyArray<ChatParticipant>;
|
|
25
|
+
resolveCitationLabel?: CitationLabelResolver;
|
|
23
26
|
soundSystem?: ChatSoundSystem;
|
|
24
27
|
onClose: () => void;
|
|
25
28
|
};
|
|
26
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Empty citation used to keep modal hooks unconditional while the modal is closed.
|
|
32
|
+
*
|
|
33
|
+
* @private component constant of `<ChatCitationModal/>`
|
|
34
|
+
*/
|
|
35
|
+
const EMPTY_MODAL_CITATION: ParsedCitation = {
|
|
36
|
+
id: '',
|
|
37
|
+
source: '',
|
|
38
|
+
};
|
|
39
|
+
|
|
27
40
|
/**
|
|
28
41
|
* Modal that previews a citation source or excerpt.
|
|
29
42
|
*
|
|
30
43
|
* @private component of `<Chat/>`
|
|
31
44
|
*/
|
|
32
45
|
export function ChatCitationModal(props: ChatCitationModalProps) {
|
|
33
|
-
const { isOpen, citation, participants, soundSystem, onClose } = props;
|
|
46
|
+
const { isOpen, citation, participants, resolveCitationLabel, soundSystem, onClose } = props;
|
|
47
|
+
const resolvedCitation = citation || EMPTY_MODAL_CITATION;
|
|
48
|
+
const label = useResolvedCitationLabel(resolvedCitation, resolveCitationLabel);
|
|
34
49
|
|
|
35
50
|
if (!isOpen || !citation) {
|
|
36
51
|
return null;
|
|
@@ -43,7 +58,6 @@ export function ChatCitationModal(props: ChatCitationModalProps) {
|
|
|
43
58
|
const previewSegment = previewBase.split('/').pop() || previewBase;
|
|
44
59
|
const extension = previewSegment.split('.').pop()?.toLowerCase();
|
|
45
60
|
const isImage = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'].includes(extension || '');
|
|
46
|
-
const label = getCitationLabel(citation);
|
|
47
61
|
const isTextCitation = isPlainTextCitation(citation);
|
|
48
62
|
const hasTextPreview = !isValidUrl && (citation.excerpt || isTextCitation);
|
|
49
63
|
const textPreviewContent = isTextCitation ? citation.source : citation.excerpt ?? '';
|