auricui-skill 0.0.0-stage → 0.1.2
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/LICENSE +21 -0
- package/README.md +29 -2
- package/bin/install.mjs +66 -0
- package/package.json +29 -4
- package/skill/SKILL.md +64 -0
- package/skill/agents/openai.yaml +4 -0
- package/skill/assets/examples/ApprovalCard.tsx +8 -0
- package/skill/assets/examples/BasicApp.tsx +38 -0
- package/skill/assets/examples/BriefingCard.tsx +8 -0
- package/skill/assets/examples/ChatControls.tsx +49 -0
- package/skill/assets/examples/ChatPanel.tsx +73 -0
- package/skill/assets/examples/Checkbox.tsx +13 -0
- package/skill/assets/examples/Combobox.tsx +14 -0
- package/skill/assets/examples/Drawer.tsx +10 -0
- package/skill/assets/examples/MemoryCard.tsx +9 -0
- package/skill/assets/examples/MessageList.tsx +8 -0
- package/skill/assets/examples/Theme.tsx +14 -0
- package/skill/assets/examples/ToolCall.tsx +8 -0
- package/skill/assets/examples/Tree.tsx +15 -0
- package/skill/assets/examples/examples.css +11 -0
- package/skill/assets/library/auricui-0.1.0-preview.1.tgz +0 -0
- package/skill/assets/library/auricui-0.1.0-preview.3.tgz +0 -0
- package/skill/assets/library/auricui-0.1.0-preview.4.tgz +0 -0
- package/skill/assets/upstream/LICENSE +21 -0
- package/skill/assets/upstream/apps/desktop/chat/src/App.tsx +1099 -0
- package/skill/assets/upstream/apps/desktop/chat/src/app-bridge.ts +154 -0
- package/skill/assets/upstream/apps/desktop/chat/src/chat.css +1812 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/AddSkill.tsx +223 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/AgentActivityRow.tsx +716 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/AgentIcons.tsx +46 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/AttachmentCard.tsx +34 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/AttachmentPreview.tsx +331 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/BalanceNotice.tsx +22 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/BrandLogo.tsx +35 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/ComposerCard.tsx +182 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/ConversationSessionBar.tsx +292 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/CopyDiagnostics.tsx +24 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/Divider.tsx +47 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/FileChangesList.tsx +119 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/Markdown.tsx +198 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/ModelPopover.tsx +280 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/NoticeCard.tsx +87 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/Popover.tsx +195 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/PreviewFrame.tsx +129 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/ProjectConversation.tsx +852 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/ProjectStarters.tsx +118 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/Tooltip.tsx +191 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/TurnLog.tsx +583 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/TurnQuestionCard.tsx +133 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/dock-pane-bar.ts +14 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/project-version.ts +37 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/MentionMenuPlugin.tsx +372 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/PromptEditor.tsx +476 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/PromptPill.tsx +399 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/PromptReferenceNode.tsx +164 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/index.ts +31 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/mention-menu.ts +206 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/prompt-text.ts +171 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/useStickToBottom.ts +320 -0
- package/skill/assets/upstream/apps/desktop/chat/src/components/useTicker.ts +55 -0
- package/skill/assets/upstream/apps/desktop/chat/src/i18n/index.ts +42 -0
- package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/en-US.ts +408 -0
- package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/es.ts +407 -0
- package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/ja.ts +407 -0
- package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/ko.ts +403 -0
- package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/words.ts +6 -0
- package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/zh-CN.ts +407 -0
- package/skill/assets/upstream/apps/desktop/chat/src/i18n/lookup.ts +12 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-activity-runs.ts +154 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-menu-rows.ts +41 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-refs.ts +105 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-transcript.ts +440 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/asset-lists.ts +75 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/attachment-place.ts +17 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/balance.ts +16 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/chat-layer.ts +10 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/chat-menu.ts +18 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/chat-store.ts +101 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/composer-attachments.ts +189 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/desktop-attachments.ts +178 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/desktop-bridge.ts +291 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/developer.ts +39 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/esc-stop.ts +23 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/file-changes.ts +32 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/live-activity.ts +20 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/local-agent-run.ts +1174 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/local-sessions.ts +25 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/model-calls.ts +87 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/pretty-json.ts +12 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/preview-top.ts +15 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/project-resources.ts +66 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/project-sessions.ts +66 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/project-versions.ts +116 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/ref-pictures.ts +119 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/relative-time.ts +46 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/skill-pages.ts +29 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/step-file.ts +23 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/structural-share.ts +52 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/studio-film.ts +44 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/studio-transfer.ts +40 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/unprompted.ts +27 -0
- package/skill/assets/upstream/apps/desktop/chat/src/lib/upload-limits.ts +53 -0
- package/skill/assets/upstream/apps/desktop/chat/src/mount.tsx +19 -0
- package/skill/assets/upstream/apps/desktop/chat/src/state/local-agent-store.ts +296 -0
- package/skill/assets/upstream/apps/desktop/chat/src/studio-refs.ts +307 -0
- package/skill/assets/upstream/apps/desktop/package.json +51 -0
- package/skill/assets/upstream/apps/desktop/shell/bridge.ts +415 -0
- package/skill/assets/upstream/apps/desktop/shell/index.html +27 -0
- package/skill/assets/upstream/apps/desktop/shell/main.tsx +17 -0
- package/skill/assets/upstream/apps/desktop/shell/shell.css +17 -0
- package/skill/assets/upstream/apps/desktop/shell/vite.config.ts +65 -0
- package/skill/assets/upstream/apps/desktop/src/agent-definitions.mjs +31 -0
- package/skill/assets/upstream/packages/openfilm/LICENSE +21 -0
- package/skill/assets/upstream/packages/openfilm/package.json +88 -0
- package/skill/assets/upstream/packages/openfilm/src/film-doc.d.mts +125 -0
- package/skill/assets/upstream/packages/openfilm/src/film-doc.mjs +986 -0
- package/skill/assets/upstream/packages/openfilm/src/overrides.mjs +73 -0
- package/skill/assets/upstream/packages/openfilm/src/timeline.mjs +1280 -0
- package/skill/assets/upstream/packages/openfilm/studio/server/bridge.js +209 -0
- package/skill/assets/upstream/packages/openfilm/studio/server/film-subtitle.mjs +785 -0
- package/skill/assets/upstream/packages/openfilm/studio/server/ops.mjs +403 -0
- package/skill/assets/upstream/packages/openfilm/studio/server/stage.js +1649 -0
- package/skill/assets/upstream/packages/openfilm/studio/server/track-layout.mjs +43 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/App.tsx +156 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/api.ts +328 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/AudioMeters.tsx +188 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BlockThumbs.tsx +84 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BlockWaveform.tsx +201 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BrandLoadingScreen.tsx +56 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BrandLogo.tsx +25 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Card.tsx +89 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ColorPicker.tsx +204 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ConfirmDialog.tsx +96 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ContextMenu.tsx +422 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/DesktopDialog.tsx +271 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ExamplesGallery.tsx +372 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FilmFullscreenBar.tsx +147 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FilmInspector.tsx +2310 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FilmStageSelect.tsx +3296 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FocusNav.tsx +28 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FontFamilyPicker.tsx +293 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FramePicker.tsx +69 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/InspectorPanel.tsx +25 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Launcher.tsx +38 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/LayersPanel.tsx +277 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/LiveTime.tsx +101 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MediaPool.tsx +1413 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MediaPreview.tsx +188 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MenuSelect.tsx +161 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MgOutline.tsx +24 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/OperationHistory.tsx +184 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PaneDivider.tsx +292 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PasteAttrsDialog.tsx +69 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PlaybackMenu.tsx +110 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Popover.tsx +159 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectCover.tsx +60 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectHistoryControls.tsx +748 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectLayoutMenu.tsx +82 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectMenu.tsx +111 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectSources.tsx +587 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectView.tsx +3222 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectsLibrary.tsx +567 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectsView.tsx +1593 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PropertiesSection.tsx +418 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ResourceInspector.tsx +100 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SelectionToolbar.tsx +157 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SkillsLibrary.tsx +504 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SourcePreview.tsx +464 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SpendAsks.tsx +88 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/StageMaskOverlay.tsx +299 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/StageTransformFrame.tsx +246 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleInspector.module.css +46 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleInspector.tsx +884 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleOverlay.tsx +148 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleRow.tsx +419 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/TabStrip.tsx +188 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Timeline.tsx +4911 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/TimelineMarkers.tsx +329 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Toast.tsx +55 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Tooltip.tsx +193 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/UpdateButton.tsx +104 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ViewerBar.tsx +98 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/WhatsNew.tsx +147 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/dock-pane-bar.ts +16 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/export/ExportCenter.tsx +1502 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/export/ExportTray.tsx +284 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/film-stage-hit.ts +18 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/inspector-fields.tsx +863 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/inspector-look.tsx +1357 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/player-controls/controls-bar.tsx +397 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/player-controls/transport.tsx +294 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/replace-drop.ts +20 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/AgentsSection.tsx +613 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/CustomServices.tsx +104 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/DiagnosticsGroup.tsx +202 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ModelsSection.tsx +179 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ProviderMark.tsx +24 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ProvidersSection.tsx +177 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/SettingsModal.tsx +511 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/SettingsSelect.tsx +84 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ShortcutsSection.tsx +291 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/StorageGroup.tsx +119 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/theme.ts +47 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ui.tsx +139 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/use-settings.ts +10 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/stage-menu.tsx +283 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/timeline-head-extras.tsx +91 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/typing-target.ts +45 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/use-editor-tools.tsx +408 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/use-page-changes.ts +48 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/use-project-history.ts +113 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/useBlockDrag.ts +639 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/Preview.tsx +426 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/player.ts +558 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/preview-frames.ts +36 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/steps.ts +36 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/undo.ts +156 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/use-film.ts +212 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/use-preview-renders.ts +89 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/globals.css +559 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/en.ts +1901 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/es.ts +1900 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/index.ts +130 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/ja.ts +1900 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/ko.ts +1896 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/words.ts +6 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/zh-CN.ts +1901 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/agent-row.ts +21 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/asset-timeline.ts +469 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/audio-levels.ts +60 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/batch-map.ts +28 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/browser.ts +10 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/canvas-fit.ts +116 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/chat-marks.ts +114 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-attrs.ts +102 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-fade.ts +70 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-look.ts +520 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-mask.ts +536 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-replace.ts +60 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/component-props.ts +128 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/context-length.ts +12 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/desktop-build.ts +44 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/diagnostics.ts +68 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/double-press.ts +22 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/dropped-overrides.ts +139 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/export-jobs.ts +191 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/export-spec.ts +261 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/field-input.ts +155 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-clip-edits.ts +82 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-frame.ts +134 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-overrides.ts +107 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-shape.ts +172 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film.ts +80 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/font-menu.ts +236 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/font-styles.ts +129 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/freeze-frame.ts +49 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/host.ts +438 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/inspect-scrub.ts +26 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/keymap-store.ts +74 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/keymap.ts +529 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/layers-tree.ts +133 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/look.ts +83 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/loudness.ts +58 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/markers.ts +152 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-bar.ts +58 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-folders.ts +45 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-place.ts +102 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-queue.ts +107 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-selection.ts +64 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/menu-position.ts +77 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/mg-transform.ts +111 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/mixed.ts +3 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/page-changes.ts +45 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/picture-files.ts +19 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/preview-prefs.ts +46 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/preview-renders.ts +71 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-delete.ts +20 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-folders.ts +144 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-history.ts +188 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-sources.ts +283 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/projects-page.ts +40 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/provider-marks.ts +35 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/providers.ts +163 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/resource-drag.ts +131 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/retry-image.ts +17 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/saved-insert.ts +40 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/saved.ts +125 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/selection-toolbar.ts +158 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/shortcut-hint.ts +21 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/similar-layers.ts +46 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/solo.ts +19 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-clip.ts +60 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-crop.ts +232 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-gesture.ts +277 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-layers.ts +71 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-mask.ts +176 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-measure.ts +53 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-types.ts +155 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/studio-refs.ts +248 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/studio-version.ts +41 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/subtitle-cues.ts +238 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/subtitles.ts +263 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/tab-menu.ts +6 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/template-controls.ts +131 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/theme-changes.ts +31 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-cache.ts +63 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-cell.ts +8 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-frame.ts +76 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-pick.ts +42 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timecode.ts +161 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-clipboard.ts +279 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-drag.ts +589 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-edit.ts +1138 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-keys.ts +63 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-layout.ts +1038 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-nav.ts +160 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-prefs.ts +73 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-split.ts +40 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-view.ts +105 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/title.ts +39 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/track-heights.ts +55 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/track-lock.ts +27 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/transitions.ts +459 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/type-metrics.ts +83 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-film-subtitles.ts +111 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-fonts.ts +181 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-loaded-thumbs.ts +91 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-subtitle-edits.ts +134 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-subtitle-font.ts +51 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-subtitle-style.ts +68 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/waveform-columns.ts +48 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/web-update.ts +41 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/whats-new.ts +401 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/workspace-resources.ts +373 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/src/main.tsx +10 -0
- package/skill/assets/upstream/packages/openfilm/studio/ui/vite.config.ts +12 -0
- package/skill/assets/upstream/packages/shared/package.json +45 -0
- package/skill/assets/upstream/packages/shared/src/agent-activity.ts +263 -0
- package/skill/assets/upstream/packages/shared/src/contract.ts +285 -0
- package/skill/assets/upstream/packages/shared/src/index.ts +17 -0
- package/skill/assets/upstream/packages/shared/src/markdown-blocks.ts +252 -0
- package/skill/assets/upstream/packages/shared/src/modality.ts +4 -0
- package/skill/assets/upstream/packages/shared/src/prompt-reference.ts +113 -0
- package/skill/assets/upstream/packages/shared/src/title.ts +76 -0
- package/skill/assets/upstream/packages/shared/src/turn.ts +68 -0
- package/skill/assets/upstream/packages/shared/src/video.ts +26 -0
- package/skill/references/agent-components.md +33 -0
- package/skill/references/api-index.json +2693 -0
- package/skill/references/chat-components.md +65 -0
- package/skill/references/components.md +23 -0
- package/skill/references/core-components.md +44 -0
- package/skill/references/dependencies.md +22 -0
- package/skill/references/esm-package.md +48 -0
- package/skill/references/integration.md +43 -0
- package/skill/references/library-manifest.json +12 -0
- package/skill/references/source-manifest.json +325 -0
- package/skill/references/studio-components.md +24 -0
- package/skill/references/theme-motion.md +49 -0
- package/skill/references/troubleshooting.md +27 -0
- package/skill/references/verification.md +13 -0
- package/skill/scripts/check_dependencies.py +109 -0
- package/skill/scripts/inspect_api.py +60 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the editor's keys act on, worked out from the timeline as it is drawn: the cuts ↑ / ↓ jump between, the clips
|
|
3
|
+
* ⌘B and ⇧⌘B split, and a selection moved a frame with ⌥ ← / →. Pure: the keys call these, the edits are written by
|
|
4
|
+
* the editor (components/ProjectView).
|
|
5
|
+
*/
|
|
6
|
+
import { MIN_BLOCK_MS } from './timeline-drag.ts';
|
|
7
|
+
import { NO_SWITCHES, TOUCH_MS, mainTrackOf, planMove, type EditModel, type EditPlan, type Switches } from './timeline-edit.ts';
|
|
8
|
+
import { stepFrames } from './timecode.ts';
|
|
9
|
+
import type { TimelineBlock, TimelineTrack } from './timeline-layout';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Every clip edge on the tracks that can be cut (not locked) and are seen (not hidden), in order, once each: what
|
|
13
|
+
* ↑ / ↓ go to. Clips not on film.html yet (a drop being written) are left out.
|
|
14
|
+
*/
|
|
15
|
+
export function cutPoints(tracks: readonly TimelineTrack[]): number[] {
|
|
16
|
+
const out = new Set<number>();
|
|
17
|
+
for (const tr of tracks) {
|
|
18
|
+
if (tr.locked || tr.hidden) continue;
|
|
19
|
+
for (const b of tr.blocks) {
|
|
20
|
+
if (!b.loc) continue;
|
|
21
|
+
out.add(Math.round(b.startMs));
|
|
22
|
+
out.add(Math.round(b.endMs));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return [...out].sort((a, b) => a - b);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The next cut after `nowMs` (`dir` 1), or the one before it (-1); null when there is none that way. */
|
|
29
|
+
export function nextCut(points: readonly number[], nowMs: number, dir: 1 | -1): number | null {
|
|
30
|
+
/* within a millisecond is where the playhead already is */
|
|
31
|
+
if (dir > 0) return points.find((p) => p > nowMs + 1) ?? null;
|
|
32
|
+
for (let i = points.length - 1; i >= 0; i--) if (points[i]! < nowMs - 1) return points[i]!;
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Whether a cut at `atMs` falls inside a clip, far enough from both its ends (the split button's own rule). */
|
|
37
|
+
export function splitsAt(b: Pick<TimelineBlock, 'startMs' | 'endMs'>, atMs: number): boolean {
|
|
38
|
+
return atMs > b.startMs + MIN_BLOCK_MS && atMs < b.endMs - MIN_BLOCK_MS;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const lockedRows = (tracks: readonly TimelineTrack[]) => new Set(tracks.filter((tr) => tr.locked).flatMap((tr) => tr.blocks.map((b) => b.id)));
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* What ⌘B splits at the playhead: the selected clips it is inside; with nothing selected, the clip it is inside on the
|
|
45
|
+
* main track (the lowest picture track); else on the targeted track (`targetLane`), else on the topmost
|
|
46
|
+
* track that is seen and has one. Never a clip on a locked track. The clips linked to them are the caller's to add.
|
|
47
|
+
*/
|
|
48
|
+
export function splitTargets(
|
|
49
|
+
tracks: readonly TimelineTrack[],
|
|
50
|
+
selectedIds: readonly string[],
|
|
51
|
+
atMs: number,
|
|
52
|
+
targetLane: string | null,
|
|
53
|
+
): TimelineBlock[] {
|
|
54
|
+
const locked = lockedRows(tracks);
|
|
55
|
+
const can = (b: TimelineBlock) => Boolean(b.loc && b.clipId) && !locked.has(b.id) && splitsAt(b, atMs);
|
|
56
|
+
if (selectedIds.length) return tracks.flatMap((tr) => tr.blocks).filter((b) => selectedIds.includes(b.id) && can(b));
|
|
57
|
+
const pictures = tracks.filter((tr) => tr.docIndex != null && tr.role !== 'audio');
|
|
58
|
+
const mainIndex = pictures.length ? Math.max(...pictures.map((tr) => tr.docIndex!)) : null;
|
|
59
|
+
const main = tracks.filter((tr) => tr.docIndex === mainIndex && !tr.hidden).flatMap((tr) => tr.blocks).find(can);
|
|
60
|
+
if (main) return [main];
|
|
61
|
+
const target = targetLane ? tracks.find((tr) => tr.lane === targetLane) : undefined;
|
|
62
|
+
if (target) {
|
|
63
|
+
const hit = target.blocks.find(can);
|
|
64
|
+
return hit ? [hit] : [];
|
|
65
|
+
}
|
|
66
|
+
for (const tr of tracks) {
|
|
67
|
+
if (tr.hidden) continue;
|
|
68
|
+
const hit = tr.blocks.find(can);
|
|
69
|
+
if (hit) return [hit];
|
|
70
|
+
}
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* What [ / ] select: every clip with a part before the playhead (`dir` -1) or after it
|
|
76
|
+
* (`dir` 1), on every track not locked — what to move when the film before or after a point moves along.
|
|
77
|
+
*/
|
|
78
|
+
export function sideTargets(tracks: readonly TimelineTrack[], atMs: number, dir: -1 | 1): TimelineBlock[] {
|
|
79
|
+
return tracks.filter((tr) => !tr.locked).flatMap((tr) => tr.blocks)
|
|
80
|
+
.filter((b) => Boolean(b.loc) && (dir > 0 ? b.endMs > atMs + 1 : b.startMs < atMs - 1));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** What ⇧⌘B splits: every clip the playhead is inside, on every track not locked. */
|
|
84
|
+
export function splitAllTargets(tracks: readonly TimelineTrack[], atMs: number): TimelineBlock[] {
|
|
85
|
+
return tracks.filter((tr) => !tr.locked).flatMap((tr) => tr.blocks).filter((b) => Boolean(b.loc && b.clipId) && splitsAt(b, atMs));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Clips (by id, the first leading) moved `frames` frames along their tracks, landing on the frame grid; a clip in the
|
|
90
|
+
* way stops them against it, uncut. Null when nothing can move (a locked track, the film's start, a clip right there,
|
|
91
|
+
* the main track with the magnet, which stays closed up).
|
|
92
|
+
*/
|
|
93
|
+
export function planNudge(model: EditModel, ids: readonly string[], frames: number, sw: Switches = NO_SWITCHES): EditPlan | null {
|
|
94
|
+
const lead = model.flatMap((t) => t.clips).find((c) => c.id === ids[0]);
|
|
95
|
+
if (!lead || !frames) return null;
|
|
96
|
+
const main = mainTrackOf(model);
|
|
97
|
+
if (sw.magnet && model.find((t) => t.index === main)?.clips.some((c) => ids.includes(c.id))) return null;
|
|
98
|
+
let deltaMs = stepFrames(lead.startMs, frames) - lead.startMs;
|
|
99
|
+
/* the room before the nearest clip they would run into, on each of their tracks */
|
|
100
|
+
const moving = new Set(ids);
|
|
101
|
+
for (const t of model) {
|
|
102
|
+
const others = t.clips.filter((c) => !moving.has(c.id));
|
|
103
|
+
for (const c of t.clips.filter((x) => moving.has(x.id))) {
|
|
104
|
+
for (const o of others) {
|
|
105
|
+
if (deltaMs > 0 && o.startMs >= c.endMs - TOUCH_MS) deltaMs = Math.min(deltaMs, o.startMs - c.endMs);
|
|
106
|
+
if (deltaMs < 0 && o.endMs <= c.startMs + TOUCH_MS) deltaMs = Math.max(deltaMs, o.endMs - c.startMs);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (Math.abs(deltaMs) <= TOUCH_MS) return null;
|
|
111
|
+
const plan = planMove(model, { ids, deltaMs, pointerMs: lead.startMs + deltaMs, mode: 'place', ...sw });
|
|
112
|
+
return plan?.ops.length ? plan : null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** A track's name as Studio keeps it (`.film/settings.json`): the clips it had when it was named find it again. */
|
|
116
|
+
export type SavedTrackName = { name: string; index: number; clips: string[] };
|
|
117
|
+
|
|
118
|
+
export type ClipsOf = readonly { clips: readonly { id: string }[] }[];
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Which track each thing kept about a track (a name, a height) is on now: the track holding the most of the clips it
|
|
122
|
+
* had then, else its place (see trackNamesOf).
|
|
123
|
+
*/
|
|
124
|
+
export function placeSaved<T extends { index: number; clips: readonly string[] }>(saved: readonly T[], tracks: ClipsOf): Map<T, number> {
|
|
125
|
+
const out = new Map<T, number>();
|
|
126
|
+
const taken = new Set<number>();
|
|
127
|
+
const late: T[] = [];
|
|
128
|
+
for (const entry of saved) {
|
|
129
|
+
const had = new Set(entry.clips);
|
|
130
|
+
let best = -1;
|
|
131
|
+
let most = 0;
|
|
132
|
+
tracks.forEach((tr, i) => {
|
|
133
|
+
const n = tr.clips.filter((c) => had.has(c.id)).length;
|
|
134
|
+
if (n > most && !taken.has(i)) { most = n; best = i; }
|
|
135
|
+
});
|
|
136
|
+
if (best >= 0) { out.set(entry, best); taken.add(best); } else late.push(entry);
|
|
137
|
+
}
|
|
138
|
+
for (const entry of late) {
|
|
139
|
+
if (entry.index < tracks.length && !taken.has(entry.index)) { out.set(entry, entry.index); taken.add(entry.index); }
|
|
140
|
+
}
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The names kept for tracks, by film.html track index now. A track is found by the clips it had when named (tracks
|
|
146
|
+
* move, and open and close above it, so its place changes; film.html gives a track no id of its own), the one holding
|
|
147
|
+
* the most of them; a track named while empty, or whose clips are all gone, by its place, when no other name took it.
|
|
148
|
+
*/
|
|
149
|
+
export function trackNamesOf(saved: readonly SavedTrackName[], tracks: ClipsOf): Map<number, string> {
|
|
150
|
+
return new Map([...placeSaved(saved, tracks)].map(([entry, i]) => [i, entry.name]));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** The names to keep once track `index` is named `name` (an empty name takes its name away); names found nowhere go. */
|
|
154
|
+
export function namedTrack(saved: readonly SavedTrackName[], tracks: ClipsOf, index: number, name: string): SavedTrackName[] {
|
|
155
|
+
const placed = placeSaved(saved, tracks);
|
|
156
|
+
const kept = saved.filter((entry) => placed.has(entry) && placed.get(entry) !== index)
|
|
157
|
+
.map((entry) => ({ ...entry, index: placed.get(entry)!, clips: (tracks[placed.get(entry)!]?.clips ?? []).map((c) => c.id) }));
|
|
158
|
+
const clean = name.trim().slice(0, 40);
|
|
159
|
+
return clean ? [...kept, { name: clean, index, clips: (tracks[index]?.clips ?? []).map((c) => c.id) }] : kept;
|
|
160
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The timeline's switches, kept on this machine across projects, in the toolbar's order, on by default but the preview
|
|
3
|
+
* axis:
|
|
4
|
+
* · `magnet` (主轨磁吸): the main track (the lowest picture track) stays closed up — a clip put on it goes in between,
|
|
5
|
+
* one deleted or taken off it closes up after it, a trim or a new speed there moves what follows. Off, the main
|
|
6
|
+
* track is like the others (lib/timeline-edit);
|
|
7
|
+
* · `snap` (自动吸附): drags line up with edges and the playhead; off means "it lands exactly where I let go";
|
|
8
|
+
* · `linkage` (联动): titles, overlays and sounds riding on a main-track clip move with it and go with it;
|
|
9
|
+
* · `previewAxis` (预览轴): the picture follows the pointer over the timeline, the playhead staying where it is. Off
|
|
10
|
+
* by default: the picture stays at the playhead until it is turned on.
|
|
11
|
+
*
|
|
12
|
+
* Clips sharing a `data-link` (a video and its detached sound) are always selected and edited together; ⌥-click picks
|
|
13
|
+
* one alone. The inspector reads the switches too (a slower speed pushes the next clip only with the magnet on), so a
|
|
14
|
+
* change is told to everyone listening.
|
|
15
|
+
*/
|
|
16
|
+
import { useSyncExternalStore } from 'react';
|
|
17
|
+
|
|
18
|
+
import type { Switches } from './timeline-edit.ts';
|
|
19
|
+
|
|
20
|
+
export type TimelinePrefs = { snap: boolean; magnet: boolean; linkage: boolean; previewAxis: boolean };
|
|
21
|
+
type Pref = keyof TimelinePrefs;
|
|
22
|
+
|
|
23
|
+
const DEFAULTS: TimelinePrefs = { snap: true, magnet: true, linkage: true, previewAxis: false };
|
|
24
|
+
const KEY: Record<Pref, string> = {
|
|
25
|
+
snap: 'openfilm.timeline.snap',
|
|
26
|
+
/* new keys: the main track came back on 10-19 with its magnet and linkage, so choices made for the switches before
|
|
27
|
+
do not carry over */
|
|
28
|
+
magnet: 'openfilm.timeline.mainTrackMagnet',
|
|
29
|
+
linkage: 'openfilm.timeline.mainTrackLinkage',
|
|
30
|
+
previewAxis: 'openfilm.timeline.previewAxis',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** Without localStorage (private window), the choices last this session. */
|
|
34
|
+
const memory: Partial<TimelinePrefs> = {};
|
|
35
|
+
const listeners = new Set<() => void>();
|
|
36
|
+
let current: TimelinePrefs | null = null;
|
|
37
|
+
|
|
38
|
+
function read(pref: Pref): boolean {
|
|
39
|
+
try {
|
|
40
|
+
const raw = localStorage.getItem(KEY[pref]);
|
|
41
|
+
if (raw != null) return raw !== '0';
|
|
42
|
+
} catch { /* no localStorage: this session's choice */ }
|
|
43
|
+
return memory[pref] ?? DEFAULTS[pref];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function readTimelinePrefs(): TimelinePrefs {
|
|
47
|
+
current ??= { snap: read('snap'), magnet: read('magnet'), linkage: read('linkage'), previewAxis: read('previewAxis') };
|
|
48
|
+
return current;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** What an edit is planned by (lib/timeline-edit Switches), from the switches. */
|
|
52
|
+
export function switchesOf(prefs: Pick<TimelinePrefs, 'magnet' | 'linkage'>): Switches {
|
|
53
|
+
return { magnet: prefs.magnet, linkage: prefs.linkage };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function writeTimelinePref(pref: Pref, on: boolean): void {
|
|
57
|
+
memory[pref] = on;
|
|
58
|
+
try {
|
|
59
|
+
localStorage.setItem(KEY[pref], on ? '1' : '0');
|
|
60
|
+
} catch { /* not stored: `memory` has it */ }
|
|
61
|
+
current = { ...readTimelinePrefs(), [pref]: on };
|
|
62
|
+
for (const fn of listeners) fn();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function subscribe(fn: () => void): () => void {
|
|
66
|
+
listeners.add(fn);
|
|
67
|
+
return () => { listeners.delete(fn); };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The switches, kept up to date wherever one is changed. */
|
|
71
|
+
export function useTimelinePrefs(): TimelinePrefs {
|
|
72
|
+
return useSyncExternalStore(subscribe, readTimelinePrefs, () => DEFAULTS);
|
|
73
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a split cuts a clip, as film.html writes its halves: the left one's trim end, the right one's trim and place.
|
|
3
|
+
*
|
|
4
|
+
* film.html writes moments to the millisecond (ops.mjs rounds them), and a clip's length on the film is its trim over
|
|
5
|
+
* its speed. So the cut is taken on a whole millisecond of the source, and the right half starts where that puts the
|
|
6
|
+
* left one's end: worked out the other way round (the film moment rounded, the trim from it), a clip at speed 0.5
|
|
7
|
+
* ends a millisecond past where the rest starts, and the two overlap.
|
|
8
|
+
*/
|
|
9
|
+
export type SplitHalves = {
|
|
10
|
+
left: { end: number };
|
|
11
|
+
/** `end` only when the clip writes one: without, the rest plays to the end of its file */
|
|
12
|
+
right: { start: number; end?: number; at: number };
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function splitHalves(
|
|
16
|
+
block: { startMs: number; endMs: number; speed?: number; anchor?: { trimFrom?: number; parentStartMs: number } },
|
|
17
|
+
atMs: number,
|
|
18
|
+
/** the clip's own trim end in film.html (source seconds), when it writes one */
|
|
19
|
+
sourceEnd?: number,
|
|
20
|
+
): SplitHalves | null {
|
|
21
|
+
const k = block.speed && block.speed > 0 ? block.speed : 1;
|
|
22
|
+
const startMs = Math.round(block.startMs);
|
|
23
|
+
const fromMs = Math.round((block.anchor?.trimFrom ?? 0) * 1000);
|
|
24
|
+
/* source ms after the clip's in point: to the cut, and to its end */
|
|
25
|
+
const cut = Math.round((atMs - startMs) * k);
|
|
26
|
+
const ends = sourceEnd != null && Number.isFinite(sourceEnd);
|
|
27
|
+
const total = ends ? Math.round(sourceEnd * 1000) - fromMs : Math.round((block.endMs - startMs) * k);
|
|
28
|
+
if (!(cut > 0 && cut < total)) return null;
|
|
29
|
+
const parentMs = block.anchor?.parentStartMs ?? 0;
|
|
30
|
+
const end = (fromMs + cut) / 1000;
|
|
31
|
+
/* the first half's length on the film, worked out as the timeline does from film.html (clipSpan's (to − from) /
|
|
32
|
+
speed, to the ms): the rest starts there, not at its own rounding of the cut (450.5 ms is 450 one way, 451 the other) */
|
|
33
|
+
const leftMs = Math.round(((end - fromMs / 1000) / k) * 1000);
|
|
34
|
+
return {
|
|
35
|
+
left: { end },
|
|
36
|
+
/* no end written when the clip has none: worked out from its length on the film (to the ms), it could land past
|
|
37
|
+
the file's own length (10.010667 s → 10.011) and the film would refuse to play */
|
|
38
|
+
right: { start: end, ...(ends ? { end: (fromMs + total) / 1000 } : {}), at: (startMs - parentMs + leftMs) / 1000 },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the timeline draws of a big film, and how a zoom gesture moves it. Every clip drawn is laid out, layerized and
|
|
3
|
+
* hit-tested again on each zoom step and scroll, and on a film of hundreds of clips most of them were out of view. So
|
|
4
|
+
* only the rows near the view get their clips (rowsNear), and while a wheel or pinch zoom goes on, what is drawn is
|
|
5
|
+
* scaled by transforms the compositor applies (ZoomPreview), and laid out at the new density once it stops.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Rows are drawn this many views above and below the view: a quick scroll does not outrun them. */
|
|
9
|
+
export const ROWS_PAD_VIEWS = 0.5;
|
|
10
|
+
/** The rows drawn follow the vertical scroll in steps of this many views, not every pixel (each step is a render). */
|
|
11
|
+
export const ROWS_STEP_VIEWS = 0.5;
|
|
12
|
+
|
|
13
|
+
function clamp(n: number, lo: number, hi: number): number {
|
|
14
|
+
return n < lo ? lo : n > hi ? hi : n;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Which step of the vertical scroll the view is at (see ROWS_STEP_VIEWS). */
|
|
18
|
+
export function rowBand(scrollTop: number, viewH: number): number {
|
|
19
|
+
if (!(viewH > 0)) return 0;
|
|
20
|
+
return Math.max(0, Math.floor(scrollTop / (viewH * ROWS_STEP_VIEWS)));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The rows drawn at a step of the vertical scroll: the first and last index, inclusive (`last` < `first` when none).
|
|
25
|
+
* `heights` are the rows' own, top to bottom; each has `gap` above it, the first `padTop` below the content's top.
|
|
26
|
+
* Before the view has a height every row is drawn.
|
|
27
|
+
*/
|
|
28
|
+
export function rowsNear(
|
|
29
|
+
heights: readonly number[],
|
|
30
|
+
at: { gap: number; padTop: number; band: number; viewH: number },
|
|
31
|
+
): { first: number; last: number } {
|
|
32
|
+
if (!(at.viewH > 0)) return { first: 0, last: heights.length - 1 };
|
|
33
|
+
const step = at.viewH * ROWS_STEP_VIEWS;
|
|
34
|
+
const pad = at.viewH * ROWS_PAD_VIEWS;
|
|
35
|
+
/* every scroll inside the step is covered, with `pad` to spare either side */
|
|
36
|
+
const from = at.band * step - pad;
|
|
37
|
+
const to = (at.band + 1) * step + at.viewH + pad;
|
|
38
|
+
let first = -1;
|
|
39
|
+
let last = -2;
|
|
40
|
+
let bottom = at.padTop;
|
|
41
|
+
for (let i = 0; i < heights.length; i += 1) {
|
|
42
|
+
const top = bottom + at.gap;
|
|
43
|
+
bottom = top + heights[i]!;
|
|
44
|
+
if (bottom <= from) continue;
|
|
45
|
+
if (top >= to) break;
|
|
46
|
+
if (first < 0) first = i;
|
|
47
|
+
last = i;
|
|
48
|
+
}
|
|
49
|
+
return first < 0 ? { first: 0, last: -1 } : { first, last };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A zoom gesture under way, against what is laid out now: what is laid out at x (px from the content's left edge) is
|
|
54
|
+
* drawn at `offset + scale × x` (px from the view's left edge). Laid out again, the density is `scale` times what it
|
|
55
|
+
* is and the scroll is `-offset`.
|
|
56
|
+
*/
|
|
57
|
+
export interface ZoomPreview {
|
|
58
|
+
offset: number;
|
|
59
|
+
scale: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** No gesture: what is laid out, drawn where it is. */
|
|
63
|
+
export function zoomPreviewAt(scrollLeft: number): ZoomPreview {
|
|
64
|
+
return { offset: -scrollLeft, scale: 1 };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* One step of a gesture: `factor` more density around the view x `at`, which stays where it is. The density stays
|
|
69
|
+
* within `minScale`..`maxScale` and the view within the canvas (`maxScrollAt`: the furthest scroll at a scale), as a
|
|
70
|
+
* zoom laid out at each step would: near an end, the point slides instead of the view leaving the canvas.
|
|
71
|
+
*/
|
|
72
|
+
export function zoomPreviewStep(
|
|
73
|
+
p: ZoomPreview,
|
|
74
|
+
factor: number,
|
|
75
|
+
at: number,
|
|
76
|
+
limits: { minScale: number; maxScale: number; maxScrollAt: (scale: number) => number },
|
|
77
|
+
): ZoomPreview {
|
|
78
|
+
const scale = clamp(p.scale * factor, limits.minScale, Math.max(limits.minScale, limits.maxScale));
|
|
79
|
+
const offset = at + (scale / p.scale) * (p.offset - at);
|
|
80
|
+
return { offset: clamp(offset, -Math.max(0, limits.maxScrollAt(scale)), 0), scale };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The same gesture against the density laid out next (`toPx` where it was `fromPx`). */
|
|
84
|
+
export function rebaseZoomPreview(p: ZoomPreview, fromPx: number, toPx: number): ZoomPreview {
|
|
85
|
+
return toPx > 0 && fromPx > 0 ? { offset: p.offset, scale: (p.scale * fromPx) / toPx } : p;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Whether a gesture draws things where they are laid out (at this scroll): nothing to transform. */
|
|
89
|
+
export function zoomPreviewIsRest(p: ZoomPreview, scrollLeft: number): boolean {
|
|
90
|
+
return Math.abs(p.scale - 1) < 1e-6 && Math.abs(p.offset + scrollLeft) < 0.01;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The transform that draws a layer as the gesture has it. `content`: laid out in content px, moved by the scroll
|
|
95
|
+
* (the clips, the ruler, the subtitle and marker rows). `view`: drawn in view px with the scroll taken off already
|
|
96
|
+
* (the playhead, the range), its left edge `bleed` px left of the view's. Empty at rest.
|
|
97
|
+
*/
|
|
98
|
+
export function zoomLayerTransform(p: ZoomPreview, scrollLeft: number, kind: 'content' | 'view', bleed = 0): string {
|
|
99
|
+
if (zoomPreviewIsRest(p, scrollLeft)) return '';
|
|
100
|
+
const x = kind === 'content' ? p.offset + scrollLeft : p.offset + p.scale * (scrollLeft - bleed) + bleed;
|
|
101
|
+
return `translate3d(${round3(x)}px,0,0) scaleX(${round6(p.scale)})`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const round3 = (n: number) => Math.round(n * 1000) / 1000;
|
|
105
|
+
const round6 = (n: number) => Math.round(n * 1e6) / 1e6;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How long a project name may be. It must fit one line on cards and in the top bar, and characters alone do not
|
|
3
|
+
* measure that: a CJK glyph is about twice as wide as a Latin one. So the budget is display width — full-width
|
|
4
|
+
* glyphs cost 2, everything else 1 — which gives "30 CJK or 60 Latin characters" from one rule.
|
|
5
|
+
*/
|
|
6
|
+
export const TITLE_MAX_WIDTH = 60;
|
|
7
|
+
|
|
8
|
+
const FULL_WIDTH_RANGES: readonly [number, number][] = [
|
|
9
|
+
[0x1100, 0x115f], // Hangul Jamo
|
|
10
|
+
[0x2e80, 0x303e], // CJK radicals, Kangxi, CJK symbols & punctuation
|
|
11
|
+
[0x3041, 0x33ff], // Hiragana, Katakana, Hangul compat, CJK compat
|
|
12
|
+
[0x3400, 0x4dbf], // CJK ext A
|
|
13
|
+
[0x4e00, 0x9fff], // CJK unified
|
|
14
|
+
[0xa000, 0xa4cf], // Yi
|
|
15
|
+
[0xac00, 0xd7a3], // Hangul syllables
|
|
16
|
+
[0xf900, 0xfaff], // CJK compat ideographs
|
|
17
|
+
[0xfe30, 0xfe6f], // CJK compat forms
|
|
18
|
+
[0xff00, 0xff60], // Full-width forms
|
|
19
|
+
[0xffe0, 0xffe6],
|
|
20
|
+
[0x20000, 0x2fffd], // CJK ext B+
|
|
21
|
+
[0x30000, 0x3fffd],
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
function charWidth(codePoint: number): number {
|
|
25
|
+
return FULL_WIDTH_RANGES.some(([lo, hi]) => codePoint >= lo && codePoint <= hi) ? 2 : 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Cut to the width budget, without an ellipsis (for typing: no "…" after every keystroke). */
|
|
29
|
+
export function limitTitleWidth(raw: string, maxWidth = TITLE_MAX_WIDTH): string {
|
|
30
|
+
let width = 0;
|
|
31
|
+
let out = '';
|
|
32
|
+
for (const ch of raw) {
|
|
33
|
+
const w = charWidth(ch.codePointAt(0)!);
|
|
34
|
+
if (width + w > maxWidth) break;
|
|
35
|
+
width += w;
|
|
36
|
+
out += ch;
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Track heights: how tall each track is drawn on the timeline, set by dragging the bottom edge of its head or picked
|
|
3
|
+
* small / medium / large from its menu. Studio's own, per project (`.film/settings.json` `trackHeights`), each with
|
|
4
|
+
* the clips its track had then, so it stays with its track when tracks move (see lib/timeline-nav placeSaved).
|
|
5
|
+
*/
|
|
6
|
+
import { placeSaved, type ClipsOf } from './timeline-nav.ts';
|
|
7
|
+
import type { TimelineLaneKind } from './timeline-layout';
|
|
8
|
+
|
|
9
|
+
export type SavedTrackHeight = { height: number; index: number; clips: string[] };
|
|
10
|
+
|
|
11
|
+
/** The heights a track can have, px. */
|
|
12
|
+
export const TRACK_MIN_H = 28;
|
|
13
|
+
export const TRACK_MAX_H = 160;
|
|
14
|
+
|
|
15
|
+
/** Small, medium (the timeline's own) and large, for a picture track and a sound track. */
|
|
16
|
+
export const TRACK_SIZES = {
|
|
17
|
+
small: { visual: 36, audio: 30 },
|
|
18
|
+
medium: { visual: 56, audio: 44 },
|
|
19
|
+
large: { visual: 96, audio: 80 },
|
|
20
|
+
} as const;
|
|
21
|
+
export type TrackSize = keyof typeof TRACK_SIZES;
|
|
22
|
+
|
|
23
|
+
/** The main track's own height: taller than the others. */
|
|
24
|
+
export const MAIN_TRACK_H = 68;
|
|
25
|
+
|
|
26
|
+
/** A track's own height (none set by the person): the main track's, else medium for its kind. */
|
|
27
|
+
export function ownTrackHeight(track: { kind: TimelineLaneKind; main?: boolean }): number {
|
|
28
|
+
return track.main ? MAIN_TRACK_H : TRACK_SIZES.medium[track.kind];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function clampTrackHeight(h: number): number {
|
|
32
|
+
return Math.round(Math.max(TRACK_MIN_H, Math.min(TRACK_MAX_H, h)));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The size a height is, when it is one of them. */
|
|
36
|
+
export function sizeOf(height: number, kind: TimelineLaneKind): TrackSize | null {
|
|
37
|
+
return (Object.keys(TRACK_SIZES) as TrackSize[]).find((s) => TRACK_SIZES[s][kind] === height) ?? null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The heights kept, by film.html track index now. */
|
|
41
|
+
export function trackHeightsOf(saved: readonly SavedTrackHeight[], tracks: ClipsOf): Map<number, number> {
|
|
42
|
+
return new Map([...placeSaved(saved, tracks)].map(([entry, i]) => [i, clampTrackHeight(entry.height)]));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The heights to keep once tracks `indexes` are `height` tall (null: back to the timeline's own). The others are kept
|
|
47
|
+
* with the clips their tracks have now; heights found on no track go.
|
|
48
|
+
*/
|
|
49
|
+
export function withTrackHeight(saved: readonly SavedTrackHeight[], tracks: ClipsOf, indexes: readonly number[], height: number | null): SavedTrackHeight[] {
|
|
50
|
+
const placed = placeSaved(saved, tracks);
|
|
51
|
+
const kept = saved.filter((entry) => placed.has(entry) && !indexes.includes(placed.get(entry)!))
|
|
52
|
+
.map((entry) => ({ height: entry.height, index: placed.get(entry)!, clips: (tracks[placed.get(entry)!]?.clips ?? []).map((c) => c.id) }));
|
|
53
|
+
if (height == null) return kept;
|
|
54
|
+
return [...kept, ...indexes.map((index) => ({ height: clampTrackHeight(height), index, clips: (tracks[index]?.clips ?? []).map((c) => c.id) }))];
|
|
55
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A locked track is the person's (SPEC §1): nothing on it changes until it is unlocked. The timeline's own edits keep
|
|
3
|
+
* to that (lib/timeline-edit); these are for every other way a clip is changed — its box and its layers moved on the
|
|
4
|
+
* picture, the arrow keys, the inspector's fields, words typed in place — so the rule holds whichever way an edit comes.
|
|
5
|
+
*/
|
|
6
|
+
import { parseFilmDocLoc } from './film.ts';
|
|
7
|
+
|
|
8
|
+
/** What a lock does not stop: switching the track itself (locking, hiding, muting, moving it up or down). */
|
|
9
|
+
const TRACK_PROPS: ReadonlySet<string> = new Set(['locked', 'hidden', 'muted', 'trackOrder']);
|
|
10
|
+
|
|
11
|
+
type LockedTracks = { tracks: readonly { locked?: boolean }[] } | null | undefined;
|
|
12
|
+
|
|
13
|
+
/** Whether the clip at a film.html place (`film.html#2.0`) is on a locked track. */
|
|
14
|
+
export function trackLockedAt(doc: LockedTracks, loc: string | null | undefined): boolean {
|
|
15
|
+
const at = loc ? parseFilmDocLoc(loc) : null;
|
|
16
|
+
return Boolean(at && doc?.tracks[at.track]?.locked);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** The edits a lock refuses: any change to a clip on a locked track, but not a switch of the track itself. */
|
|
20
|
+
export function lockedEdits<E extends { loc: string; prop: string }>(edits: readonly E[], doc: LockedTracks): E[] {
|
|
21
|
+
return edits.filter((e) => !TRACK_PROPS.has(e.prop) && trackLockedAt(doc, e.loc));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Whether any of these clips (by their film.html place) is on a locked track. */
|
|
25
|
+
export function anyLocked(doc: LockedTracks, locs: readonly (string | null | undefined)[]): boolean {
|
|
26
|
+
return locs.some((loc) => trackLockedAt(doc, loc));
|
|
27
|
+
}
|