@otto-assistant/bridge 0.4.92
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/bin.js +2 -0
- package/dist/agent-model.e2e.test.js +755 -0
- package/dist/ai-tool-to-genai.js +233 -0
- package/dist/ai-tool-to-genai.test.js +267 -0
- package/dist/ai-tool.js +6 -0
- package/dist/anthropic-auth-plugin.js +728 -0
- package/dist/anthropic-auth-plugin.test.js +125 -0
- package/dist/anthropic-auth-state.js +231 -0
- package/dist/bin.js +90 -0
- package/dist/channel-management.js +227 -0
- package/dist/cli-parsing.test.js +137 -0
- package/dist/cli-send-thread.e2e.test.js +356 -0
- package/dist/cli.js +3276 -0
- package/dist/commands/abort.js +65 -0
- package/dist/commands/action-buttons.js +245 -0
- package/dist/commands/add-project.js +113 -0
- package/dist/commands/agent.js +335 -0
- package/dist/commands/ask-question.js +274 -0
- package/dist/commands/btw.js +116 -0
- package/dist/commands/compact.js +120 -0
- package/dist/commands/context-usage.js +140 -0
- package/dist/commands/create-new-project.js +130 -0
- package/dist/commands/diff.js +63 -0
- package/dist/commands/file-upload.js +275 -0
- package/dist/commands/fork.js +220 -0
- package/dist/commands/gemini-apikey.js +70 -0
- package/dist/commands/login.js +885 -0
- package/dist/commands/mcp.js +239 -0
- package/dist/commands/memory-snapshot.js +24 -0
- package/dist/commands/mention-mode.js +44 -0
- package/dist/commands/merge-worktree.js +159 -0
- package/dist/commands/model-variant.js +364 -0
- package/dist/commands/model.js +776 -0
- package/dist/commands/new-worktree.js +366 -0
- package/dist/commands/paginated-select.js +57 -0
- package/dist/commands/permissions.js +274 -0
- package/dist/commands/queue.js +206 -0
- package/dist/commands/remove-project.js +115 -0
- package/dist/commands/restart-opencode-server.js +127 -0
- package/dist/commands/resume.js +149 -0
- package/dist/commands/run-command.js +79 -0
- package/dist/commands/screenshare.js +303 -0
- package/dist/commands/screenshare.test.js +20 -0
- package/dist/commands/session-id.js +78 -0
- package/dist/commands/session.js +176 -0
- package/dist/commands/share.js +80 -0
- package/dist/commands/tasks.js +205 -0
- package/dist/commands/types.js +2 -0
- package/dist/commands/undo-redo.js +305 -0
- package/dist/commands/unset-model.js +138 -0
- package/dist/commands/upgrade.js +42 -0
- package/dist/commands/user-command.js +155 -0
- package/dist/commands/verbosity.js +125 -0
- package/dist/commands/worktree-settings.js +43 -0
- package/dist/commands/worktrees.js +410 -0
- package/dist/condense-memory.js +33 -0
- package/dist/config.js +94 -0
- package/dist/context-awareness-plugin.js +363 -0
- package/dist/context-awareness-plugin.test.js +124 -0
- package/dist/critique-utils.js +95 -0
- package/dist/database.js +1310 -0
- package/dist/db.js +251 -0
- package/dist/db.test.js +138 -0
- package/dist/debounce-timeout.js +28 -0
- package/dist/debounced-process-flush.js +77 -0
- package/dist/discord-bot.js +1008 -0
- package/dist/discord-command-registration.js +524 -0
- package/dist/discord-urls.js +81 -0
- package/dist/discord-utils.js +591 -0
- package/dist/discord-utils.test.js +134 -0
- package/dist/errors.js +157 -0
- package/dist/escape-backticks.test.js +429 -0
- package/dist/event-stream-real-capture.e2e.test.js +533 -0
- package/dist/eventsource-parser.test.js +327 -0
- package/dist/exec-async.js +26 -0
- package/dist/external-opencode-sync.js +480 -0
- package/dist/format-tables.js +302 -0
- package/dist/format-tables.test.js +308 -0
- package/dist/forum-sync/config.js +79 -0
- package/dist/forum-sync/discord-operations.js +154 -0
- package/dist/forum-sync/index.js +5 -0
- package/dist/forum-sync/markdown.js +113 -0
- package/dist/forum-sync/sync-to-discord.js +417 -0
- package/dist/forum-sync/sync-to-files.js +190 -0
- package/dist/forum-sync/types.js +53 -0
- package/dist/forum-sync/watchers.js +307 -0
- package/dist/gateway-proxy-reconnect.e2e.test.js +394 -0
- package/dist/gateway-proxy.e2e.test.js +483 -0
- package/dist/genai-worker-wrapper.js +111 -0
- package/dist/genai-worker.js +311 -0
- package/dist/genai.js +232 -0
- package/dist/generated/browser.js +17 -0
- package/dist/generated/client.js +37 -0
- package/dist/generated/commonInputTypes.js +10 -0
- package/dist/generated/enums.js +52 -0
- package/dist/generated/internal/class.js +49 -0
- package/dist/generated/internal/prismaNamespace.js +253 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +223 -0
- package/dist/generated/models/bot_api_keys.js +1 -0
- package/dist/generated/models/bot_tokens.js +1 -0
- package/dist/generated/models/channel_agents.js +1 -0
- package/dist/generated/models/channel_directories.js +1 -0
- package/dist/generated/models/channel_mention_mode.js +1 -0
- package/dist/generated/models/channel_models.js +1 -0
- package/dist/generated/models/channel_verbosity.js +1 -0
- package/dist/generated/models/channel_worktrees.js +1 -0
- package/dist/generated/models/forum_sync_configs.js +1 -0
- package/dist/generated/models/global_models.js +1 -0
- package/dist/generated/models/ipc_requests.js +1 -0
- package/dist/generated/models/part_messages.js +1 -0
- package/dist/generated/models/scheduled_tasks.js +1 -0
- package/dist/generated/models/session_agents.js +1 -0
- package/dist/generated/models/session_events.js +1 -0
- package/dist/generated/models/session_models.js +1 -0
- package/dist/generated/models/session_start_sources.js +1 -0
- package/dist/generated/models/thread_sessions.js +1 -0
- package/dist/generated/models/thread_worktrees.js +1 -0
- package/dist/generated/models.js +1 -0
- package/dist/heap-monitor.js +122 -0
- package/dist/hrana-server.js +263 -0
- package/dist/hrana-server.test.js +370 -0
- package/dist/html-actions.js +123 -0
- package/dist/html-actions.test.js +70 -0
- package/dist/html-components.js +117 -0
- package/dist/html-components.test.js +34 -0
- package/dist/image-optimizer-plugin.js +153 -0
- package/dist/image-utils.js +112 -0
- package/dist/interaction-handler.js +397 -0
- package/dist/ipc-polling.js +252 -0
- package/dist/ipc-tools-plugin.js +193 -0
- package/dist/kimaki-digital-twin.e2e.test.js +161 -0
- package/dist/kimaki-opencode-plugin-loading.e2e.test.js +87 -0
- package/dist/kimaki-opencode-plugin.js +17 -0
- package/dist/kimaki-opencode-plugin.test.js +98 -0
- package/dist/limit-heading-depth.js +25 -0
- package/dist/limit-heading-depth.test.js +105 -0
- package/dist/logger.js +165 -0
- package/dist/markdown.js +342 -0
- package/dist/markdown.test.js +257 -0
- package/dist/message-finish-field.e2e.test.js +165 -0
- package/dist/message-formatting.js +413 -0
- package/dist/message-formatting.test.js +73 -0
- package/dist/message-preprocessing.js +330 -0
- package/dist/onboarding-tutorial.js +172 -0
- package/dist/onboarding-welcome.js +37 -0
- package/dist/openai-realtime.js +224 -0
- package/dist/opencode-command-detection.js +65 -0
- package/dist/opencode-command-detection.test.js +240 -0
- package/dist/opencode-command.js +129 -0
- package/dist/opencode-command.test.js +48 -0
- package/dist/opencode-interrupt-plugin.js +361 -0
- package/dist/opencode-interrupt-plugin.test.js +458 -0
- package/dist/opencode.js +861 -0
- package/dist/otto/branding.js +22 -0
- package/dist/otto/index.js +21 -0
- package/dist/parse-permission-rules.test.js +117 -0
- package/dist/patch-text-parser.js +97 -0
- package/dist/plugin-logger.js +59 -0
- package/dist/privacy-sanitizer.js +105 -0
- package/dist/queue-advanced-abort.e2e.test.js +293 -0
- package/dist/queue-advanced-action-buttons.e2e.test.js +206 -0
- package/dist/queue-advanced-e2e-setup.js +786 -0
- package/dist/queue-advanced-footer.e2e.test.js +472 -0
- package/dist/queue-advanced-model-switch.e2e.test.js +299 -0
- package/dist/queue-advanced-permissions-typing.e2e.test.js +180 -0
- package/dist/queue-advanced-question.e2e.test.js +261 -0
- package/dist/queue-advanced-typing-interrupt.e2e.test.js +114 -0
- package/dist/queue-advanced-typing.e2e.test.js +153 -0
- package/dist/queue-drain-after-interactive-ui.e2e.test.js +119 -0
- package/dist/queue-interrupt-drain.e2e.test.js +135 -0
- package/dist/queue-question-select-drain.e2e.test.js +120 -0
- package/dist/runtime-idle-sweeper.js +52 -0
- package/dist/runtime-lifecycle.e2e.test.js +508 -0
- package/dist/sentry.js +23 -0
- package/dist/session-handler/agent-utils.js +67 -0
- package/dist/session-handler/event-stream-state.js +420 -0
- package/dist/session-handler/event-stream-state.test.js +563 -0
- package/dist/session-handler/model-utils.js +124 -0
- package/dist/session-handler/opencode-session-event-log.js +94 -0
- package/dist/session-handler/thread-runtime-state.js +104 -0
- package/dist/session-handler/thread-session-runtime.js +3258 -0
- package/dist/session-handler.js +9 -0
- package/dist/session-search.js +100 -0
- package/dist/session-search.test.js +40 -0
- package/dist/session-title-rename.test.js +80 -0
- package/dist/startup-service.js +153 -0
- package/dist/startup-time.e2e.test.js +296 -0
- package/dist/store.js +17 -0
- package/dist/system-message.js +613 -0
- package/dist/system-message.test.js +602 -0
- package/dist/task-runner.js +295 -0
- package/dist/task-schedule.js +209 -0
- package/dist/task-schedule.test.js +71 -0
- package/dist/test-utils.js +299 -0
- package/dist/thinking-utils.js +35 -0
- package/dist/thread-message-queue.e2e.test.js +999 -0
- package/dist/tools.js +357 -0
- package/dist/undo-redo.e2e.test.js +161 -0
- package/dist/unnest-code-blocks.js +146 -0
- package/dist/unnest-code-blocks.test.js +673 -0
- package/dist/upgrade.js +114 -0
- package/dist/utils.js +144 -0
- package/dist/voice-attachment.js +34 -0
- package/dist/voice-handler.js +646 -0
- package/dist/voice-message.e2e.test.js +1021 -0
- package/dist/voice.js +447 -0
- package/dist/voice.test.js +235 -0
- package/dist/wait-session.js +94 -0
- package/dist/websockify.js +69 -0
- package/dist/worker-types.js +4 -0
- package/dist/worktree-lifecycle.e2e.test.js +308 -0
- package/dist/worktree-utils.js +3 -0
- package/dist/worktrees.js +929 -0
- package/dist/worktrees.test.js +189 -0
- package/dist/xml.js +92 -0
- package/dist/xml.test.js +32 -0
- package/package.json +98 -0
- package/schema.prisma +295 -0
- package/skills/batch/SKILL.md +87 -0
- package/skills/critique/SKILL.md +112 -0
- package/skills/egaki/SKILL.md +100 -0
- package/skills/errore/SKILL.md +647 -0
- package/skills/event-sourcing-state/SKILL.md +252 -0
- package/skills/gitchamber/SKILL.md +93 -0
- package/skills/goke/SKILL.md +644 -0
- package/skills/jitter/EDITOR.md +219 -0
- package/skills/jitter/EXPORT-INTERNALS.md +309 -0
- package/skills/jitter/SKILL.md +158 -0
- package/skills/jitter/jitter-clipboard.json +1042 -0
- package/skills/jitter/package.json +14 -0
- package/skills/jitter/tsconfig.json +15 -0
- package/skills/jitter/utils/actions.ts +212 -0
- package/skills/jitter/utils/export.ts +114 -0
- package/skills/jitter/utils/index.ts +141 -0
- package/skills/jitter/utils/snapshot.ts +154 -0
- package/skills/jitter/utils/traverse.ts +246 -0
- package/skills/jitter/utils/types.ts +279 -0
- package/skills/jitter/utils/wait.ts +133 -0
- package/skills/lintcn/SKILL.md +873 -0
- package/skills/new-skill/SKILL.md +211 -0
- package/skills/npm-package/SKILL.md +239 -0
- package/skills/playwriter/SKILL.md +35 -0
- package/skills/proxyman/SKILL.md +215 -0
- package/skills/security-review/SKILL.md +208 -0
- package/skills/simplify/SKILL.md +58 -0
- package/skills/spiceflow/SKILL.md +14 -0
- package/skills/termcast/SKILL.md +945 -0
- package/skills/tuistory/SKILL.md +250 -0
- package/skills/usecomputer/SKILL.md +264 -0
- package/skills/x-articles/SKILL.md +554 -0
- package/skills/zele/SKILL.md +112 -0
- package/skills/zustand-centralized-state/SKILL.md +1004 -0
- package/src/agent-model.e2e.test.ts +976 -0
- package/src/ai-tool-to-genai.test.ts +296 -0
- package/src/ai-tool-to-genai.ts +283 -0
- package/src/ai-tool.ts +39 -0
- package/src/anthropic-auth-plugin.test.ts +159 -0
- package/src/anthropic-auth-plugin.ts +861 -0
- package/src/anthropic-auth-state.ts +282 -0
- package/src/bin.ts +111 -0
- package/src/channel-management.ts +334 -0
- package/src/cli-parsing.test.ts +195 -0
- package/src/cli-send-thread.e2e.test.ts +464 -0
- package/src/cli.ts +4581 -0
- package/src/commands/abort.ts +89 -0
- package/src/commands/action-buttons.ts +364 -0
- package/src/commands/add-project.ts +149 -0
- package/src/commands/agent.ts +473 -0
- package/src/commands/ask-question.ts +390 -0
- package/src/commands/btw.ts +164 -0
- package/src/commands/compact.ts +157 -0
- package/src/commands/context-usage.ts +199 -0
- package/src/commands/create-new-project.ts +190 -0
- package/src/commands/diff.ts +91 -0
- package/src/commands/file-upload.ts +389 -0
- package/src/commands/fork.ts +321 -0
- package/src/commands/gemini-apikey.ts +104 -0
- package/src/commands/login.ts +1173 -0
- package/src/commands/mcp.ts +307 -0
- package/src/commands/memory-snapshot.ts +30 -0
- package/src/commands/mention-mode.ts +68 -0
- package/src/commands/merge-worktree.ts +223 -0
- package/src/commands/model-variant.ts +483 -0
- package/src/commands/model.ts +1053 -0
- package/src/commands/new-worktree.ts +510 -0
- package/src/commands/paginated-select.ts +81 -0
- package/src/commands/permissions.ts +397 -0
- package/src/commands/queue.ts +271 -0
- package/src/commands/remove-project.ts +155 -0
- package/src/commands/restart-opencode-server.ts +162 -0
- package/src/commands/resume.ts +230 -0
- package/src/commands/run-command.ts +123 -0
- package/src/commands/screenshare.test.ts +30 -0
- package/src/commands/screenshare.ts +366 -0
- package/src/commands/session-id.ts +109 -0
- package/src/commands/session.ts +227 -0
- package/src/commands/share.ts +106 -0
- package/src/commands/tasks.ts +293 -0
- package/src/commands/types.ts +25 -0
- package/src/commands/undo-redo.ts +386 -0
- package/src/commands/unset-model.ts +173 -0
- package/src/commands/upgrade.ts +52 -0
- package/src/commands/user-command.ts +198 -0
- package/src/commands/verbosity.ts +173 -0
- package/src/commands/worktree-settings.ts +70 -0
- package/src/commands/worktrees.ts +552 -0
- package/src/condense-memory.ts +36 -0
- package/src/config.ts +111 -0
- package/src/context-awareness-plugin.test.ts +142 -0
- package/src/context-awareness-plugin.ts +510 -0
- package/src/critique-utils.ts +139 -0
- package/src/database.ts +1876 -0
- package/src/db.test.ts +162 -0
- package/src/db.ts +286 -0
- package/src/debounce-timeout.ts +43 -0
- package/src/debounced-process-flush.ts +104 -0
- package/src/discord-bot.ts +1330 -0
- package/src/discord-command-registration.ts +693 -0
- package/src/discord-urls.ts +88 -0
- package/src/discord-utils.test.ts +153 -0
- package/src/discord-utils.ts +800 -0
- package/src/errors.ts +201 -0
- package/src/escape-backticks.test.ts +469 -0
- package/src/event-stream-real-capture.e2e.test.ts +692 -0
- package/src/eventsource-parser.test.ts +351 -0
- package/src/exec-async.ts +35 -0
- package/src/external-opencode-sync.ts +685 -0
- package/src/format-tables.test.ts +335 -0
- package/src/format-tables.ts +445 -0
- package/src/forum-sync/config.ts +92 -0
- package/src/forum-sync/discord-operations.ts +241 -0
- package/src/forum-sync/index.ts +9 -0
- package/src/forum-sync/markdown.ts +172 -0
- package/src/forum-sync/sync-to-discord.ts +595 -0
- package/src/forum-sync/sync-to-files.ts +294 -0
- package/src/forum-sync/types.ts +175 -0
- package/src/forum-sync/watchers.ts +454 -0
- package/src/gateway-proxy-reconnect.e2e.test.ts +523 -0
- package/src/gateway-proxy.e2e.test.ts +640 -0
- package/src/genai-worker-wrapper.ts +164 -0
- package/src/genai-worker.ts +386 -0
- package/src/genai.ts +321 -0
- package/src/generated/browser.ts +114 -0
- package/src/generated/client.ts +138 -0
- package/src/generated/commonInputTypes.ts +736 -0
- package/src/generated/enums.ts +88 -0
- package/src/generated/internal/class.ts +384 -0
- package/src/generated/internal/prismaNamespace.ts +2386 -0
- package/src/generated/internal/prismaNamespaceBrowser.ts +326 -0
- package/src/generated/models/bot_api_keys.ts +1288 -0
- package/src/generated/models/bot_tokens.ts +1656 -0
- package/src/generated/models/channel_agents.ts +1256 -0
- package/src/generated/models/channel_directories.ts +1859 -0
- package/src/generated/models/channel_mention_mode.ts +1300 -0
- package/src/generated/models/channel_models.ts +1288 -0
- package/src/generated/models/channel_verbosity.ts +1228 -0
- package/src/generated/models/channel_worktrees.ts +1300 -0
- package/src/generated/models/forum_sync_configs.ts +1452 -0
- package/src/generated/models/global_models.ts +1288 -0
- package/src/generated/models/ipc_requests.ts +1485 -0
- package/src/generated/models/part_messages.ts +1302 -0
- package/src/generated/models/scheduled_tasks.ts +2320 -0
- package/src/generated/models/session_agents.ts +1086 -0
- package/src/generated/models/session_events.ts +1439 -0
- package/src/generated/models/session_models.ts +1114 -0
- package/src/generated/models/session_start_sources.ts +1408 -0
- package/src/generated/models/thread_sessions.ts +1781 -0
- package/src/generated/models/thread_worktrees.ts +1356 -0
- package/src/generated/models.ts +30 -0
- package/src/heap-monitor.ts +152 -0
- package/src/hrana-server.test.ts +434 -0
- package/src/hrana-server.ts +314 -0
- package/src/html-actions.test.ts +87 -0
- package/src/html-actions.ts +174 -0
- package/src/html-components.test.ts +38 -0
- package/src/html-components.ts +181 -0
- package/src/image-optimizer-plugin.ts +194 -0
- package/src/image-utils.ts +149 -0
- package/src/interaction-handler.ts +576 -0
- package/src/ipc-polling.ts +326 -0
- package/src/ipc-tools-plugin.ts +236 -0
- package/src/kimaki-digital-twin.e2e.test.ts +199 -0
- package/src/kimaki-opencode-plugin-loading.e2e.test.ts +109 -0
- package/src/kimaki-opencode-plugin.test.ts +108 -0
- package/src/kimaki-opencode-plugin.ts +18 -0
- package/src/limit-heading-depth.test.ts +116 -0
- package/src/limit-heading-depth.ts +26 -0
- package/src/logger.ts +208 -0
- package/src/markdown.test.ts +308 -0
- package/src/markdown.ts +410 -0
- package/src/message-finish-field.e2e.test.ts +192 -0
- package/src/message-formatting.test.ts +81 -0
- package/src/message-formatting.ts +533 -0
- package/src/message-preprocessing.ts +455 -0
- package/src/onboarding-tutorial.ts +176 -0
- package/src/onboarding-welcome.ts +49 -0
- package/src/openai-realtime.ts +358 -0
- package/src/opencode-command-detection.test.ts +307 -0
- package/src/opencode-command-detection.ts +76 -0
- package/src/opencode-command.test.ts +70 -0
- package/src/opencode-command.ts +188 -0
- package/src/opencode-interrupt-plugin.test.ts +677 -0
- package/src/opencode-interrupt-plugin.ts +477 -0
- package/src/opencode.ts +1110 -0
- package/src/otto/branding.ts +23 -0
- package/src/otto/index.ts +22 -0
- package/src/parse-permission-rules.test.ts +127 -0
- package/src/patch-text-parser.ts +107 -0
- package/src/plugin-logger.ts +68 -0
- package/src/privacy-sanitizer.ts +142 -0
- package/src/queue-advanced-abort.e2e.test.ts +382 -0
- package/src/queue-advanced-action-buttons.e2e.test.ts +268 -0
- package/src/queue-advanced-e2e-setup.ts +873 -0
- package/src/queue-advanced-footer.e2e.test.ts +576 -0
- package/src/queue-advanced-model-switch.e2e.test.ts +383 -0
- package/src/queue-advanced-permissions-typing.e2e.test.ts +245 -0
- package/src/queue-advanced-question.e2e.test.ts +316 -0
- package/src/queue-advanced-typing-interrupt.e2e.test.ts +146 -0
- package/src/queue-advanced-typing.e2e.test.ts +199 -0
- package/src/queue-drain-after-interactive-ui.e2e.test.ts +151 -0
- package/src/queue-interrupt-drain.e2e.test.ts +166 -0
- package/src/queue-question-select-drain.e2e.test.ts +152 -0
- package/src/runtime-idle-sweeper.ts +76 -0
- package/src/runtime-lifecycle.e2e.test.ts +641 -0
- package/src/schema.sql +173 -0
- package/src/sentry.ts +26 -0
- package/src/session-handler/agent-utils.ts +97 -0
- package/src/session-handler/event-stream-fixtures/real-session-action-buttons.jsonl +45 -0
- package/src/session-handler/event-stream-fixtures/real-session-footer-suppressed-on-pre-idle-interrupt.jsonl +40 -0
- package/src/session-handler/event-stream-fixtures/real-session-permission-external-file.jsonl +23 -0
- package/src/session-handler/event-stream-fixtures/real-session-task-normal.jsonl +22 -0
- package/src/session-handler/event-stream-fixtures/real-session-task-three-parallel-sleeps.jsonl +277 -0
- package/src/session-handler/event-stream-fixtures/real-session-task-user-interruption.jsonl +46 -0
- package/src/session-handler/event-stream-fixtures/session-abort-after-idle-race.jsonl +21 -0
- package/src/session-handler/event-stream-fixtures/session-concurrent-messages-serialized.jsonl +56 -0
- package/src/session-handler/event-stream-fixtures/session-explicit-abort.jsonl +44 -0
- package/src/session-handler/event-stream-fixtures/session-normal-completion.jsonl +29 -0
- package/src/session-handler/event-stream-fixtures/session-tool-call-noisy-stream.jsonl +29 -0
- package/src/session-handler/event-stream-fixtures/session-two-completions-same-session.jsonl +50 -0
- package/src/session-handler/event-stream-fixtures/session-user-interruption.jsonl +59 -0
- package/src/session-handler/event-stream-fixtures/session-voice-queued-followup.jsonl +52 -0
- package/src/session-handler/event-stream-state.test.ts +645 -0
- package/src/session-handler/event-stream-state.ts +608 -0
- package/src/session-handler/model-utils.ts +183 -0
- package/src/session-handler/opencode-session-event-log.ts +130 -0
- package/src/session-handler/thread-runtime-state.ts +212 -0
- package/src/session-handler/thread-session-runtime.ts +4281 -0
- package/src/session-handler.ts +15 -0
- package/src/session-search.test.ts +50 -0
- package/src/session-search.ts +148 -0
- package/src/session-title-rename.test.ts +112 -0
- package/src/startup-service.ts +200 -0
- package/src/startup-time.e2e.test.ts +373 -0
- package/src/store.ts +122 -0
- package/src/system-message.test.ts +612 -0
- package/src/system-message.ts +723 -0
- package/src/task-runner.ts +421 -0
- package/src/task-schedule.test.ts +84 -0
- package/src/task-schedule.ts +311 -0
- package/src/test-utils.ts +435 -0
- package/src/thinking-utils.ts +61 -0
- package/src/thread-message-queue.e2e.test.ts +1219 -0
- package/src/tools.ts +430 -0
- package/src/undici.d.ts +12 -0
- package/src/undo-redo.e2e.test.ts +209 -0
- package/src/unnest-code-blocks.test.ts +713 -0
- package/src/unnest-code-blocks.ts +185 -0
- package/src/upgrade.ts +127 -0
- package/src/utils.ts +212 -0
- package/src/voice-attachment.ts +51 -0
- package/src/voice-handler.ts +908 -0
- package/src/voice-message.e2e.test.ts +1255 -0
- package/src/voice.test.ts +281 -0
- package/src/voice.ts +627 -0
- package/src/wait-session.ts +147 -0
- package/src/websockify.ts +101 -0
- package/src/worker-types.ts +64 -0
- package/src/worktree-lifecycle.e2e.test.ts +391 -0
- package/src/worktree-utils.ts +4 -0
- package/src/worktrees.test.ts +223 -0
- package/src/worktrees.ts +1294 -0
- package/src/xml.test.ts +38 -0
- package/src/xml.ts +121 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Jitter Editor API Reference
|
|
2
|
+
|
|
3
|
+
Reference for `window.app` methods and layer types. For utilities, see SKILL.md and use `jitterUtils.*`.
|
|
4
|
+
|
|
5
|
+
## App Instance Methods
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
// Playback
|
|
9
|
+
app.play()
|
|
10
|
+
app.stopPlayback()
|
|
11
|
+
app.moveCursor(timeInMs)
|
|
12
|
+
|
|
13
|
+
// Layer creation (opens picker or adds at cursor)
|
|
14
|
+
app.addArtboard()
|
|
15
|
+
app.addText('toolbar')
|
|
16
|
+
app.addRectShape('toolbar')
|
|
17
|
+
app.addEllipseShape('toolbar')
|
|
18
|
+
app.addMedia('toolbar')
|
|
19
|
+
|
|
20
|
+
// File operations
|
|
21
|
+
app.renameFile(newName)
|
|
22
|
+
app.deleteFile()
|
|
23
|
+
app.downloadProject()
|
|
24
|
+
app.scheduleSave()
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Dispatch Actions
|
|
28
|
+
|
|
29
|
+
Use `app.dispatchAction(action)` or `jitterUtils.*` helpers.
|
|
30
|
+
|
|
31
|
+
### Core Actions
|
|
32
|
+
|
|
33
|
+
| Action Type | Purpose |
|
|
34
|
+
| ------------------- | ---------------------- |
|
|
35
|
+
| `updateObjWithUndo` | Update node properties |
|
|
36
|
+
| `addObjWithUndo` | Add new node |
|
|
37
|
+
| `removeObjWithUndo` | Remove nodes |
|
|
38
|
+
| `setSelection` | Select nodes |
|
|
39
|
+
| `emptySelection` | Clear selection |
|
|
40
|
+
| `undo` / `redo` | Undo/redo |
|
|
41
|
+
| `setCurrentTime` | Set playhead time |
|
|
42
|
+
| `zoomToSelection` | Zoom to selected |
|
|
43
|
+
|
|
44
|
+
## Layer Types
|
|
45
|
+
|
|
46
|
+
### Artboard
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
{
|
|
50
|
+
type: "artboard",
|
|
51
|
+
name: "16:9",
|
|
52
|
+
width: 1920,
|
|
53
|
+
height: 1080,
|
|
54
|
+
duration: 11000,
|
|
55
|
+
background: true,
|
|
56
|
+
fillColor: "#ffffff"
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Text
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
{
|
|
64
|
+
type: "text",
|
|
65
|
+
text: "Hello World",
|
|
66
|
+
fontSize: 48,
|
|
67
|
+
font: { name: "Poppins", type: "googlefont", weight: 600 },
|
|
68
|
+
fillColor: "#000000",
|
|
69
|
+
textAlign: "center", // "left" | "center" | "right"
|
|
70
|
+
verticalAlign: "middle"
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Image / SVG / Video / GIF
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
{
|
|
78
|
+
type: "image", // or "svg", "video", "gif"
|
|
79
|
+
url: "https://example.com/asset.jpg",
|
|
80
|
+
width: 400,
|
|
81
|
+
height: 300,
|
|
82
|
+
cornerRadius: 0
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Shapes
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
// Rectangle
|
|
90
|
+
{ type: "rect", fillColor: "#3B82F6", cornerRadius: 8 }
|
|
91
|
+
|
|
92
|
+
// Ellipse
|
|
93
|
+
{ type: "ellipse", fillColor: "#EF4444" }
|
|
94
|
+
|
|
95
|
+
// Star
|
|
96
|
+
{ type: "star", fillColor: "#F59E0B", points: 5, innerRadius: 50 }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Group
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
{
|
|
103
|
+
type: "layerGrp",
|
|
104
|
+
name: "Group Name",
|
|
105
|
+
clipsContent: false,
|
|
106
|
+
cornerRadius: 0
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Common Properties
|
|
111
|
+
|
|
112
|
+
All layers support:
|
|
113
|
+
|
|
114
|
+
| Property | Type | Description |
|
|
115
|
+
| ----------------- | ------- | ------------------- |
|
|
116
|
+
| `x`, `y` | number | Position |
|
|
117
|
+
| `width`, `height` | number | Size |
|
|
118
|
+
| `angle` | number | Rotation in degrees |
|
|
119
|
+
| `scale` | number | Scale factor |
|
|
120
|
+
| `opacity` | number | 0-100 |
|
|
121
|
+
| `shadowEnabled` | boolean | Drop shadow |
|
|
122
|
+
| `strokeEnabled` | boolean | Stroke/border |
|
|
123
|
+
|
|
124
|
+
## Fill Colors
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
// Solid
|
|
128
|
+
fillColor: "#3B82F6"
|
|
129
|
+
|
|
130
|
+
// Linear gradient
|
|
131
|
+
fillColor: {
|
|
132
|
+
type: "GRADIENT_LINEAR",
|
|
133
|
+
stops: [
|
|
134
|
+
{ id: "s1", position: 0, color: "#FF0000" },
|
|
135
|
+
{ id: "s2", position: 1, color: "#0000FF" }
|
|
136
|
+
],
|
|
137
|
+
transform: { angle: 0, sx: 1, tx: 0.5, ty: 0.5 }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Radial gradient
|
|
141
|
+
fillColor: {
|
|
142
|
+
type: "GRADIENT_RADIAL",
|
|
143
|
+
stops: [...],
|
|
144
|
+
transform: { sx: 1, tx: 0.5, ty: 0.5 }
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Easing Presets
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
{ name: "smooth:standard:v1", schema: "v1", config: { intensity: 50 } }
|
|
152
|
+
{ name: "smooth:accelerate:v1", schema: "v1", config: { intensity: 50 } }
|
|
153
|
+
{ name: "smooth:decelerate:v1", schema: "v1", config: { intensity: 50 } }
|
|
154
|
+
{ name: "spring", schema: "v1", config: { stiffness: 100, damping: 10 } }
|
|
155
|
+
{ name: "bounce", schema: "v1", config: { bounces: 3 } }
|
|
156
|
+
{ name: "linear", schema: "v1", config: {} }
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Animation Types
|
|
160
|
+
|
|
161
|
+
### Transform
|
|
162
|
+
|
|
163
|
+
`scale`, `move`, `rotate`, `opacity`
|
|
164
|
+
|
|
165
|
+
### Enter/Exit
|
|
166
|
+
|
|
167
|
+
`fadeIn/Out`, `growIn/Out`, `shrinkIn/Out`, `slideIn/Out`, `spinIn/Out`, `blurIn/Out`, `textIn/Out`
|
|
168
|
+
|
|
169
|
+
### Mask
|
|
170
|
+
|
|
171
|
+
`maskRevealIn/Out`, `maskSlideIn/Out`, `maskCenterIn/Out`
|
|
172
|
+
|
|
173
|
+
### Media
|
|
174
|
+
|
|
175
|
+
`playVideo`, `playAudio`
|
|
176
|
+
|
|
177
|
+
## Node Tree Structure
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
Artboard (type: "artboard")
|
|
181
|
+
├── LayersTree (type: "layersTree")
|
|
182
|
+
│ ├── LayerGrp (type: "layerGrp")
|
|
183
|
+
│ │ ├── Text (type: "text")
|
|
184
|
+
│ │ └── Image (type: "image")
|
|
185
|
+
│ └── SVG (type: "svg")
|
|
186
|
+
└── OperationsTree (type: "operationsTree")
|
|
187
|
+
└── OpGrp (type: "opGrp")
|
|
188
|
+
├── Scale animation
|
|
189
|
+
└── FadeIn animation
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## State Access
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
// Current selection
|
|
196
|
+
const state = app.props.observableEditorState.getSnapshot()
|
|
197
|
+
const selectedIds = state.selection.nodesIds
|
|
198
|
+
|
|
199
|
+
// Project config
|
|
200
|
+
const conf = app.props.observableImmutableConf.lastImmutableConf
|
|
201
|
+
|
|
202
|
+
// File metadata
|
|
203
|
+
const fileMeta = app.props.fileMeta
|
|
204
|
+
// { id, name, bucket, teamId }
|
|
205
|
+
|
|
206
|
+
// Subscribe to changes
|
|
207
|
+
const unsubscribe = app.props.observableImmutableConf.subscribe(() => {
|
|
208
|
+
// Config changed
|
|
209
|
+
})
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## File Actions
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
await app.props.fileActions.duplicateFile(fileId) // Returns new ID
|
|
216
|
+
await app.props.fileActions.deleteFile(fileId)
|
|
217
|
+
await app.props.fileActions.renameFile(name)
|
|
218
|
+
await app.props.fileActions.saveFile()
|
|
219
|
+
```
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Jitter Export Pipeline Internals
|
|
3
|
+
description: |
|
|
4
|
+
Reverse-engineered architecture of Jitter's export and rendering pipeline.
|
|
5
|
+
Covers the headless renderer page, scene graph format, network requests,
|
|
6
|
+
bundle structure, and feasibility of building a standalone local exporter.
|
|
7
|
+
prompt: |
|
|
8
|
+
Analyze the jitter skill. Try it in the playwriter. Then analyze the
|
|
9
|
+
JavaScript code that runs in the exporter page. Think about extracting
|
|
10
|
+
the JavaScript bundle to create a standalone local exporter for AI agents.
|
|
11
|
+
Examine network requests, download the bundle, see where the data for the
|
|
12
|
+
scene graph comes from and how we would override it.
|
|
13
|
+
Files read: @discord/skills/jitter/SKILL.md @discord/skills/jitter/EDITOR.md
|
|
14
|
+
@discord/skills/jitter/utils/export.ts @discord/skills/jitter/utils/wait.ts
|
|
15
|
+
@discord/skills/jitter/utils/types.ts @discord/skills/jitter/utils/traverse.ts
|
|
16
|
+
@discord/skills/jitter/utils/actions.ts
|
|
17
|
+
Used Playwriter to navigate to jitter.video, open a real project, inspect
|
|
18
|
+
window.app, download all JS chunks, and intercept network requests on the
|
|
19
|
+
/api/renderer/ page.
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# Jitter Export Pipeline Internals
|
|
23
|
+
|
|
24
|
+
## Architecture Overview
|
|
25
|
+
|
|
26
|
+
Jitter is a **Gatsby (React) SPA**. Three pages are relevant to export:
|
|
27
|
+
|
|
28
|
+
| Page | Path | Role |
|
|
29
|
+
|------|------|------|
|
|
30
|
+
| Editor | `/file/?id=` | Interactive editor, stores scene graph in `window.app` |
|
|
31
|
+
| Export UI | `/export/` | Plan-limit checks, delegates to renderer |
|
|
32
|
+
| **API Renderer** | `/api/renderer/` | **Headless rendering engine** — the key page |
|
|
33
|
+
|
|
34
|
+
The API Renderer page renders **nothing visible** (`render() { return null }`).
|
|
35
|
+
It exists solely to be driven by an external process (Puppeteer/Playwright on
|
|
36
|
+
Jitter's servers) that calls `window.jitter.renderFrame(time)` in a loop.
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
┌─────────────────────────────────────────────────────────┐
|
|
40
|
+
│ Jitter's export backend (server-side Puppeteer) │
|
|
41
|
+
│ │
|
|
42
|
+
│ 1. Open /api/renderer/?file=X&artboardId=Y&width=... │
|
|
43
|
+
│ 2. Wait for jitterLoadEvent {name:"ready"} │
|
|
44
|
+
│ 3. Loop: window.jitter.renderFrame(t) → PNG string │
|
|
45
|
+
│ 4. Pipe PNGs to FFmpeg → MP4/WebM/GIF │
|
|
46
|
+
│ 5. Upload result to S3, return download link │
|
|
47
|
+
└─────────────────────────────────────────────────────────┘
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## The API Renderer Page
|
|
51
|
+
|
|
52
|
+
**Source:** `component---src-pages-api-renderer-ts` (3KB, all logic delegated
|
|
53
|
+
to modules in `app.js`)
|
|
54
|
+
|
|
55
|
+
**URL params** (all required):
|
|
56
|
+
|
|
57
|
+
| Param | Type | Description |
|
|
58
|
+
|-------|------|-------------|
|
|
59
|
+
| `file` | string | Project/file ID |
|
|
60
|
+
| `bucket` | string | S3 bucket name (e.g. `snackthis-userdata`) |
|
|
61
|
+
| `artboardId` | string | Which artboard to render |
|
|
62
|
+
| `width` | number | Export width in px |
|
|
63
|
+
| `height` | number | Export height in px |
|
|
64
|
+
| `noBg` | boolean | Transparent background |
|
|
65
|
+
| `addWatermark` | boolean | Add Jitter watermark |
|
|
66
|
+
| `superSampling` | number | Render at higher res then downsample |
|
|
67
|
+
| `playbackDirection` | string | `normal`, `reverse`, or `boomerang` |
|
|
68
|
+
| `vfe` | string | Video fallback export (`on`/`off`) |
|
|
69
|
+
|
|
70
|
+
**Lifecycle:**
|
|
71
|
+
|
|
72
|
+
1. Parses and Zod-validates URL params
|
|
73
|
+
2. Loads project data: `GM(fileId, bucket)` — tries IndexedDB cache first,
|
|
74
|
+
then S3/CloudFront
|
|
75
|
+
3. Finds the artboard in the loaded project
|
|
76
|
+
4. Creates a **scene** object (resolves assets, builds render tree)
|
|
77
|
+
5. Creates a **canvas renderer** (Canvas 2D, not WebGL)
|
|
78
|
+
6. Sets `window.jitter`:
|
|
79
|
+
- `exportContext: { exportWidth, exportHeight, exportDuration }`
|
|
80
|
+
- `renderFrame(time)` → renders frame, returns `{ name: "frame", t, pngString, ...exportContext }`
|
|
81
|
+
- `wav` → audio data as number array (or undefined)
|
|
82
|
+
7. Dispatches `CustomEvent("jitterLoadEvent", { detail: { name: "ready", ...exportContext } })`
|
|
83
|
+
8. On error dispatches `{ name: "error", message }`
|
|
84
|
+
|
|
85
|
+
## Scene Graph Format
|
|
86
|
+
|
|
87
|
+
The project configuration lives at
|
|
88
|
+
`window.app.props.observableImmutableConf.lastImmutableConf`.
|
|
89
|
+
|
|
90
|
+
Top-level structure:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"nodes": {},
|
|
95
|
+
"roots": [
|
|
96
|
+
{
|
|
97
|
+
"id": "artboard-id",
|
|
98
|
+
"item": {
|
|
99
|
+
"type": "artboard",
|
|
100
|
+
"width": 1080,
|
|
101
|
+
"height": 1080,
|
|
102
|
+
"duration": 8000,
|
|
103
|
+
"fillColor": "#ffffff",
|
|
104
|
+
"background": true
|
|
105
|
+
},
|
|
106
|
+
"children": [
|
|
107
|
+
{ "id": "...", "item": { "type": "operationsTree" }, "children": [...] },
|
|
108
|
+
{ "id": "...", "item": { "type": "layersTree" }, "children": [...] }
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Layer types
|
|
116
|
+
|
|
117
|
+
| Type | Key properties |
|
|
118
|
+
|------|---------------|
|
|
119
|
+
| `artboard` | `width`, `height`, `duration`, `fillColor`, `background` |
|
|
120
|
+
| `layersTree` | Container for visual layers |
|
|
121
|
+
| `operationsTree` | Container for animation operations |
|
|
122
|
+
| `opGrp` | Named animation step (e.g. "Step 1") |
|
|
123
|
+
| `layerGrp` | Visual group, `clipsContent`, `cornerRadius` |
|
|
124
|
+
| `image` | `url` (CloudFront), `width`, `height`, `cornerRadius` |
|
|
125
|
+
| `video` | `url`, `audioUrl`, `width`, `height` |
|
|
126
|
+
| `svg` | `url` |
|
|
127
|
+
| `gif` | `url` |
|
|
128
|
+
| `text` | `text`, `font`, `fontSize`, `fillColor`, `textAlign` |
|
|
129
|
+
| `rect` | `fillColor`, `cornerRadius`, `strokeColor` |
|
|
130
|
+
| `ellipse` | `fillColor` |
|
|
131
|
+
| `star` | `fillColor`, `points`, `innerRadius` |
|
|
132
|
+
|
|
133
|
+
All layers share: `x`, `y`, `width`, `height`, `angle`, `scale`, `opacity`,
|
|
134
|
+
`shadowEnabled`, `strokeEnabled`.
|
|
135
|
+
|
|
136
|
+
### Animation operations
|
|
137
|
+
|
|
138
|
+
Operations live under `operationsTree > opGrp` nodes. Each operation targets
|
|
139
|
+
a layer by `targetId`:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"type": "move",
|
|
144
|
+
"targetId": "layer-id",
|
|
145
|
+
"startTime": 1000,
|
|
146
|
+
"endTime": 2000,
|
|
147
|
+
"toValue": { "moveX": -530, "moveY": 0 },
|
|
148
|
+
"easing": {
|
|
149
|
+
"name": "smooth:standard:v1",
|
|
150
|
+
"schema": "v1",
|
|
151
|
+
"config": { "intensity": 85 }
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Animation types: `move`, `scale`, `rotate`, `opacity`, `fadeIn/Out`,
|
|
157
|
+
`growIn/Out`, `shrinkIn/Out`, `slideIn/Out`, `spinIn/Out`, `blurIn/Out`,
|
|
158
|
+
`textIn/Out`, `maskRevealIn/Out`, `maskSlideIn/Out`, `maskCenterIn/Out`,
|
|
159
|
+
`playVideo`, `playAudio`.
|
|
160
|
+
|
|
161
|
+
### Asset URLs
|
|
162
|
+
|
|
163
|
+
All media assets are served from CloudFront:
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
https://d154zarmrcpu4a.cloudfront.net/{assetId}.png
|
|
167
|
+
https://d154zarmrcpu4a.cloudfront.net/{assetId}.mp4
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Project data (the conf JSON) is stored at:
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
https://d2q1h0g8a6snwf.cloudfront.net/{encodedFileId}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The `d2q1h0g8a6snwf` URL is for the `snackthis-userdata` bucket.
|
|
177
|
+
Other buckets use `(0,u.T8)(bucket, fileId)` to construct the URL.
|
|
178
|
+
|
|
179
|
+
## Network Requests During Export
|
|
180
|
+
|
|
181
|
+
Requests made when the `/api/renderer/` page loads:
|
|
182
|
+
|
|
183
|
+
**Static assets (cached):**
|
|
184
|
+
- `webpack-runtime-*.js` (11KB)
|
|
185
|
+
- 6 shared chunks (~970KB total)
|
|
186
|
+
- `app.js` (3.0MB) — contains the entire renderer
|
|
187
|
+
- `api-renderer-*.js` (3KB)
|
|
188
|
+
- Page data JSONs from Gatsby
|
|
189
|
+
|
|
190
|
+
**Data fetches:**
|
|
191
|
+
- `backend2.jitter.video/get-user-infos` — user profile
|
|
192
|
+
- `backend2.jitter.video/get-subscription` — plan info
|
|
193
|
+
- `backend2.jitter.video/teams/get-all-subscriptions`
|
|
194
|
+
- `backend2.jitter.video/realtime/get-token` — WebSocket auth token
|
|
195
|
+
|
|
196
|
+
**Project data:** loaded from IndexedDB cache if the user recently visited the
|
|
197
|
+
editor, otherwise fetched from S3/CloudFront.
|
|
198
|
+
|
|
199
|
+
**No rendering API calls** — all rendering is 100% client-side on Canvas 2D.
|
|
200
|
+
|
|
201
|
+
## JS Bundle Structure
|
|
202
|
+
|
|
203
|
+
| File | Size | Purpose |
|
|
204
|
+
|------|------|---------|
|
|
205
|
+
| `app-*.js` | **3.0MB** | Core: renderer, scene builder, all shared modules |
|
|
206
|
+
| `editor-page (file-*.js)` | 960KB | Editor UI (not needed for export) |
|
|
207
|
+
| `22016225-*.js` | 176KB | Shared chunk |
|
|
208
|
+
| `3caaf7ec-*.js` | 168KB | Shared chunk |
|
|
209
|
+
| `42b3359b-*.js` | 316KB | Shared chunk |
|
|
210
|
+
| `4fa16633-*.js` | 124KB | Shared chunk (canvas/WebGL refs) |
|
|
211
|
+
| `146c69ca-*.js` | 62KB | Shared chunk |
|
|
212
|
+
| `f27202df-*.js` | 116KB | Shared chunk |
|
|
213
|
+
| `api-renderer-*.js` | **3KB** | Glue: parse params → create scene → expose `window.jitter` |
|
|
214
|
+
| `webpack-runtime-*.js` | 11KB | Module loader |
|
|
215
|
+
|
|
216
|
+
Total for rendering: ~4.8MB of JavaScript.
|
|
217
|
+
|
|
218
|
+
### Key webpack modules (inside app.js)
|
|
219
|
+
|
|
220
|
+
| Module ID | Export | Purpose |
|
|
221
|
+
|-----------|--------|---------|
|
|
222
|
+
| 65031 | `GM` (as `L`) | Project loader: IndexedDB → S3/CloudFront fallback |
|
|
223
|
+
| 82106 | `h` (as `b`) | Scene creation: conf → scene object with asset store |
|
|
224
|
+
| 89018 | `UH` (as `a`) | Renderer factory: scene → `{ canvas, renderFrame, duration }` |
|
|
225
|
+
| 66868 | `HX` (as `Z`) | Core frame render: `(scene, time, canvasCtx) → void` |
|
|
226
|
+
| 82755 | `eM` | Canvas to PNG string conversion |
|
|
227
|
+
| 44852 | `vS` | Artboard finder in project tree |
|
|
228
|
+
| 94533 | `Mj` | Audio track extraction |
|
|
229
|
+
| 61904 | `ev` | Canvas context creation at given dimensions |
|
|
230
|
+
|
|
231
|
+
## Renderer Internals
|
|
232
|
+
|
|
233
|
+
The renderer factory (module 89018) creates a closure:
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
function createRenderer(scene, width, height, superSampling, options):
|
|
237
|
+
canvas = createCanvasContext(width, height)
|
|
238
|
+
if superSampling > 1:
|
|
239
|
+
create chain of progressively smaller canvases for downscaling
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
canvas: canvas.canvas,
|
|
243
|
+
duration: computeDuration(scene.duration, playbackDirection),
|
|
244
|
+
renderFrame: async (time) => {
|
|
245
|
+
adjustedTime = applyPlaybackDirection(time)
|
|
246
|
+
coreRender(scene, adjustedTime, canvas) // module 66868.HX
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Scene creation (module 82106) takes the raw conf and:
|
|
252
|
+
1. Resolves the camera/viewport for the selected artboards
|
|
253
|
+
2. Optionally applies imgix transforms for super-sampled images
|
|
254
|
+
3. Optionally strips audio or backgrounds
|
|
255
|
+
4. Loads all assets into an `assetStore` (Map of asset ID → loaded asset)
|
|
256
|
+
5. Creates a `prepass` function (prepares frame) and `render` function (draws frame)
|
|
257
|
+
|
|
258
|
+
## Standalone Local Exporter: Feasibility
|
|
259
|
+
|
|
260
|
+
### What would be needed
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
┌──────────────────────────────────────────────────┐
|
|
264
|
+
│ Local index.html │
|
|
265
|
+
│ │
|
|
266
|
+
│ ┌─────────────┐ ┌──────────────────────────┐ │
|
|
267
|
+
│ │ Scene JSON │──▸│ Jitter Renderer Engine │ │
|
|
268
|
+
│ │ (uploaded) │ │ (extracted from app.js) │ │
|
|
269
|
+
│ └─────────────┘ │ scene → canvas → frames │ │
|
|
270
|
+
│ └───────────┬──────────────┘ │
|
|
271
|
+
│ ▼ │
|
|
272
|
+
│ ┌──────────────────────────┐ │
|
|
273
|
+
│ │ Frame capture + encode │ │
|
|
274
|
+
│ │ MediaRecorder/WebCodecs │ │
|
|
275
|
+
│ └───────────┬──────────────┘ │
|
|
276
|
+
│ ▼ │
|
|
277
|
+
│ ┌──────────────────────────┐ │
|
|
278
|
+
│ │ MP4/WebM output file │ │
|
|
279
|
+
│ └──────────────────────────┘ │
|
|
280
|
+
└──────────────────────────────────────────────────┘
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Assessment by component
|
|
284
|
+
|
|
285
|
+
| Component | Difficulty | Notes |
|
|
286
|
+
|-----------|-----------|-------|
|
|
287
|
+
| Bundle extraction | Hard | 3MB minified webpack bundle, ~15 transitive module deps |
|
|
288
|
+
| Project data override | Easy | Replace `GM()` loader with local JSON injection |
|
|
289
|
+
| Asset hosting | Easy | Download CloudFront assets, rewrite URLs or use service worker |
|
|
290
|
+
| Auth bypass | Easy | Mock `/get-user-infos`, `/get-subscription` — rendering is client-side |
|
|
291
|
+
| Video encoding | Medium | WebCodecs API, MediaRecorder, or FFmpeg.wasm |
|
|
292
|
+
| Legal/ToS compliance | **Blocker** | Extracting and redistributing Jitter's code likely violates ToS |
|
|
293
|
+
|
|
294
|
+
### Practical alternatives
|
|
295
|
+
|
|
296
|
+
1. **Use Playwright to drive `/api/renderer/` directly** — this is exactly
|
|
297
|
+
what Jitter's own backend does. Navigate, wait for ready event, call
|
|
298
|
+
`renderFrame()` in a loop, pipe frames to FFmpeg. No extraction needed.
|
|
299
|
+
|
|
300
|
+
2. **Build a custom renderer** using the scene format as a spec. The JSON
|
|
301
|
+
format is well-understood. Libraries like `lottie-web`, `rive`, or a
|
|
302
|
+
custom Canvas 2D renderer could interpret the same format.
|
|
303
|
+
|
|
304
|
+
3. **Use the editor + Playwriter skill** — the existing jitter skill already
|
|
305
|
+
supports: modify scene → generate export URL → navigate → download. This
|
|
306
|
+
works today.
|
|
307
|
+
|
|
308
|
+
4. **Request an API/self-hosted tier from Jitter** — their architecture
|
|
309
|
+
already has an `api/renderer` page designed for programmatic use.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jitter
|
|
3
|
+
description: Control Jitter (jitter.video) for exporting animations, replacing assets, and modifying text programmatically via Playwriter.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Jitter Programmatic Control Skill
|
|
7
|
+
|
|
8
|
+
Control Jitter (jitter.video) for exporting animations, replacing assets, and modifying text.
|
|
9
|
+
|
|
10
|
+
## Setup
|
|
11
|
+
|
|
12
|
+
Load utils before interacting with Jitter:
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
// Load once per page (before navigation or via addInitScript)
|
|
16
|
+
await page.addInitScript({ path: './skills/jitter/dist/jitter-utils.js' })
|
|
17
|
+
|
|
18
|
+
// Navigate to project
|
|
19
|
+
await page.goto('https://jitter.video/file/?id=YOUR_FILE_ID')
|
|
20
|
+
|
|
21
|
+
// Wait for app to be ready
|
|
22
|
+
await page.evaluate(() => jitterUtils.waitForApp())
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## API Reference
|
|
26
|
+
|
|
27
|
+
### Traversal
|
|
28
|
+
|
|
29
|
+
| Function | Description |
|
|
30
|
+
| ----------------------- | ---------------------------------- |
|
|
31
|
+
| `findNodeById(id)` | Find node by ID |
|
|
32
|
+
| `findAllMediaNodes()` | Get all images/SVGs/videos/GIFs |
|
|
33
|
+
| `findAllTextNodes()` | Get all text nodes |
|
|
34
|
+
| `getArtboards()` | Get all artboards with dimensions |
|
|
35
|
+
| `findNodesByType(type)` | Find nodes by layer type |
|
|
36
|
+
| `findNodesByName(name)` | Find nodes by name (partial match) |
|
|
37
|
+
| `flattenTree()` | Get all nodes as flat array |
|
|
38
|
+
|
|
39
|
+
### Actions
|
|
40
|
+
|
|
41
|
+
| Function | Description |
|
|
42
|
+
| ------------------------------ | --------------------------- |
|
|
43
|
+
| `replaceAssetUrl(nodeId, url)` | Replace image/SVG/video URL |
|
|
44
|
+
| `replaceText(nodeId, text)` | Replace text content |
|
|
45
|
+
| `updateNode(nodeId, props)` | Update any node properties |
|
|
46
|
+
| `batchReplace(replacements)` | Batch update multiple nodes |
|
|
47
|
+
| `selectNodes(nodeIds)` | Select nodes by ID |
|
|
48
|
+
| `removeNodes(nodeIds)` | Remove nodes |
|
|
49
|
+
| `undo()` / `redo()` | Undo/redo actions |
|
|
50
|
+
|
|
51
|
+
### Export
|
|
52
|
+
|
|
53
|
+
| Function | Description |
|
|
54
|
+
| ------------------------------------------- | -------------------------------- |
|
|
55
|
+
| `generateExportUrl(opts)` | Generate export URL with options |
|
|
56
|
+
| `generateExportUrlFromCurrentProject(opts)` | Export URL for current project |
|
|
57
|
+
| `parseJitterUrl(url)` | Parse file/node IDs from URL |
|
|
58
|
+
| `getFileMeta()` | Get current file metadata |
|
|
59
|
+
|
|
60
|
+
### Snapshot & Restore
|
|
61
|
+
|
|
62
|
+
| Function | Description |
|
|
63
|
+
| -------------------------------------------------- | ----------------------------------------- |
|
|
64
|
+
| `createSnapshot(nodeIds)` | Save node states |
|
|
65
|
+
| `restoreFromSnapshot(snapshot)` | Restore saved states |
|
|
66
|
+
| `duplicateProject()` | Clone current project |
|
|
67
|
+
| `withTemporaryChanges(nodeIds, changes, callback)` | Apply temp changes, run callback, restore |
|
|
68
|
+
|
|
69
|
+
### Waiting
|
|
70
|
+
|
|
71
|
+
| Function | Description |
|
|
72
|
+
| ------------------------------- | ---------------------- |
|
|
73
|
+
| `waitForApp(timeout?)` | Wait for app to load |
|
|
74
|
+
| `waitForSync(delay?)` | Wait for server sync |
|
|
75
|
+
| `waitForNode(nodeId, timeout?)` | Wait for node to exist |
|
|
76
|
+
| `isAppReady()` | Check if app is ready |
|
|
77
|
+
|
|
78
|
+
## Examples
|
|
79
|
+
|
|
80
|
+
### Replace Assets and Export
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
// Get all media nodes
|
|
84
|
+
const media = await page.evaluate(() => jitterUtils.findAllMediaNodes())
|
|
85
|
+
|
|
86
|
+
// Replace specific assets
|
|
87
|
+
await page.evaluate(() => {
|
|
88
|
+
jitterUtils.batchReplace([
|
|
89
|
+
{ nodeId: 'abc123', data: { url: 'https://example.com/new-image.svg' } },
|
|
90
|
+
{ nodeId: 'def456', data: { url: 'https://example.com/new-photo.jpg' } },
|
|
91
|
+
])
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
// Wait for sync then export
|
|
95
|
+
await page.evaluate(() => jitterUtils.waitForSync())
|
|
96
|
+
const exportUrl = await page.evaluate(() =>
|
|
97
|
+
jitterUtils.generateExportUrlFromCurrentProject({ profile: 'lottie' }),
|
|
98
|
+
)
|
|
99
|
+
await page.goto(exportUrl)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Export with Temporary Changes
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
await page.evaluate(async () => {
|
|
106
|
+
const nodeIds = ['node1', 'node2']
|
|
107
|
+
const changes = {
|
|
108
|
+
node1: { url: 'https://temp-asset.svg' },
|
|
109
|
+
node2: { text: 'Temporary Text' },
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
await jitterUtils.withTemporaryChanges(nodeIds, changes, async () => {
|
|
113
|
+
// Changes applied here, will be restored after
|
|
114
|
+
const url = jitterUtils.generateExportUrlFromCurrentProject()
|
|
115
|
+
// ... navigate to export URL and download
|
|
116
|
+
})
|
|
117
|
+
// Original values automatically restored
|
|
118
|
+
})
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Find and Update Text
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
const textNodes = await page.evaluate(() => jitterUtils.findAllTextNodes())
|
|
125
|
+
// [{ id, name, text, fontSize, fontFamily }, ...]
|
|
126
|
+
|
|
127
|
+
await page.evaluate(() => {
|
|
128
|
+
jitterUtils.replaceText('textNodeId', 'New headline')
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Export Profiles
|
|
133
|
+
|
|
134
|
+
| Profile | Output |
|
|
135
|
+
| ------------ | ------------------------------ |
|
|
136
|
+
| `lottie` | Lottie JSON (vector animation) |
|
|
137
|
+
| `mp4` | H.264 video |
|
|
138
|
+
| `gif` | Animated GIF |
|
|
139
|
+
| `webm` | WebM video |
|
|
140
|
+
| `prores4444` | ProRes 4444 (with alpha) |
|
|
141
|
+
| `pngs` | PNG sequence |
|
|
142
|
+
|
|
143
|
+
## Lottie Export Limitations
|
|
144
|
+
|
|
145
|
+
- **NodeIds are NOT preserved** in exported Lottie - cannot map back to Jitter nodes
|
|
146
|
+
- **Text becomes shapes** - not editable Lottie text layers
|
|
147
|
+
- **Images are embedded** as base64, no external URLs
|
|
148
|
+
- **Videos** export as first frame only
|
|
149
|
+
|
|
150
|
+
**Workaround:** Always modify assets in Jitter before export using `replaceAssetUrl()`.
|
|
151
|
+
|
|
152
|
+
## Tips
|
|
153
|
+
|
|
154
|
+
1. **Wait for sync** after modifications before exporting (1-2 seconds)
|
|
155
|
+
2. **Asset URLs** must be publicly accessible - Jitter fetches server-side
|
|
156
|
+
3. All `*WithUndo` actions can be undone with Ctrl+Z
|
|
157
|
+
4. Node IDs are stable and bookmarkable via `?nodeId=xxx`
|
|
158
|
+
5. Export URLs require being logged in with project access
|