@crievo/omni 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +41 -0
- package/README.md +2 -2
- package/bin/omni.mjs +14 -0
- package/docs/onboarding/clone-voice.png +0 -0
- package/docs/onboarding/getting-started.png +0 -0
- package/docs/onboarding/new-video.png +0 -0
- package/docs/onboarding/providers.png +0 -0
- package/docs/onboarding/publish.png +0 -0
- package/docs/onboarding/references.png +0 -0
- package/docs/onboarding.md +212 -0
- package/omnivideo.config.example.json +437 -0
- package/package.json +40 -4
- package/reference/captions.md +156 -0
- package/reference/carousel-contract.md +91 -0
- package/reference/cloud.md +96 -0
- package/reference/learnings.md +792 -0
- package/reference/omnichat.md +305 -0
- package/reference/premiere-mcp.md +91 -0
- package/reference/publish.md +305 -0
- package/reference/scenes-contract.md +109 -0
- package/reference/studio.md +666 -0
- package/reference/voicestudio.md +81 -0
- package/reference/writing-for-voice.md +67 -0
- package/requirements.txt +3 -0
- package/studio/api/app.ts +87 -0
- package/studio/api/lib/errors.ts +33 -0
- package/studio/api/lib/files.ts +41 -0
- package/studio/api/lib/hono.ts +9 -0
- package/studio/api/lib/result.ts +14 -0
- package/studio/api/lib/validate.ts +31 -0
- package/studio/api/lib/video.ts +10 -0
- package/studio/api/middleware/json-charset.ts +11 -0
- package/studio/api/middleware/local-only.ts +32 -0
- package/studio/api/middleware/no-timeout.ts +10 -0
- package/studio/api/routes/admin.ts +18 -0
- package/studio/api/routes/agent-cascade.ts +100 -0
- package/studio/api/routes/agent-history.ts +23 -0
- package/studio/api/routes/agent.ts +162 -0
- package/studio/api/routes/analytics.ts +31 -0
- package/studio/api/routes/approval.ts +60 -0
- package/studio/api/routes/archive.ts +12 -0
- package/studio/api/routes/captions.ts +28 -0
- package/studio/api/routes/carousel.ts +38 -0
- package/studio/api/routes/clone.ts +27 -0
- package/studio/api/routes/create.ts +19 -0
- package/studio/api/routes/events.ts +11 -0
- package/studio/api/routes/export.ts +14 -0
- package/studio/api/routes/media.ts +30 -0
- package/studio/api/routes/omnichat.ts +113 -0
- package/studio/api/routes/onboarding.ts +14 -0
- package/studio/api/routes/publish.ts +40 -0
- package/studio/api/routes/queue.ts +14 -0
- package/studio/api/routes/references.ts +40 -0
- package/studio/api/routes/runner.ts +17 -0
- package/studio/api/routes/schedule.ts +47 -0
- package/studio/api/routes/services.ts +11 -0
- package/studio/api/routes/sessions.ts +27 -0
- package/studio/api/routes/settings.ts +102 -0
- package/studio/api/routes/sound.ts +45 -0
- package/studio/api/routes/thumbnail.ts +18 -0
- package/studio/api/routes/usage.ts +13 -0
- package/studio/api/routes/videos.ts +41 -0
- package/studio/api/routes/voices.ts +71 -0
- package/studio/api/services/admin.ts +113 -0
- package/studio/api/services/agent-cascade.ts +975 -0
- package/studio/api/services/agent-claude.ts +47 -0
- package/studio/api/services/agent-history.ts +103 -0
- package/studio/api/services/agent-persona.ts +77 -0
- package/studio/api/services/agent-tools.ts +2237 -0
- package/studio/api/services/agent-ui-tools.ts +259 -0
- package/studio/api/services/agent-wait.ts +32 -0
- package/studio/api/services/agent.ts +553 -0
- package/studio/api/services/analytics.ts +92 -0
- package/studio/api/services/approval.ts +134 -0
- package/studio/api/services/archive.ts +38 -0
- package/studio/api/services/captions.ts +268 -0
- package/studio/api/services/carousel.ts +206 -0
- package/studio/api/services/classify.ts +196 -0
- package/studio/api/services/clone-phrases.ts +75 -0
- package/studio/api/services/clone.ts +722 -0
- package/studio/api/services/create.ts +421 -0
- package/studio/api/services/events.ts +215 -0
- package/studio/api/services/media.ts +32 -0
- package/studio/api/services/omnichat.ts +624 -0
- package/studio/api/services/onboarding.ts +77 -0
- package/studio/api/services/publish.ts +287 -0
- package/studio/api/services/queue.ts +150 -0
- package/studio/api/services/references.ts +269 -0
- package/studio/api/services/root.ts +60 -0
- package/studio/api/services/services.ts +114 -0
- package/studio/api/services/sessions.ts +1007 -0
- package/studio/api/services/settings.ts +983 -0
- package/studio/api/services/sound.ts +311 -0
- package/studio/api/services/thumbnail.ts +133 -0
- package/studio/api/services/usage.ts +27 -0
- package/studio/api/services/videos.ts +418 -0
- package/studio/api/services/voice-pause.ts +98 -0
- package/studio/api/services/voices.ts +324 -0
- package/studio/runner/runner.ts +244 -0
- package/studio/shared/omni-actions.ts +68 -0
- package/studio/shared/omni-admin.ts +52 -0
- package/studio/shared/omni-farewell.ts +48 -0
- package/studio/shared/omni-hotword.ts +20 -0
- package/studio/shared/omni-screens.ts +228 -0
- package/studio/shared/schemas/admin.ts +15 -0
- package/studio/shared/schemas/agent-cascade.ts +58 -0
- package/studio/shared/schemas/agent-history.ts +73 -0
- package/studio/shared/schemas/agent.ts +50 -0
- package/studio/shared/schemas/analytics.ts +6 -0
- package/studio/shared/schemas/approval.ts +22 -0
- package/studio/shared/schemas/captions.ts +19 -0
- package/studio/shared/schemas/carousel.ts +26 -0
- package/studio/shared/schemas/clone.ts +40 -0
- package/studio/shared/schemas/common.ts +16 -0
- package/studio/shared/schemas/omnichat.ts +54 -0
- package/studio/shared/schemas/onboarding.ts +5 -0
- package/studio/shared/schemas/publish.ts +45 -0
- package/studio/shared/schemas/references.ts +20 -0
- package/studio/shared/schemas/settings.ts +82 -0
- package/studio/shared/schemas/sound.ts +22 -0
- package/studio/shared/schemas/videos.ts +38 -0
- package/studio/shared/schemas/voices.ts +23 -0
- package/studio/shared/types/api.ts +1290 -0
- package/studio/studio.ts +148 -0
- package/studio/tsconfig.json +15 -0
- package/studio/web/assets/logos/cartesia.svg +4 -0
- package/studio/web/assets/logos/elevenlabs.svg +12 -0
- package/studio/web/assets/logos/fish.svg +24 -0
- package/studio/web/assets/logos/omni-black.png +0 -0
- package/studio/web/assets/logos/omni-white.png +0 -0
- package/studio/web/assets/logos/voicestudio.svg +21 -0
- package/studio/web/components/AgentMark.tsx +7 -0
- package/studio/web/components/AgentWalking.tsx +11 -0
- package/studio/web/components/ApiKeyField.tsx +104 -0
- package/studio/web/components/AppShell.tsx +64 -0
- package/studio/web/components/ApprovalNotice.tsx +65 -0
- package/studio/web/components/AvatarGroupIcon.tsx +22 -0
- package/studio/web/components/AvatarNameField.tsx +86 -0
- package/studio/web/components/AvatarPicker.tsx +84 -0
- package/studio/web/components/BrandLogo.tsx +16 -0
- package/studio/web/components/CartesiaPlanSetting.tsx +90 -0
- package/studio/web/components/ClaudeWalking.tsx +32 -0
- package/studio/web/components/CloneVoiceDialog/GuidedScript.tsx +39 -0
- package/studio/web/components/CloneVoiceDialog/LanguageBar.tsx +37 -0
- package/studio/web/components/CloneVoiceDialog/LevelMeter.tsx +31 -0
- package/studio/web/components/CloneVoiceDialog/ProviderChoice.tsx +81 -0
- package/studio/web/components/CloneVoiceDialog/QualityPanel.tsx +62 -0
- package/studio/web/components/CloneVoiceDialog/RecordStep.tsx +50 -0
- package/studio/web/components/CloneVoiceDialog/RecorderBar.tsx +79 -0
- package/studio/web/components/CloneVoiceDialog/RedoSummary.tsx +54 -0
- package/studio/web/components/CloneVoiceDialog/SaveStep.tsx +91 -0
- package/studio/web/components/CloneVoiceDialog/SourceBar.tsx +30 -0
- package/studio/web/components/CloneVoiceDialog/index.tsx +141 -0
- package/studio/web/components/CloneVoiceDialog/types.ts +28 -0
- package/studio/web/components/CloneVoiceDialog/useCloneVoice.ts +528 -0
- package/studio/web/components/ConnectionSignals.tsx +51 -0
- package/studio/web/components/EditVoiceDialog/EditVoiceFooter.tsx +72 -0
- package/studio/web/components/EditVoiceDialog/ProviderCards.tsx +81 -0
- package/studio/web/components/EditVoiceDialog/index.tsx +256 -0
- package/studio/web/components/ErrorBanner.tsx +115 -0
- package/studio/web/components/FinishedTask.tsx +41 -0
- package/studio/web/components/FishModelSetting.tsx +69 -0
- package/studio/web/components/FishPriceSetting.tsx +44 -0
- package/studio/web/components/HumanBanner.tsx +64 -0
- package/studio/web/components/Lightbox.tsx +41 -0
- package/studio/web/components/LogStream.tsx +42 -0
- package/studio/web/components/Markdown.tsx +21 -0
- package/studio/web/components/MissingDmsPanel/BatchSend.tsx +137 -0
- package/studio/web/components/MissingDmsPanel/CommentCard.tsx +168 -0
- package/studio/web/components/MissingDmsPanel/CommentFeed.tsx +45 -0
- package/studio/web/components/MissingDmsPanel/DmBubble.tsx +38 -0
- package/studio/web/components/MissingDmsPanel/ReplyComposer.tsx +63 -0
- package/studio/web/components/MissingDmsPanel/index.tsx +98 -0
- package/studio/web/components/NotFound.tsx +48 -0
- package/studio/web/components/Omni/OmniAvatarPicker.tsx +92 -0
- package/studio/web/components/Omni/OmniCards.tsx +202 -0
- package/studio/web/components/Omni/OmniGlow.tsx +183 -0
- package/studio/web/components/Omni/OmniHistory.tsx +119 -0
- package/studio/web/components/Omni/OmniHotword.tsx +40 -0
- package/studio/web/components/Omni/OmniMicSelect.tsx +92 -0
- package/studio/web/components/Omni/OmniVoiceSample.tsx +81 -0
- package/studio/web/components/Omni/OmniWidget.tsx +743 -0
- package/studio/web/components/Omni/PendingActions.tsx +200 -0
- package/studio/web/components/Omni/Transcript.tsx +127 -0
- package/studio/web/components/OmnichatAccountStatus.tsx +87 -0
- package/studio/web/components/OmnichatRulePanel/RuleConfig.tsx +150 -0
- package/studio/web/components/OmnichatRulePanel/RuleDryRun.tsx +15 -0
- package/studio/web/components/OmnichatRulePanel/RuleEnableConfirm.tsx +42 -0
- package/studio/web/components/OmnichatRulePanel/RuleSkeleton.tsx +18 -0
- package/studio/web/components/OmnichatRulePanel/RuleStatus.tsx +55 -0
- package/studio/web/components/OmnichatRulePanel/index.tsx +115 -0
- package/studio/web/components/OmnichatRulePanel/rule-steps.ts +67 -0
- package/studio/web/components/OmnichatRulePanel/steps/MessageStep.tsx +91 -0
- package/studio/web/components/OmnichatRulePanel/steps/RepliesStep.tsx +201 -0
- package/studio/web/components/OmnichatRulePanel/steps/TriggerStep.tsx +76 -0
- package/studio/web/components/OmnichatRulePanel/steps/types.ts +11 -0
- package/studio/web/components/Palette.tsx +17 -0
- package/studio/web/components/PlatformCard.tsx +109 -0
- package/studio/web/components/PlatformIcon.tsx +19 -0
- package/studio/web/components/ProviderCard.tsx +80 -0
- package/studio/web/components/ProviderDetail.tsx +367 -0
- package/studio/web/components/ProviderLogo.tsx +20 -0
- package/studio/web/components/QueuePanel.tsx +77 -0
- package/studio/web/components/ReferenceActions.tsx +89 -0
- package/studio/web/components/ReferencePicker.tsx +136 -0
- package/studio/web/components/ResultMessage.tsx +7 -0
- package/studio/web/components/RuleForm.tsx +138 -0
- package/studio/web/components/RuleLog.tsx +151 -0
- package/studio/web/components/RunningTask.tsx +23 -0
- package/studio/web/components/SampleList.tsx +55 -0
- package/studio/web/components/SessionPanel.tsx +352 -0
- package/studio/web/components/SettingRow.tsx +14 -0
- package/studio/web/components/SettingsCategorySkeleton.tsx +25 -0
- package/studio/web/components/SidePanel.tsx +77 -0
- package/studio/web/components/Sidebar.tsx +289 -0
- package/studio/web/components/StageStepper.tsx +87 -0
- package/studio/web/components/StudioOffline.tsx +80 -0
- package/studio/web/components/TaskName.tsx +17 -0
- package/studio/web/components/TopBanners.tsx +30 -0
- package/studio/web/components/VideoOmnichatPanel.tsx +287 -0
- package/studio/web/components/VoiceAvatar.tsx +33 -0
- package/studio/web/components/VoiceCarousel.tsx +196 -0
- package/studio/web/components/VoiceCategory.tsx +9 -0
- package/studio/web/components/VoiceModal.tsx +39 -0
- package/studio/web/components/VoiceProfileCard.tsx +75 -0
- package/studio/web/components/VoiceProfilePicker.tsx +107 -0
- package/studio/web/components/VoiceProfilesSettings.tsx +150 -0
- package/studio/web/components/VoiceProviderCard.tsx +118 -0
- package/studio/web/components/VoiceProvidersCard.tsx +26 -0
- package/studio/web/components/WaitList.tsx +21 -0
- package/studio/web/components/icons.tsx +247 -0
- package/studio/web/components/ui/accordion.tsx +47 -0
- package/studio/web/components/ui/badge.tsx +18 -0
- package/studio/web/components/ui/calendar.tsx +43 -0
- package/studio/web/components/ui/chart.tsx +229 -0
- package/studio/web/components/ui/checkbox.tsx +26 -0
- package/studio/web/components/ui/cx.ts +2 -0
- package/studio/web/components/ui/date-time-picker.tsx +84 -0
- package/studio/web/components/ui/panel.tsx +23 -0
- package/studio/web/components/ui/picker.tsx +58 -0
- package/studio/web/components/ui/popover.tsx +24 -0
- package/studio/web/components/ui/select.tsx +89 -0
- package/studio/web/components/ui/skeleton.tsx +10 -0
- package/studio/web/components/ui/slider.tsx +68 -0
- package/studio/web/components/ui/switch.tsx +13 -0
- package/studio/web/components/ui/tooltip.test.tsx +30 -0
- package/studio/web/components/ui/tooltip.tsx +59 -0
- package/studio/web/hooks/useAccounts.ts +27 -0
- package/studio/web/hooks/useAdmin.ts +12 -0
- package/studio/web/hooks/useAnalytics.ts +21 -0
- package/studio/web/hooks/useAvatarAudioReactive.ts +87 -0
- package/studio/web/hooks/useBrowserConnect.ts +48 -0
- package/studio/web/hooks/useClonePlan.ts +14 -0
- package/studio/web/hooks/useConnected.ts +7 -0
- package/studio/web/hooks/useLiveQuery.ts +29 -0
- package/studio/web/hooks/useMenuCollapsed.ts +32 -0
- package/studio/web/hooks/useMicDevices.ts +53 -0
- package/studio/web/hooks/useMissingDms.ts +211 -0
- package/studio/web/hooks/useMissingSetupSteps.ts +26 -0
- package/studio/web/hooks/useNow.ts +11 -0
- package/studio/web/hooks/useOmniAgent.ts +278 -0
- package/studio/web/hooks/useOmniClaude.ts +124 -0
- package/studio/web/hooks/useOmniDock.ts +142 -0
- package/studio/web/hooks/useOmniGreeting.ts +60 -0
- package/studio/web/hooks/useOmniHotword.ts +128 -0
- package/studio/web/hooks/useOmnichat.ts +26 -0
- package/studio/web/hooks/useOnboarding.ts +27 -0
- package/studio/web/hooks/usePost.ts +23 -0
- package/studio/web/hooks/useQueue.ts +10 -0
- package/studio/web/hooks/useReferences.ts +20 -0
- package/studio/web/hooks/useRuleEditor.ts +101 -0
- package/studio/web/hooks/useRunner.ts +24 -0
- package/studio/web/hooks/useSaveAction.ts +23 -0
- package/studio/web/hooks/useSchedule.ts +11 -0
- package/studio/web/hooks/useServices.ts +10 -0
- package/studio/web/hooks/useSessions.ts +15 -0
- package/studio/web/hooks/useSettings.ts +11 -0
- package/studio/web/hooks/useSettingsSection.ts +30 -0
- package/studio/web/hooks/useSidePanel.ts +23 -0
- package/studio/web/hooks/useSound.ts +30 -0
- package/studio/web/hooks/useUsage.ts +11 -0
- package/studio/web/hooks/useVideoVoice.ts +36 -0
- package/studio/web/hooks/useVideos.ts +21 -0
- package/studio/web/hooks/useVoiceProfilePreview.ts +52 -0
- package/studio/web/hooks/useVoiceProfiles.ts +7 -0
- package/studio/web/hooks/useVoiceRunning.ts +10 -0
- package/studio/web/hooks/useVoiceStudioClosed.ts +8 -0
- package/studio/web/index.html +19 -0
- package/studio/web/lib/agent.ts +7 -0
- package/studio/web/lib/alerts.ts +210 -0
- package/studio/web/lib/analytics-metrics.ts +351 -0
- package/studio/web/lib/api.ts +70 -0
- package/studio/web/lib/audio.ts +39 -0
- package/studio/web/lib/avatars.ts +41 -0
- package/studio/web/lib/calendar.ts +218 -0
- package/studio/web/lib/caption-position.ts +249 -0
- package/studio/web/lib/carousel.ts +24 -0
- package/studio/web/lib/chime.ts +42 -0
- package/studio/web/lib/clone-voice.ts +55 -0
- package/studio/web/lib/export.ts +11 -0
- package/studio/web/lib/files.ts +8 -0
- package/studio/web/lib/format.ts +93 -0
- package/studio/web/lib/media.ts +29 -0
- package/studio/web/lib/mic-device.ts +72 -0
- package/studio/web/lib/missing-dms.ts +70 -0
- package/studio/web/lib/omni-cards.ts +42 -0
- package/studio/web/lib/omni-cascade.ts +1067 -0
- package/studio/web/lib/omni-greeting-audio.ts +24 -0
- package/studio/web/lib/omni-hotword.ts +231 -0
- package/studio/web/lib/omni-panel.ts +67 -0
- package/studio/web/lib/omni-realtime.ts +811 -0
- package/studio/web/lib/omni-ui.ts +402 -0
- package/studio/web/lib/omni-wait.ts +174 -0
- package/studio/web/lib/omnichat-api.ts +44 -0
- package/studio/web/lib/orb.ts +270 -0
- package/studio/web/lib/pcm-recorder.ts +115 -0
- package/studio/web/lib/platforms.ts +17 -0
- package/studio/web/lib/providers.ts +27 -0
- package/studio/web/lib/publish-draft.ts +52 -0
- package/studio/web/lib/publish-settings.ts +81 -0
- package/studio/web/lib/query-client.ts +122 -0
- package/studio/web/lib/references.ts +13 -0
- package/studio/web/lib/services.ts +40 -0
- package/studio/web/lib/sessions.ts +103 -0
- package/studio/web/lib/settings-categories.ts +58 -0
- package/studio/web/lib/sound-audio.ts +33 -0
- package/studio/web/lib/sound-timeline.ts +291 -0
- package/studio/web/lib/sse.ts +86 -0
- package/studio/web/lib/stage-history.ts +141 -0
- package/studio/web/lib/stages.ts +344 -0
- package/studio/web/lib/studio-offline.ts +60 -0
- package/studio/web/lib/upload.ts +24 -0
- package/studio/web/lib/video-tabs.ts +118 -0
- package/studio/web/lib/voice-profile-draft.ts +34 -0
- package/studio/web/lib/voice-profiles.ts +3 -0
- package/studio/web/main.tsx +14 -0
- package/studio/web/pages/AdminPage/index.tsx +123 -0
- package/studio/web/pages/AgentPage/components/Measurements.tsx +102 -0
- package/studio/web/pages/AgentPage/index.tsx +28 -0
- package/studio/web/pages/AnalyticsPage/components/About.tsx +52 -0
- package/studio/web/pages/AnalyticsPage/components/ChannelCards.tsx +106 -0
- package/studio/web/pages/AnalyticsPage/components/ChannelView.tsx +137 -0
- package/studio/web/pages/AnalyticsPage/components/CollectionStatus.tsx +46 -0
- package/studio/web/pages/AnalyticsPage/components/Comparison.tsx +68 -0
- package/studio/web/pages/AnalyticsPage/components/Diagnosis.tsx +50 -0
- package/studio/web/pages/AnalyticsPage/components/Highlights.tsx +49 -0
- package/studio/web/pages/AnalyticsPage/components/Hint.tsx +11 -0
- package/studio/web/pages/AnalyticsPage/components/HookVsBody.tsx +100 -0
- package/studio/web/pages/AnalyticsPage/components/HourlyWave.tsx +133 -0
- package/studio/web/pages/AnalyticsPage/components/Insights.tsx +70 -0
- package/studio/web/pages/AnalyticsPage/components/MetricCard.tsx +46 -0
- package/studio/web/pages/AnalyticsPage/components/PlanSection.tsx +40 -0
- package/studio/web/pages/AnalyticsPage/components/ProgressionChart.tsx +155 -0
- package/studio/web/pages/AnalyticsPage/components/ReelBarsChart.tsx +154 -0
- package/studio/web/pages/AnalyticsPage/components/ReelThumb.tsx +19 -0
- package/studio/web/pages/AnalyticsPage/components/ReelView.tsx +290 -0
- package/studio/web/pages/AnalyticsPage/components/ReelsTable.tsx +269 -0
- package/studio/web/pages/AnalyticsPage/components/RequestWithFocus.tsx +38 -0
- package/studio/web/pages/AnalyticsPage/components/SegmentedControl.tsx +35 -0
- package/studio/web/pages/AnalyticsPage/components/VsMedian.tsx +31 -0
- package/studio/web/pages/AnalyticsPage/index.tsx +17 -0
- package/studio/web/pages/GettingStartedPage/index.tsx +174 -0
- package/studio/web/pages/NewVideoPage/components/DeliverablesPicker.tsx +62 -0
- package/studio/web/pages/NewVideoPage/components/FormatPicker.tsx +33 -0
- package/studio/web/pages/NewVideoPage/index.tsx +133 -0
- package/studio/web/pages/NotFoundPage/index.tsx +9 -0
- package/studio/web/pages/OmnichatPage/components/NewFromLink.tsx +59 -0
- package/studio/web/pages/OmnichatPage/components/RuleListItem.tsx +64 -0
- package/studio/web/pages/OmnichatPage/components/RulePreview.tsx +14 -0
- package/studio/web/pages/OmnichatPage/components/RuleView.tsx +88 -0
- package/studio/web/pages/OmnichatPage/index.tsx +153 -0
- package/studio/web/pages/QueuePage/index.tsx +22 -0
- package/studio/web/pages/ReferencePage/components/ReferenceTexts.tsx +131 -0
- package/studio/web/pages/ReferencePage/index.tsx +216 -0
- package/studio/web/pages/ReferencesPage/components/NewReferenceForm.tsx +150 -0
- package/studio/web/pages/ReferencesPage/components/ReferenceCard.tsx +42 -0
- package/studio/web/pages/ReferencesPage/components/ReferenceGridSkeleton.tsx +31 -0
- package/studio/web/pages/ReferencesPage/index.tsx +67 -0
- package/studio/web/pages/SchedulePage/components/CalendarSkeleton.tsx +18 -0
- package/studio/web/pages/SchedulePage/components/DayView.tsx +177 -0
- package/studio/web/pages/SchedulePage/components/HourPicker.tsx +103 -0
- package/studio/web/pages/SchedulePage/components/MonthDayCell.tsx +111 -0
- package/studio/web/pages/SchedulePage/components/MonthView.tsx +47 -0
- package/studio/web/pages/SchedulePage/components/PlatformIcons.tsx +12 -0
- package/studio/web/pages/SchedulePage/components/PostThumb.tsx +15 -0
- package/studio/web/pages/SchedulePage/components/WeekColumn.tsx +75 -0
- package/studio/web/pages/SchedulePage/components/WeekView.tsx +35 -0
- package/studio/web/pages/SchedulePage/index.tsx +285 -0
- package/studio/web/pages/SettingsPage/components/AgentAccounts.tsx +263 -0
- package/studio/web/pages/SettingsPage/components/AgentCategory.tsx +20 -0
- package/studio/web/pages/SettingsPage/components/ModelPicker.tsx +49 -0
- package/studio/web/pages/SettingsPage/components/ModelsSettings.tsx +138 -0
- package/studio/web/pages/SettingsPage/components/PlatformsCategory.tsx +23 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/AccountStatus.tsx +29 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/AutoPublishPanel.tsx +90 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/BrowserConnect.tsx +62 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/CheckField.tsx +19 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/InstagramPanel.tsx +113 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/OmnichatSettingsPanel.tsx +146 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/SaveBar.tsx +33 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/SchedulePanel.tsx +132 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/SettingsCard.tsx +47 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/SettingsCardGroup.tsx +19 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/TextPanel.tsx +55 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/TiktokPanel.tsx +123 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/YoutubePanel.tsx +100 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/badges.tsx +15 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/index.tsx +40 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/types.ts +10 -0
- package/studio/web/pages/SettingsPage/components/UsageCategory.tsx +389 -0
- package/studio/web/pages/SettingsPage/components/VoiceProvidersCategory.tsx +97 -0
- package/studio/web/pages/SettingsPage/index.tsx +85 -0
- package/studio/web/pages/VideoPage/components/AudioPlayer.tsx +113 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/AxisField.tsx +50 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionList.tsx +56 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionListItem.tsx +92 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionMargins.tsx +57 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionStyleFields.tsx +70 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionTextForm.tsx +87 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/ColorField.tsx +37 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/MarginField.tsx +59 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/NumberField.tsx +57 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/PositionControls.tsx +140 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/captionEditor.ts +215 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/useCaptionPosition.ts +154 -0
- package/studio/web/pages/VideoPage/components/CarouselChangeRequest.tsx +72 -0
- package/studio/web/pages/VideoPage/components/CarouselCompositionStage.tsx +80 -0
- package/studio/web/pages/VideoPage/components/CarouselCreate.tsx +63 -0
- package/studio/web/pages/VideoPage/components/CarouselMissing.tsx +19 -0
- package/studio/web/pages/VideoPage/components/CarouselPublishStage.tsx +173 -0
- package/studio/web/pages/VideoPage/components/CarouselScriptStage.tsx +82 -0
- package/studio/web/pages/VideoPage/components/CarouselSlideCard.tsx +49 -0
- package/studio/web/pages/VideoPage/components/CarouselViewer.tsx +55 -0
- package/studio/web/pages/VideoPage/components/ChangedVoices.tsx +53 -0
- package/studio/web/pages/VideoPage/components/CompositionStage.tsx +78 -0
- package/studio/web/pages/VideoPage/components/CoverPicker.tsx +32 -0
- package/studio/web/pages/VideoPage/components/EditorStage.tsx +53 -0
- package/studio/web/pages/VideoPage/components/LineTakes.tsx +160 -0
- package/studio/web/pages/VideoPage/components/LineTextEditor.tsx +124 -0
- package/studio/web/pages/VideoPage/components/LineVoicePicker.tsx +37 -0
- package/studio/web/pages/VideoPage/components/MediaImage.tsx +25 -0
- package/studio/web/pages/VideoPage/components/MotionScriptStage.tsx +39 -0
- package/studio/web/pages/VideoPage/components/NarrationStage.tsx +70 -0
- package/studio/web/pages/VideoPage/components/PublishForm.tsx +387 -0
- package/studio/web/pages/VideoPage/components/PublishStage.tsx +76 -0
- package/studio/web/pages/VideoPage/components/PublishText.tsx +149 -0
- package/studio/web/pages/VideoPage/components/ScenesApprovalPanel.tsx +278 -0
- package/studio/web/pages/VideoPage/components/ScheduledInfo.tsx +72 -0
- package/studio/web/pages/VideoPage/components/ScriptApprovalPanel.tsx +189 -0
- package/studio/web/pages/VideoPage/components/ScriptStage.tsx +17 -0
- package/studio/web/pages/VideoPage/components/SequencePlayer.tsx +146 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/AddSound.tsx +117 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/AreaSelection.tsx +74 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/BedPanel.tsx +94 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/BedRow.tsx +45 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionOverlay.tsx +44 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionSaveBar.tsx +32 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionsPanel.tsx +22 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/ClipBlock.tsx +111 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/ClipPanel.tsx +76 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/CutsPanel.tsx +44 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/EditorTabBar.tsx +73 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/EffectChoice.tsx +46 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/EffectItem.tsx +89 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/EffectPanel.tsx +232 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/EffectsRow.tsx +21 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/Lane.tsx +39 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/MarkerRow.tsx +40 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/MuteButton.tsx +36 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/NumberInput.tsx +37 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/PlanWarnings.tsx +19 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/PlayerResizeHandle.tsx +50 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/PreviewControls.tsx +51 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/SceneRow.tsx +54 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/SettingsPanel.tsx +65 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/SoundLibrary.tsx +99 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/SoundPreview.tsx +82 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/SpeedPanel.tsx +128 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineDock.tsx +56 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineFooter.tsx +26 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineSkeleton.tsx +21 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineToolbar.tsx +160 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineTracks.tsx +121 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TrackSidebar.tsx +30 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/VoiceRow.tsx +53 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/Waveform.tsx +97 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/clipActions.ts +50 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/effectActions.ts +161 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/index.tsx +161 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/timelineGeometry.ts +45 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/types.ts +43 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useAutosave.ts +107 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useEditorShortcuts.ts +168 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useFitHeight.ts +40 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useFollowPlayhead.ts +21 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useListenMix.ts +43 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/usePlayback.ts +231 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/usePlayerWidth.ts +27 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useSoundData.ts +124 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useSoundTimeline.ts +511 -0
- package/studio/web/pages/VideoPage/components/StageDrawer/CompareVersions.tsx +111 -0
- package/studio/web/pages/VideoPage/components/StageDrawer/VersionCard.tsx +81 -0
- package/studio/web/pages/VideoPage/components/StageDrawer/VersionMedia.tsx +24 -0
- package/studio/web/pages/VideoPage/components/StageDrawer/VersionText.tsx +15 -0
- package/studio/web/pages/VideoPage/components/StageDrawer/index.tsx +109 -0
- package/studio/web/pages/VideoPage/components/StageProcess.tsx +126 -0
- package/studio/web/pages/VideoPage/components/StageResult.tsx +69 -0
- package/studio/web/pages/VideoPage/components/SwapReference.tsx +92 -0
- package/studio/web/pages/VideoPage/components/ThumbnailPanel.tsx +252 -0
- package/studio/web/pages/VideoPage/components/TimingPanel.tsx +89 -0
- package/studio/web/pages/VideoPage/components/VideoPlayer.tsx +18 -0
- package/studio/web/pages/VideoPage/components/VideoSkeleton.tsx +50 -0
- package/studio/web/pages/VideoPage/components/VideoVoiceInfo.tsx +33 -0
- package/studio/web/pages/VideoPage/components/VideoVoicePicker.tsx +165 -0
- package/studio/web/pages/VideoPage/components/VoicePauseBanner.tsx +56 -0
- package/studio/web/pages/VideoPage/components/WithLogo.tsx +10 -0
- package/studio/web/pages/VideoPage/index.tsx +295 -0
- package/studio/web/pages/VideosPage/components/PublishedOn.tsx +85 -0
- package/studio/web/pages/VideosPage/components/ServicesPanel.tsx +81 -0
- package/studio/web/pages/VideosPage/components/SessionsPanel.tsx +62 -0
- package/studio/web/pages/VideosPage/components/VideoListSkeleton.tsx +25 -0
- package/studio/web/pages/VideosPage/components/VideoRow.tsx +122 -0
- package/studio/web/pages/VideosPage/index.tsx +134 -0
- package/studio/web/pages/VoicePage/index.tsx +28 -0
- package/studio/web/router.tsx +201 -0
- package/studio/web/styles/base/elements.css +55 -0
- package/studio/web/styles/base/utilities.css +25 -0
- package/studio/web/styles/components/badge.css +33 -0
- package/studio/web/styles/components/claude-running.css +27 -0
- package/studio/web/styles/components/claude-session.css +212 -0
- package/studio/web/styles/components/claude-walking.css +92 -0
- package/studio/web/styles/components/clone-voice-save.css +136 -0
- package/studio/web/styles/components/clone-voice.css +379 -0
- package/studio/web/styles/components/controls.css +70 -0
- package/studio/web/styles/components/data-and-image.css +54 -0
- package/studio/web/styles/components/forms.css +132 -0
- package/studio/web/styles/components/human-banner.css +99 -0
- package/studio/web/styles/components/lightbox.css +50 -0
- package/studio/web/styles/components/markdown.css +68 -0
- package/studio/web/styles/components/modal.css +70 -0
- package/studio/web/styles/components/omni-cards.css +105 -0
- package/studio/web/styles/components/omni.css +859 -0
- package/studio/web/styles/components/omnichat.css +538 -0
- package/studio/web/styles/components/panel.css +115 -0
- package/studio/web/styles/components/platform-card.css +140 -0
- package/studio/web/styles/components/provider-card.css +132 -0
- package/studio/web/styles/components/queue.css +185 -0
- package/studio/web/styles/components/reference-actions.css +133 -0
- package/studio/web/styles/components/reference-picker.css +146 -0
- package/studio/web/styles/components/results-drawer.css +224 -0
- package/studio/web/styles/components/segmented.css +115 -0
- package/studio/web/styles/components/side-panel-tab.css +23 -0
- package/studio/web/styles/components/status-signals.css +66 -0
- package/studio/web/styles/components/stepper.css +208 -0
- package/studio/web/styles/components/table.css +19 -0
- package/studio/web/styles/components/tabs.css +24 -0
- package/studio/web/styles/components/ui/accordion.css +71 -0
- package/studio/web/styles/components/ui/chart.css +162 -0
- package/studio/web/styles/components/ui/checkbox.css +37 -0
- package/studio/web/styles/components/ui/date-picker.css +153 -0
- package/studio/web/styles/components/ui/select.css +110 -0
- package/studio/web/styles/components/ui/skeleton.css +25 -0
- package/studio/web/styles/components/ui/slider.css +81 -0
- package/studio/web/styles/components/ui/switch.css +41 -0
- package/studio/web/styles/components/ui/tooltip.css +24 -0
- package/studio/web/styles/components/voice-carousel.css +255 -0
- package/studio/web/styles/components/voice-editor.css +179 -0
- package/studio/web/styles/components/voice-grid.css +56 -0
- package/studio/web/styles/components/voice-profiles.css +192 -0
- package/studio/web/styles/design-system.md +136 -0
- package/studio/web/styles/index.css +116 -0
- package/studio/web/styles/layout/page.css +41 -0
- package/studio/web/styles/layout/sidebar-groups.css +39 -0
- package/studio/web/styles/layout/sidebar.css +111 -0
- package/studio/web/styles/pages/agent.css +26 -0
- package/studio/web/styles/pages/analytics/dashboard.css +614 -0
- package/studio/web/styles/pages/analytics/insights.css +48 -0
- package/studio/web/styles/pages/getting-started.css +166 -0
- package/studio/web/styles/pages/new-video/form.css +32 -0
- package/studio/web/styles/pages/not-found.css +59 -0
- package/studio/web/styles/pages/references.css +204 -0
- package/studio/web/styles/pages/schedule/calendar.css +541 -0
- package/studio/web/styles/pages/schedule/chip-states.css +60 -0
- package/studio/web/styles/pages/settings/models.css +72 -0
- package/studio/web/styles/pages/settings/shell.css +361 -0
- package/studio/web/styles/pages/settings/usage.css +63 -0
- package/studio/web/styles/pages/studio-offline.css +105 -0
- package/studio/web/styles/pages/video/caption-controls.css +194 -0
- package/studio/web/styles/pages/video/captions-grid.css +70 -0
- package/studio/web/styles/pages/video/captions.css +79 -0
- package/studio/web/styles/pages/video/editor-chat.css +103 -0
- package/studio/web/styles/pages/video/export.css +50 -0
- package/studio/web/styles/pages/video/frames.css +29 -0
- package/studio/web/styles/pages/video/fullscreen-stage.css +400 -0
- package/studio/web/styles/pages/video/instagram-carousel.css +309 -0
- package/studio/web/styles/pages/video/layout.css +285 -0
- package/studio/web/styles/pages/video/narration.css +138 -0
- package/studio/web/styles/pages/video/preview-overview.css +11 -0
- package/studio/web/styles/pages/video/processing-notice.css +34 -0
- package/studio/web/styles/pages/video/publish-when.css +76 -0
- package/studio/web/styles/pages/video/publish.css +97 -0
- package/studio/web/styles/pages/video/result.css +96 -0
- package/studio/web/styles/pages/video/scenes.css +167 -0
- package/studio/web/styles/pages/video/sound-timeline.css +672 -0
- package/studio/web/styles/pages/video/sound-toolbar.css +149 -0
- package/studio/web/styles/pages/video/take-player.css +100 -0
- package/studio/web/styles/pages/video/thumbnail.css +157 -0
- package/studio/web/styles/pages/video/timeline.css +117 -0
- package/studio/web/styles/pages/video/voice-picker.css +14 -0
- package/studio/web/styles/pages/video-list/active-row.css +27 -0
- package/studio/web/styles/pages/video-list/card-link.css +49 -0
- package/studio/web/styles/pages/video-list/list.css +86 -0
- package/studio/web/styles/theme/identity/details.css +204 -0
- package/studio/web/styles/theme/identity/shell.css +249 -0
- package/studio/web/styles/theme/identity/surfaces.css +183 -0
- package/studio/web/styles/theme/identity/titles-and-buttons.css +120 -0
- package/studio/web/styles/theme/no-borders/blocks.css +208 -0
- package/studio/web/styles/theme/no-borders/controls.css +256 -0
- package/studio/web/styles/tokens.css +245 -0
- package/studio/web/types/api.ts +2 -0
- package/studio/web/types/assets.d.ts +9 -0
- package/templates/brief.md +27 -0
- package/templates/captions.html +204 -0
- package/templates/carousel-composition.md +47 -0
- package/templates/carousel-script.md +60 -0
- package/templates/components/voiceavatar/README.md +87 -0
- package/templates/components/voiceavatar/demo.html +50 -0
- package/templates/components/voiceavatar/voiceavatar.js +415 -0
- package/templates/motion.md +80 -0
- package/templates/playbook.md +43 -0
- package/templates/reference.md +123 -0
- package/templates/scene.html +112 -0
- package/templates/scenes.example.json +96 -0
- package/templates/script.md +63 -0
- package/templates/slide.html +71 -0
- package/templates/wireframe.html +91 -0
- package/tools/analysis.mjs +300 -0
- package/tools/approval.mjs +442 -0
- package/tools/assemble.mjs +942 -0
- package/tools/build-motion.mjs +437 -0
- package/tools/captions.mjs +246 -0
- package/tools/carousel.mjs +558 -0
- package/tools/compose.mjs +307 -0
- package/tools/cuts.mjs +74 -0
- package/tools/editor.mjs +419 -0
- package/tools/epidemic-capture.js +54 -0
- package/tools/fanout.mjs +69 -0
- package/tools/history.mjs +70 -0
- package/tools/history.py +61 -0
- package/tools/job-queue.mjs +180 -0
- package/tools/job_queue.py +430 -0
- package/tools/lib/agents.mjs +412 -0
- package/tools/lib/channel.mjs +399 -0
- package/tools/lib/claude-settings.mjs +67 -0
- package/tools/lib/cli.mjs +9 -0
- package/tools/lib/fanout.mjs +234 -0
- package/tools/lib/http.mjs +94 -0
- package/tools/lib/index.js +14 -0
- package/tools/lib/mcp-server.mjs +69 -0
- package/tools/lib/metrics/metrics.mjs +204 -0
- package/tools/lib/narration.mjs +15 -0
- package/tools/lib/oauth-client.mjs +295 -0
- package/tools/lib/omnichat/config.mjs +139 -0
- package/tools/lib/omnichat/errors.mjs +42 -0
- package/tools/lib/omnichat/extract.mjs +82 -0
- package/tools/lib/omnichat/gate.mjs +151 -0
- package/tools/lib/omnichat/manual.mjs +166 -0
- package/tools/lib/omnichat/match.mjs +78 -0
- package/tools/lib/omnichat/pass.mjs +393 -0
- package/tools/lib/omnichat/record.mjs +208 -0
- package/tools/lib/omnichat/text.mjs +315 -0
- package/tools/lib/omnichat/webhook.mjs +166 -0
- package/tools/lib/pairing.mjs +99 -0
- package/tools/lib/paths.mjs +41 -0
- package/tools/lib/platforms/instagram.mjs +469 -0
- package/tools/lib/platforms/tiktok.mjs +343 -0
- package/tools/lib/platforms/youtube.mjs +228 -0
- package/tools/lib/publish/publish.mjs +244 -0
- package/tools/lib/schedule/schedule.mjs +191 -0
- package/tools/lib/service.mjs +134 -0
- package/tools/lib/skill-client.mjs +126 -0
- package/tools/lib/skills-release.mjs +196 -0
- package/tools/lib/testing.mjs +52 -0
- package/tools/lib/up.mjs +187 -0
- package/tools/metrics.mjs +415 -0
- package/tools/models.mjs +134 -0
- package/tools/narrate.mjs +257 -0
- package/tools/omni.mjs +298 -0
- package/tools/omni_paths.py +12 -0
- package/tools/omnichat.mjs +1577 -0
- package/tools/omnivideo.py +1122 -0
- package/tools/package.mjs +130 -0
- package/tools/platforms.mjs +236 -0
- package/tools/premiere.mjs +533 -0
- package/tools/publish.mjs +1496 -0
- package/tools/reference.mjs +1408 -0
- package/tools/render.mjs +426 -0
- package/tools/runner.mjs +156 -0
- package/tools/setup.mjs +466 -0
- package/tools/skills-release.mjs +93 -0
- package/tools/sound.mjs +1323 -0
- package/tools/soundtrack.mjs +217 -0
- package/tools/thumbnail.mjs +271 -0
- package/tools/timing.mjs +108 -0
- package/tools/usage.py +628 -0
- package/tools/voice-envelope.mjs +185 -0
- package/tools/voice.py +448 -0
- package/tools/voice_sample.py +75 -0
- package/tools/wireframe.mjs +230 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# VoiceAvatar
|
|
2
|
+
|
|
3
|
+
The audio-reactive orb of a talking voice: a round liquid gradient that flows
|
|
4
|
+
on its own and wakes up with the speech (a ring of light, faster flow, more
|
|
5
|
+
shake on the high frequencies). WebGL2, no libraries, seek-safe.
|
|
6
|
+
|
|
7
|
+
Measured from a voice-agent orb (principle, not a copied asset): the
|
|
8
|
+
structure and constants come from the reference, the shader code and the
|
|
9
|
+
palette are ours.
|
|
10
|
+
|
|
11
|
+
## Use in a scene
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<div id="avatar"></div>
|
|
15
|
+
<!-- omnivideo:component voiceavatar -->
|
|
16
|
+
<!-- omnivideo:envelope -->
|
|
17
|
+
<script>
|
|
18
|
+
VoiceAvatar.mount(document.getElementById("avatar"), {
|
|
19
|
+
envelope: window.VOICE_ENVELOPE,
|
|
20
|
+
timeOffset: window.OMNIVIDEO?.start ?? 0, // the idle flow carries across cuts
|
|
21
|
+
size: 560,
|
|
22
|
+
palette: ["#ff5a1f", "#ffa04d", "#c8240f"],
|
|
23
|
+
});
|
|
24
|
+
document.fonts.ready.then(() => { window.__ready = true; });
|
|
25
|
+
</script>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Each marker goes alone on its line; `tools/build-motion.mjs` pastes them in:
|
|
29
|
+
|
|
30
|
+
- `omnivideo:component NAME` → `templates/components/NAME/NAME.js`, inline.
|
|
31
|
+
- `omnivideo:envelope` → `window.VOICE_ENVELOPE` of **this scene**, computed by
|
|
32
|
+
`tools/voice-envelope.mjs --scene` from the scene's lines (`wav` placed at
|
|
33
|
+
`start`). While the scene has no voice it is `null` and the orb only idles.
|
|
34
|
+
|
|
35
|
+
The orb follows the renderer's `--t` by itself. Nothing plays and nothing
|
|
36
|
+
reads a clock, so a frame depends only on `t`.
|
|
37
|
+
|
|
38
|
+
## Options
|
|
39
|
+
|
|
40
|
+
| option | what |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `envelope` | `{ fps, low, mid, high, all }`, per-frame values 0..1; absent = silence |
|
|
43
|
+
| `audioStart` | scene second where the envelope's frame 0 plays (default 0; the build's envelope is already on the scene clock) |
|
|
44
|
+
| `timeOffset` | seconds added to `t` for the idle flow; the video's `--scene-start` makes it continuous across scenes |
|
|
45
|
+
| `palette` | three CSS colors; the whole orb is made of them |
|
|
46
|
+
| `grain` | light film grain, 0–0.2 (default 0.08); static and fixed to the pixel, so it never flickers |
|
|
47
|
+
| `seed` | integer; same palette, other blob layout |
|
|
48
|
+
| `size` | side in CSS px; omitted = the element's own width |
|
|
49
|
+
| `exposure` | default 0.15 |
|
|
50
|
+
| `autoSeek` | `false` to drive it by hand with `avatar.seek(t)` |
|
|
51
|
+
|
|
52
|
+
## How the voice becomes motion
|
|
53
|
+
|
|
54
|
+
`voice-envelope.mjs` emulates a browser `AnalyserNode` (48 kHz, fftSize 256,
|
|
55
|
+
Blackman, smoothing 0.8, −100…−30 dB) and averages four bands per 1/60 s frame:
|
|
56
|
+
low 0–200 Hz, mid 200–2000 Hz, high 2–20 kHz, all. In the shader:
|
|
57
|
+
|
|
58
|
+
| band | drives |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `all` | brightness of the ring (`min(all·4, 1)`) and its spin |
|
|
61
|
+
| `mid` | how far the ring sits from the centre |
|
|
62
|
+
| `low` | ring noise scale and the flow's clock |
|
|
63
|
+
| `high` | shake of the simplex drift and the second flow clock |
|
|
64
|
+
|
|
65
|
+
The live orb smooths these with per-frame lerps (0.55 for the level, 0.25 for
|
|
66
|
+
the running clock). Those are IIR filters, so here they are computed once over
|
|
67
|
+
the whole envelope and a seek is a lookup.
|
|
68
|
+
|
|
69
|
+
## What was left out on purpose
|
|
70
|
+
|
|
71
|
+
The reference also runs a 128² fluid simulation whose only effect on the image
|
|
72
|
+
is a 0.001 UV nudge and a 10 % hard-light tint. It accumulates state, so every
|
|
73
|
+
seek would have to replay it. It is cut; the difference is not visible.
|
|
74
|
+
|
|
75
|
+
## Demo
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
node tools/voice-envelope.mjs <voice.wav> --out templates/components/voiceavatar/envelope.js
|
|
79
|
+
node tools/render.mjs templates/components/voiceavatar/demo.html --sheet sheet.png \
|
|
80
|
+
--at 0,0.6,1.2,1.8,2.4,3,4,5 --w 1080 --h 1920
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`render.mjs` switches to software WebGL (SwiftShader) on its own when the scene
|
|
84
|
+
source mentions `webgl` or `VoiceAvatar` (`--gl` forces it): its default Chrome
|
|
85
|
+
runs with `--disable-gpu`, which has no WebGL at all. Software GL is slower
|
|
86
|
+
(about 0.1 s per 1080×1920 frame with 3 Chromes); `envelope.js` is generated
|
|
87
|
+
per voice and is not committed.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="pt-BR">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>voiceavatar demo</title>
|
|
6
|
+
<!-- ============================================================
|
|
7
|
+
VoiceAvatar demo scene: the orb alone on the base canvas.
|
|
8
|
+
|
|
9
|
+
node tools/voice-envelope.mjs <voice.wav> --out templates/components/voiceavatar/envelope.js
|
|
10
|
+
node tools/render.mjs templates/components/voiceavatar/demo.html --sheet sheet.png \
|
|
11
|
+
--at 0,0.5,1,1.5,2,3,4,5 --w 1080 --h 1920
|
|
12
|
+
|
|
13
|
+
The voice starts at AUDIO_START (scene seconds).
|
|
14
|
+
============================================================ -->
|
|
15
|
+
<style>
|
|
16
|
+
:root{ --t:0s; --bg:#F5F5F3; }
|
|
17
|
+
html,body{ margin:0; width:100vw; height:100vh; overflow:hidden; background:var(--bg); }
|
|
18
|
+
.stage{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center; }
|
|
19
|
+
#avatar{
|
|
20
|
+
position:relative; width:58vmin; aspect-ratio:1; border-radius:50%; overflow:hidden;
|
|
21
|
+
/* soft inner edge, like the reference's inner shadow */
|
|
22
|
+
box-shadow:0 0 0 1px rgba(0,0,0,.06);
|
|
23
|
+
}
|
|
24
|
+
#avatar::after{
|
|
25
|
+
content:""; position:absolute; inset:0; border-radius:50%; pointer-events:none;
|
|
26
|
+
box-shadow:inset 0 0 14px rgba(0,0,0,.18);
|
|
27
|
+
}
|
|
28
|
+
</style>
|
|
29
|
+
</head>
|
|
30
|
+
<body>
|
|
31
|
+
<main class="stage"><div id="avatar"></div></main>
|
|
32
|
+
|
|
33
|
+
<script src="voiceavatar.js"></script>
|
|
34
|
+
<script src="envelope.js"></script>
|
|
35
|
+
<script>
|
|
36
|
+
const AUDIO_START = 0.4;
|
|
37
|
+
const el = document.getElementById("avatar");
|
|
38
|
+
VoiceAvatar.mount(el, {
|
|
39
|
+
envelope: window.VOICE_ENVELOPE,
|
|
40
|
+
audioStart: AUDIO_START,
|
|
41
|
+
size: Math.round(Math.min(innerWidth, innerHeight) * 0.58),
|
|
42
|
+
palette: ["#ff5a1f", "#ffa04d", "#c8240f"],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const q = new URLSearchParams(location.search);
|
|
46
|
+
if (q.has("t")) document.documentElement.style.setProperty("--t", q.get("t") + "s");
|
|
47
|
+
document.fonts.ready.then(() => { window.__ready = true; });
|
|
48
|
+
</script>
|
|
49
|
+
</body>
|
|
50
|
+
</html>
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
VoiceAvatar: the audio-reactive orb of a talking voice (WebGL2, no libs).
|
|
3
|
+
|
|
4
|
+
A round gradient that looks like liquid and moves with the speech: the
|
|
5
|
+
texture is warped by domain-warped fbm and simplex noise, a soft white ring
|
|
6
|
+
turns inside it and lights up with the voice. Measured from a voice-agent
|
|
7
|
+
orb in the wild (principle, not a copied asset): the structure and the
|
|
8
|
+
constants are what the reference showed, the code and the palette are ours.
|
|
9
|
+
|
|
10
|
+
Seek-safe: the frame depends only on t. There is no clock and no
|
|
11
|
+
requestAnimationFrame. `seek(t)` draws one frame; by default the avatar
|
|
12
|
+
follows the renderer's `--t` (a MutationObserver on <html>'s style, the same
|
|
13
|
+
contract as a paused GSAP timeline).
|
|
14
|
+
|
|
15
|
+
The audio is not played: it comes as an envelope (tools/voice-envelope.mjs
|
|
16
|
+
writes it from the voice WAV, emulating a browser AnalyserNode with
|
|
17
|
+
fftSize 256), so the same frames come out on every render.
|
|
18
|
+
|
|
19
|
+
const avatar = VoiceAvatar.mount(document.getElementById("avatar"), {
|
|
20
|
+
envelope: window.VOICE_ENVELOPE, // { fps, low, mid, high, all }, 0..1
|
|
21
|
+
audioStart: 0.4, // second of the scene where the voice begins
|
|
22
|
+
palette: ["#ff5a1f", "#ffa04d", "#c8240f"],
|
|
23
|
+
});
|
|
24
|
+
avatar.seek(2.1); // by hand (preview, stills)
|
|
25
|
+
|
|
26
|
+
In a scene: a <div id="avatar"> plus the two markers on a line of their own,
|
|
27
|
+
component and envelope (see README.md); the build pastes them in.
|
|
28
|
+
|
|
29
|
+
Options
|
|
30
|
+
envelope { fps, low, mid, high, all } per-frame values 0..1; absent = silence
|
|
31
|
+
audioStart scene second where the envelope's frame 0 plays (default 0)
|
|
32
|
+
timeOffset seconds added to t for the idle motion; use the video's
|
|
33
|
+
--scene-start so the orb flows on across a cut (default 0)
|
|
34
|
+
palette three CSS colors (the whole orb is made of them)
|
|
35
|
+
seed integer; the same palette with another seed moves the blobs
|
|
36
|
+
size CSS px of the side; omitted = the element's own size
|
|
37
|
+
exposure default 0.15
|
|
38
|
+
grain light film grain, 0 to 0.2 (default 0.08); static, fixed to the pixel
|
|
39
|
+
fill true = fill the whole frame instead of a round orb (no circular crop)
|
|
40
|
+
autoSeek follow --t on <html> (default true)
|
|
41
|
+
============================================================================ */
|
|
42
|
+
(function (root) {
|
|
43
|
+
"use strict";
|
|
44
|
+
|
|
45
|
+
/* what the reference measured; the audio terms are in the shader */
|
|
46
|
+
const CFG = {
|
|
47
|
+
timeScale: 1.4,
|
|
48
|
+
sphereScale: 0.9,
|
|
49
|
+
spherePower: 1.1,
|
|
50
|
+
noiseSpeed: 0.25,
|
|
51
|
+
noiseAmplitude: 0.15,
|
|
52
|
+
noiseScale: 0.65,
|
|
53
|
+
fbmScale: 3.25,
|
|
54
|
+
fbmPower: 2.75,
|
|
55
|
+
fbmAmplitude: 0.65,
|
|
56
|
+
fbmSpeed: 4.5,
|
|
57
|
+
ringOpacity: 0.4,
|
|
58
|
+
grain: 0.08,
|
|
59
|
+
overallSound: 1.8 /* how hard the voice drives everything below */,
|
|
60
|
+
voiceWarp: 0.9 /* extra liquid distortion at the loudest */,
|
|
61
|
+
voiceShake: 0.9 /* extra drift from the high frequencies */,
|
|
62
|
+
avgLerp: 0.55 /* per-frame lerp toward the band values */,
|
|
63
|
+
cumLerp: 0.25 /* same for the running (cumulative) clock */,
|
|
64
|
+
envFps: 60,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const VERT = `#version 300 es
|
|
68
|
+
in vec2 aPos;
|
|
69
|
+
out vec2 vUv;
|
|
70
|
+
void main(){ vUv = aPos * .5 + .5; gl_Position = vec4(aPos, 0., 1.); }`;
|
|
71
|
+
|
|
72
|
+
const f = n => (Number.isInteger(n) ? n.toFixed(1) : String(n));
|
|
73
|
+
|
|
74
|
+
const FRAG = `#version 300 es
|
|
75
|
+
precision highp float;
|
|
76
|
+
in vec2 vUv;
|
|
77
|
+
out vec4 outColor;
|
|
78
|
+
|
|
79
|
+
uniform float uTime; // seconds * timeScale
|
|
80
|
+
uniform vec4 uAudio; // smoothed low, mid, high, all
|
|
81
|
+
uniform vec4 uCum; // running clock per band
|
|
82
|
+
uniform float uExposure;
|
|
83
|
+
uniform float uFill; // 0 = round orb, 1 = fills the whole frame (no circular crop)
|
|
84
|
+
uniform float uGrain; // film grain amplitude; fixed to the pixel, so it never flickers
|
|
85
|
+
uniform sampler2D uTexture;
|
|
86
|
+
|
|
87
|
+
// --- simplex noise 3D (Ashima Arts / Stefan Gustavson, MIT) ---
|
|
88
|
+
vec4 permute(vec4 x){ return mod(((x*34.0)+1.0)*x, 289.0); }
|
|
89
|
+
vec4 taylorInvSqrt(vec4 r){ return 1.79284291400159 - 0.85373472095314 * r; }
|
|
90
|
+
float snoise(vec3 v){
|
|
91
|
+
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
|
|
92
|
+
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
|
93
|
+
vec3 i = floor(v + dot(v, C.yyy));
|
|
94
|
+
vec3 x0 = v - i + dot(i, C.xxx);
|
|
95
|
+
vec3 g = step(x0.yzx, x0.xyz);
|
|
96
|
+
vec3 l = 1.0 - g;
|
|
97
|
+
vec3 i1 = min(g.xyz, l.zxy);
|
|
98
|
+
vec3 i2 = max(g.xyz, l.zxy);
|
|
99
|
+
vec3 x1 = x0 - i1 + C.xxx;
|
|
100
|
+
vec3 x2 = x0 - i2 + 2.0 * C.xxx;
|
|
101
|
+
vec3 x3 = x0 - 1.0 + 3.0 * C.xxx;
|
|
102
|
+
i = mod(i, 289.0);
|
|
103
|
+
vec4 p = permute(permute(permute(
|
|
104
|
+
i.z + vec4(0.0, i1.z, i2.z, 1.0))
|
|
105
|
+
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
|
|
106
|
+
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
|
|
107
|
+
float n_ = 1.0/7.0;
|
|
108
|
+
vec3 ns = n_ * D.wyz - D.xzx;
|
|
109
|
+
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
|
|
110
|
+
vec4 x_ = floor(j * ns.z);
|
|
111
|
+
vec4 y_ = floor(j - 7.0 * x_);
|
|
112
|
+
vec4 x = x_ * ns.x + ns.yyyy;
|
|
113
|
+
vec4 y = y_ * ns.x + ns.yyyy;
|
|
114
|
+
vec4 h = 1.0 - abs(x) - abs(y);
|
|
115
|
+
vec4 b0 = vec4(x.xy, y.xy);
|
|
116
|
+
vec4 b1 = vec4(x.zw, y.zw);
|
|
117
|
+
vec4 s0 = floor(b0) * 2.0 + 1.0;
|
|
118
|
+
vec4 s1 = floor(b1) * 2.0 + 1.0;
|
|
119
|
+
vec4 sh = -step(h, vec4(0.0));
|
|
120
|
+
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
|
|
121
|
+
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
|
|
122
|
+
vec3 p0 = vec3(a0.xy, h.x);
|
|
123
|
+
vec3 p1 = vec3(a0.zw, h.y);
|
|
124
|
+
vec3 p2 = vec3(a1.xy, h.z);
|
|
125
|
+
vec3 p3 = vec3(a1.zw, h.w);
|
|
126
|
+
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2,p2), dot(p3,p3)));
|
|
127
|
+
p0 *= norm.x; p1 *= norm.y; p2 *= norm.z; p3 *= norm.w;
|
|
128
|
+
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
|
|
129
|
+
m = m * m;
|
|
130
|
+
return 42.0 * dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// --- value noise + fbm (4 octaves, rotated) ---
|
|
134
|
+
float rnd(vec2 st){ return fract(sin(dot(st, vec2(12.9898, 78.233))) * 43758.5453123); }
|
|
135
|
+
float vnoise(vec2 st){
|
|
136
|
+
vec2 i = floor(st), fr = fract(st);
|
|
137
|
+
float a = rnd(i), b = rnd(i + vec2(1., 0.)), c = rnd(i + vec2(0., 1.)), d = rnd(i + vec2(1., 1.));
|
|
138
|
+
vec2 u = fr * fr * (3.0 - 2.0 * fr);
|
|
139
|
+
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
|
|
140
|
+
}
|
|
141
|
+
float fbm(vec2 st){
|
|
142
|
+
float v = 0.0, a = 0.5;
|
|
143
|
+
mat2 rot = mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.5));
|
|
144
|
+
for (int i = 0; i < 4; i++){ v += a * vnoise(st); st = rot * st * 2.0 + vec2(100.0); a *= 0.5; }
|
|
145
|
+
return v;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
void main(){
|
|
149
|
+
vec2 uv = vec2(1.0 - vUv.x, vUv.y);
|
|
150
|
+
|
|
151
|
+
// sphere: bulge the texture coordinates toward the middle
|
|
152
|
+
vec2 p = (uv - 0.5) * 2.0 * mix(1.0, 0.72, uFill);
|
|
153
|
+
float d = pow(sqrt(1.0 - clamp(dot(p, p), 0.0, 1.0)), ${f(CFG.spherePower)});
|
|
154
|
+
vec3 normal = vec3(p, d);
|
|
155
|
+
uv = (p * ${f(CFG.sphereScale)} / (d + 1.0) + 1.0) * 0.5;
|
|
156
|
+
|
|
157
|
+
// liquid: domain-warped fbm; the voice speeds up its clock
|
|
158
|
+
vec2 fuv = uv * ${f(CFG.fbmScale)};
|
|
159
|
+
float tw = uTime * ${f(CFG.fbmSpeed)} * 0.5 + uCum.x * 0.25;
|
|
160
|
+
vec2 q = vec2(fbm(fuv), fbm(fuv + vec2(1.0)));
|
|
161
|
+
vec2 r = vec2(fbm(fuv + q + vec2(91.3, 0.55) + 0.15 * tw),
|
|
162
|
+
fbm(fuv + q - vec2(45.33, 1.2) + 0.126 * tw));
|
|
163
|
+
float fv = fbm(fuv + r);
|
|
164
|
+
float ff = mix(0.8, 0.66, clamp(fv * fv * ${f(CFG.fbmPower)}, 0.0, 1.0));
|
|
165
|
+
ff = mix(ff, 0.0, clamp(length(q), 0.0, 1.0));
|
|
166
|
+
ff = mix(ff, 1.0, clamp(abs(r.x), 0.0, 1.0));
|
|
167
|
+
|
|
168
|
+
// simplex drift; high frequencies shake it harder
|
|
169
|
+
float n1 = uTime * ${f(CFG.noiseSpeed)} * 0.5 + uCum.z * 0.1;
|
|
170
|
+
vec2 disp = vec2(snoise(vec3(vUv * ${f(CFG.noiseScale)}, n1)),
|
|
171
|
+
snoise(vec3(vUv * ${f(CFG.noiseScale)} + vec2(54.0), uTime * ${f(CFG.noiseSpeed)})));
|
|
172
|
+
disp *= 1.0 + uAudio.z * ${f(CFG.voiceShake)};
|
|
173
|
+
|
|
174
|
+
// the louder the voice, the more the liquid is stirred
|
|
175
|
+
float drive = clamp(uAudio.w * 3.0, 0.0, 1.5);
|
|
176
|
+
uv += normal.xy * (ff - 0.5) * ${f(CFG.fbmAmplitude)} * (1.0 + drive * ${f(CFG.voiceWarp)});
|
|
177
|
+
uv += disp * ${f(CFG.noiseAmplitude)};
|
|
178
|
+
vec3 color = texture(uTexture, uv).rgb;
|
|
179
|
+
|
|
180
|
+
// ring of light: only shows while there is sound
|
|
181
|
+
vec2 ru = (vUv - 0.5) * 2.0 * 0.75;
|
|
182
|
+
float ang = atan(ru.y, ru.x);
|
|
183
|
+
float len = length(ru);
|
|
184
|
+
float rt = -uTime * 0.5 - uCum.w * 0.2;
|
|
185
|
+
ru.x += 1.0 + uAudio.y * 1.5;
|
|
186
|
+
float n0 = snoise(vec3(ru * (0.65 + uAudio.x * 0.4), rt * 0.5)) * 0.5 + 0.5;
|
|
187
|
+
float cl = cos(ang + rt * 2.0) * 0.5 + 0.5;
|
|
188
|
+
cl *= (1.0 - smoothstep(mix(0.25, 1.0, n0 * 0.5), 1.0, len));
|
|
189
|
+
cl *= pow(smoothstep(0.25, mix(0.25, 1.0, n0 * 0.75), len), 2.0);
|
|
190
|
+
cl = clamp(pow(cl * min(uAudio.w * 4.0, 1.0), 3.0), 0.0, 1.0);
|
|
191
|
+
color += vec3(cl) * ${f(CFG.ringOpacity)};
|
|
192
|
+
|
|
193
|
+
// round mask, antialiased
|
|
194
|
+
float dist = length(vUv - 0.5) * 2.0;
|
|
195
|
+
float aa = max(fwidth(dist), 1e-4);
|
|
196
|
+
float a = mix(1.0 - smoothstep(1.0, 1.0 + aa, dist), 1.0, uFill);
|
|
197
|
+
|
|
198
|
+
// light grain: static noise per pixel, centered on zero so it neither darkens nor lightens
|
|
199
|
+
float grain = fract(sin(dot(gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453);
|
|
200
|
+
color = color * (1.0 + uExposure) + (grain - 0.5) * uGrain;
|
|
201
|
+
color = clamp(color, 0.0, 1.0);
|
|
202
|
+
outColor = vec4(color * a, a);
|
|
203
|
+
}`;
|
|
204
|
+
|
|
205
|
+
/* --- tiny seeded random: the palette texture is the same on every render --- */
|
|
206
|
+
function mulberry32(a) {
|
|
207
|
+
return function () {
|
|
208
|
+
a |= 0;
|
|
209
|
+
a = (a + 0x6d2b79f5) | 0;
|
|
210
|
+
let t = Math.imul(a ^ (a >>> 15), 1 | a);
|
|
211
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
212
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function withAlpha(css, a) {
|
|
217
|
+
const c = document.createElement("canvas").getContext("2d");
|
|
218
|
+
c.fillStyle = css;
|
|
219
|
+
const m = c.fillStyle.match(/^#(..)(..)(..)$/);
|
|
220
|
+
return m ? `rgba(${parseInt(m[1], 16)},${parseInt(m[2], 16)},${parseInt(m[3], 16)},${a})` : css;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* The orb's gradient: a diagonal wash of the three colors plus soft blobs of each of them. */
|
|
224
|
+
function paintTexture(palette, seed) {
|
|
225
|
+
const S = 512;
|
|
226
|
+
const c = document.createElement("canvas");
|
|
227
|
+
c.width = c.height = S;
|
|
228
|
+
const g = c.getContext("2d");
|
|
229
|
+
const rnd = mulberry32(seed);
|
|
230
|
+
const base = g.createLinearGradient(0, 0, S, S);
|
|
231
|
+
palette.forEach((col, i) => base.addColorStop(i / (palette.length - 1), col));
|
|
232
|
+
g.fillStyle = base;
|
|
233
|
+
g.fillRect(0, 0, S, S);
|
|
234
|
+
for (let i = 0; i < palette.length * 4; i++) {
|
|
235
|
+
const x = rnd() * S;
|
|
236
|
+
const y = rnd() * S;
|
|
237
|
+
const r = S * (0.22 + rnd() * 0.28);
|
|
238
|
+
const col = palette[i % palette.length]; /* each color gets the same number of blobs */
|
|
239
|
+
const rg = g.createRadialGradient(x, y, 0, x, y, r);
|
|
240
|
+
rg.addColorStop(0, col);
|
|
241
|
+
rg.addColorStop(1, withAlpha(col, 0)); /* same hue, not transparent black: no dark fringe */
|
|
242
|
+
g.globalAlpha = 0.9;
|
|
243
|
+
g.fillStyle = rg;
|
|
244
|
+
g.fillRect(0, 0, S, S);
|
|
245
|
+
}
|
|
246
|
+
g.globalAlpha = 1;
|
|
247
|
+
return c;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* Per-frame audio state, precomputed once so a seek is a lookup: the lerps
|
|
251
|
+
of the live orb are IIR filters, which would make the frame depend on the
|
|
252
|
+
order of the calls. Index i = frame i of the envelope at envFps. */
|
|
253
|
+
function precompute(env) {
|
|
254
|
+
const n = (env && env.all ? env.all.length : 0) + CFG.envFps * 2; /* 2 s of tail: it settles */
|
|
255
|
+
const avg = new Float32Array(n * 4);
|
|
256
|
+
const cum = new Float32Array(n * 4);
|
|
257
|
+
const a = [0, 0, 0, 0];
|
|
258
|
+
const c = [0, 0, 0, 0];
|
|
259
|
+
const bands = env ? [env.low, env.mid, env.high, env.all] : [];
|
|
260
|
+
for (let i = 0; i < n; i++) {
|
|
261
|
+
for (let k = 0; k < 4; k++) {
|
|
262
|
+
const raw = (bands[k] && bands[k][i]) || 0;
|
|
263
|
+
a[k] += CFG.avgLerp * (raw * CFG.overallSound - a[k]);
|
|
264
|
+
c[k] += CFG.cumLerp * raw * CFG.overallSound * CFG.timeScale; /* one 1/60 s step */
|
|
265
|
+
avg[i * 4 + k] = a[k];
|
|
266
|
+
cum[i * 4 + k] = c[k];
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return { n, avg, cum };
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/* The GL side, apart from any canvas: compiles the program once on `gl` and draws
|
|
273
|
+
one orb per call into a viewport. The studio shares one context among many
|
|
274
|
+
avatars through this; a scene's `mount` below owns a context of its own. */
|
|
275
|
+
function createPainter(gl) {
|
|
276
|
+
const sh = (type, src) => {
|
|
277
|
+
const s = gl.createShader(type);
|
|
278
|
+
gl.shaderSource(s, src);
|
|
279
|
+
gl.compileShader(s);
|
|
280
|
+
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error("VoiceAvatar shader: " + gl.getShaderInfoLog(s));
|
|
281
|
+
return s;
|
|
282
|
+
};
|
|
283
|
+
const prog = gl.createProgram();
|
|
284
|
+
gl.attachShader(prog, sh(gl.VERTEX_SHADER, VERT));
|
|
285
|
+
gl.attachShader(prog, sh(gl.FRAGMENT_SHADER, FRAG));
|
|
286
|
+
gl.linkProgram(prog);
|
|
287
|
+
if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) throw new Error("VoiceAvatar link: " + gl.getProgramInfoLog(prog));
|
|
288
|
+
gl.useProgram(prog);
|
|
289
|
+
|
|
290
|
+
const buf = gl.createBuffer();
|
|
291
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
|
|
292
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
|
|
293
|
+
const loc = gl.getAttribLocation(prog, "aPos");
|
|
294
|
+
gl.enableVertexAttribArray(loc);
|
|
295
|
+
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
|
|
296
|
+
|
|
297
|
+
const U = n => gl.getUniformLocation(prog, n);
|
|
298
|
+
const uTime = U("uTime");
|
|
299
|
+
const uAudio = U("uAudio");
|
|
300
|
+
const uCum = U("uCum");
|
|
301
|
+
const uExposure = U("uExposure");
|
|
302
|
+
const uFill = U("uFill");
|
|
303
|
+
const uGrain = U("uGrain");
|
|
304
|
+
gl.uniform1i(U("uTexture"), 0);
|
|
305
|
+
gl.enable(gl.SCISSOR_TEST);
|
|
306
|
+
|
|
307
|
+
return {
|
|
308
|
+
/* the orb's gradient, uploaded as a texture; free it with deleteTexture */
|
|
309
|
+
texture(palette, seed) {
|
|
310
|
+
const tex = gl.createTexture();
|
|
311
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
312
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
313
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, paintTexture(palette, seed));
|
|
314
|
+
/* no mipmaps: the warped coordinates jump between neighbour pixels, and the
|
|
315
|
+
derivative-picked mip level draws a fine hatch */
|
|
316
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
317
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
318
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
319
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
320
|
+
return tex;
|
|
321
|
+
},
|
|
322
|
+
deleteTexture(tex) {
|
|
323
|
+
gl.deleteTexture(tex);
|
|
324
|
+
},
|
|
325
|
+
/* o: { texture, time (s), audio [4], cum [4], width, height, x?, y?, fill?, exposure?, grain? } */
|
|
326
|
+
draw(o) {
|
|
327
|
+
const x = o.x || 0;
|
|
328
|
+
const y = o.y || 0;
|
|
329
|
+
gl.useProgram(prog);
|
|
330
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
331
|
+
gl.bindTexture(gl.TEXTURE_2D, o.texture);
|
|
332
|
+
gl.viewport(x, y, o.width, o.height);
|
|
333
|
+
gl.scissor(x, y, o.width, o.height);
|
|
334
|
+
gl.uniform1f(uTime, o.time * CFG.timeScale);
|
|
335
|
+
gl.uniform4fv(uAudio, o.audio);
|
|
336
|
+
gl.uniform4fv(uCum, o.cum);
|
|
337
|
+
gl.uniform1f(uExposure, o.exposure == null ? 0.15 : o.exposure);
|
|
338
|
+
gl.uniform1f(uFill, o.fill ? 1 : 0);
|
|
339
|
+
gl.uniform1f(uGrain, o.grain == null ? CFG.grain : o.grain);
|
|
340
|
+
gl.clearColor(0, 0, 0, 0);
|
|
341
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
342
|
+
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function mount(el, opts) {
|
|
348
|
+
opts = opts || {};
|
|
349
|
+
const palette = opts.palette && opts.palette.length > 1 ? opts.palette : ["#ff5a1f", "#ffa04d", "#c8240f"];
|
|
350
|
+
const side = opts.size || el.clientWidth || 256;
|
|
351
|
+
const audioStart = opts.audioStart || 0;
|
|
352
|
+
const timeOffset = opts.timeOffset || 0;
|
|
353
|
+
const state = precompute(opts.envelope);
|
|
354
|
+
const fps = (opts.envelope && opts.envelope.fps) || CFG.envFps;
|
|
355
|
+
|
|
356
|
+
el.classList.add("voiceavatar");
|
|
357
|
+
if (opts.size) {
|
|
358
|
+
el.style.width = el.style.height = side + "px";
|
|
359
|
+
}
|
|
360
|
+
const cv = document.createElement("canvas");
|
|
361
|
+
cv.width = cv.height = Math.round(side * (opts.dpr || 1));
|
|
362
|
+
cv.style.cssText = "position:absolute;inset:0;width:100%;height:100%;display:block";
|
|
363
|
+
el.appendChild(cv);
|
|
364
|
+
|
|
365
|
+
const gl = cv.getContext("webgl2", { alpha: true, premultipliedAlpha: true, antialias: false, preserveDrawingBuffer: true });
|
|
366
|
+
if (!gl) throw new Error("VoiceAvatar: WebGL2 indisponível");
|
|
367
|
+
const painter = createPainter(gl);
|
|
368
|
+
const texture = painter.texture(palette, opts.seed == null ? 7 : opts.seed);
|
|
369
|
+
|
|
370
|
+
/* audio state at scene second t: linear between the two frames around it */
|
|
371
|
+
function audioAt(t) {
|
|
372
|
+
const x = (t - audioStart) * fps;
|
|
373
|
+
if (x <= 0) return { avg: [0, 0, 0, 0], cum: [0, 0, 0, 0] };
|
|
374
|
+
const i0 = Math.min(Math.floor(x), state.n - 1);
|
|
375
|
+
const i1 = Math.min(i0 + 1, state.n - 1);
|
|
376
|
+
const w = x - Math.floor(x);
|
|
377
|
+
const avg = [];
|
|
378
|
+
const cum = [];
|
|
379
|
+
for (let k = 0; k < 4; k++) {
|
|
380
|
+
avg.push(state.avg[i0 * 4 + k] * (1 - w) + state.avg[i1 * 4 + k] * w);
|
|
381
|
+
cum.push(state.cum[i0 * 4 + k] * (1 - w) + state.cum[i1 * 4 + k] * w);
|
|
382
|
+
}
|
|
383
|
+
return { avg, cum };
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function seek(t) {
|
|
387
|
+
const s = audioAt(t);
|
|
388
|
+
painter.draw({
|
|
389
|
+
texture,
|
|
390
|
+
time: t + timeOffset,
|
|
391
|
+
audio: s.avg,
|
|
392
|
+
cum: s.cum,
|
|
393
|
+
width: cv.width,
|
|
394
|
+
height: cv.height,
|
|
395
|
+
exposure: opts.exposure,
|
|
396
|
+
fill: opts.fill,
|
|
397
|
+
grain: opts.grain,
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const readT = () => parseFloat(document.documentElement.style.getPropertyValue("--t")) || 0;
|
|
402
|
+
if (opts.autoSeek !== false) {
|
|
403
|
+
new MutationObserver(() => seek(readT())).observe(document.documentElement, { attributes: true, attributeFilter: ["style"] });
|
|
404
|
+
}
|
|
405
|
+
seek(readT());
|
|
406
|
+
return { seek, canvas: cv, audioAt };
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/* a scene loads this as a plain script and finds `VoiceAvatar` on window; a bundler (the studio)
|
|
410
|
+
gets it as a module, and must not touch the global: a bundle's own top-level `VoiceAvatar`
|
|
411
|
+
(the React component) would be overwritten by it */
|
|
412
|
+
const api = { mount, createPainter, config: CFG };
|
|
413
|
+
if (typeof module === "object" && module && module.exports) module.exports = api;
|
|
414
|
+
else root.VoiceAvatar = api;
|
|
415
|
+
})(typeof window !== "undefined" ? window : globalThis);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Roteiro de motion · <título>
|
|
2
|
+
|
|
3
|
+
Formato: 9:16, 1080×1920, 30 fps.
|
|
4
|
+
Momento "wow": cena `cNN`, <o que acontece>.
|
|
5
|
+
|
|
6
|
+
## Estilo visual
|
|
7
|
+
|
|
8
|
+
Um estilo visual da biblioteca, `referencias/<pasta>` (veja `node tools/reference.mjs list`).
|
|
9
|
+
Um, no máximo dois. O que vem dele é princípio, não asset.
|
|
10
|
+
|
|
11
|
+
| | |
|
|
12
|
+
|---|---|
|
|
13
|
+
| por que este | o que ele tem que este vídeo precisa |
|
|
14
|
+
| vale levar | os itens do "Vale levar" do guia que entram aqui, cada um como regra |
|
|
15
|
+
| primitivas | as do guia que este vídeo usa, e se vêm do código da `proof/proof.html` |
|
|
16
|
+
| traduzido | o que da peça o código não reproduz (Tipo do guia) e o que entra no lugar; "nada" se o Tipo é reproduzível inteiro |
|
|
17
|
+
| ritmo | do `measurements.json`: quanto dura um beat, quanto a tela segura depois |
|
|
18
|
+
| não copiar | marca, dados, layout literal |
|
|
19
|
+
|
|
20
|
+
## Estilo do vídeo
|
|
21
|
+
|
|
22
|
+
Vale para todas as cenas e sai do estilo visual: medido, não inventado.
|
|
23
|
+
|
|
24
|
+
| | escolha |
|
|
25
|
+
|---|---|
|
|
26
|
+
| fundo | cor ou textura; se anda, vai em `motion/src/_common.html`, no tempo do vídeo |
|
|
27
|
+
| paleta | 2 a 3 cores, com papel de cada uma |
|
|
28
|
+
| tipografia | Schibsted Grotesk, a sans padrão (`av-motion`); do estilo visual, corpos, pesos e tracking |
|
|
29
|
+
| curva de entrada | ex.: `cubic-bezier(0.22, 1, 0.36, 1)`, sem overshoot |
|
|
30
|
+
| entrada padrão | ex.: opacidade + 12 px de subida + desfoque de 3 px, 600 ms |
|
|
31
|
+
| som | a família de efeitos (ex.: cliques secos e um whoosh curto), quantos no vídeo e o termo de busca na Epidemic de cada um |
|
|
32
|
+
|
|
33
|
+
## Cenas
|
|
34
|
+
|
|
35
|
+
| cena | bloco | herói | o que está na tela |
|
|
36
|
+
|---|---|---|---|
|
|
37
|
+
| c01 | B1 | | |
|
|
38
|
+
| c02 | B2 | | |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## c01 · <título>
|
|
43
|
+
|
|
44
|
+
**Objetivo:** o que a cena comunica.
|
|
45
|
+
**Herói:** o único elemento em destaque total.
|
|
46
|
+
**Apoio:** o que entra e cede o palco.
|
|
47
|
+
|
|
48
|
+
<!-- Up to here, the motion script (stage 2), one block per scene. The
|
|
49
|
+
scenes' composition notes (composição, beats table, passagem) go to the
|
|
50
|
+
"Composição por cena" section, which tools/compose.mjs apply writes during
|
|
51
|
+
composition (stage 3); the Passagens section is written by the close call. -->
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Base da composição
|
|
56
|
+
|
|
57
|
+
<!-- Stage 3, written by the `base da composição` call before the scenes: what
|
|
58
|
+
motion/src/_common.html offers and the rules every scene fork follows. -->
|
|
59
|
+
|
|
60
|
+
| peça | o que é | como usar |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `--ink`, `--accent`… | paleta por papel | `color: var(--accent)` só no herói |
|
|
63
|
+
| `--ease-in`, `--dur-in` | a curva e a duração medidas no guia | toda entrada |
|
|
64
|
+
| `.card` | o cartão que se repete | `<div class="card">` |
|
|
65
|
+
| fundo | grão e gradiente no tempo do vídeo | já está em toda cena |
|
|
66
|
+
|
|
67
|
+
Regras: entradas em `--dur-in` com `--ease-in`, nada some para opacidade 0 no
|
|
68
|
+
meio da cena, a tela fica parada ≥ 600 ms antes do corte.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Passagens
|
|
73
|
+
|
|
74
|
+
Como cada cena entra a partir da anterior. Corte seco é escolha, não
|
|
75
|
+
esquecimento; o que continua leva `data-continues` nas duas cenas.
|
|
76
|
+
|
|
77
|
+
| corte | tipo | o que continua | como |
|
|
78
|
+
|---|---|---|---|
|
|
79
|
+
| c01 → c02 | continua | `fundo`, `card` | o card termina a c01 onde a c02 começa |
|
|
80
|
+
| c02 → c03 | corte | — | troca de assunto |
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Playbook do canal
|
|
2
|
+
|
|
3
|
+
O que o canal promete, os pilares e o que os números já mostraram. O
|
|
4
|
+
`av-script` lê antes de escrever; a análise de cada vídeo publicado atualiza.
|
|
5
|
+
Cada aprendizado diz quantos vídeos o sustentam: com menos de 5, é hipótese.
|
|
6
|
+
Números de `node tools/metrics.mjs show`.
|
|
7
|
+
|
|
8
|
+
## Promessa
|
|
9
|
+
|
|
10
|
+
Uma frase: o que quem segue ganha, vídeo após vídeo.
|
|
11
|
+
|
|
12
|
+
## Pilares
|
|
13
|
+
|
|
14
|
+
| pilar | o que é | objetivo mais comum |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| | | |
|
|
17
|
+
|
|
18
|
+
## O que cada métrica julga
|
|
19
|
+
|
|
20
|
+
| métrica | julga | pergunta que ela responde |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| pulo em 3 s | gancho: quadro 0 + primeira frase | parei de rolar? |
|
|
23
|
+
| % assistido | o miolo | valeu ficar? |
|
|
24
|
+
| compartilhamentos | o tema | mando isso para alguém? |
|
|
25
|
+
| salvos | a utilidade | vou querer rever? |
|
|
26
|
+
| comentários | o CTA | tenho motivo para falar? |
|
|
27
|
+
| visitas ao perfil e seguidores | a promessa do canal | quero mais disso? |
|
|
28
|
+
|
|
29
|
+
## Linha de base
|
|
30
|
+
|
|
31
|
+
As medianas do canal, para dizer se um vídeo foi acima ou abaixo. Compare
|
|
32
|
+
vídeos na mesma idade (marcos 24 h e 72 h do `metrics.json`).
|
|
33
|
+
|
|
34
|
+
| métrica | mediana | vídeos | de quando |
|
|
35
|
+
|---|---|---|---|
|
|
36
|
+
| pulo em 3 s | | | |
|
|
37
|
+
| % assistido | | | |
|
|
38
|
+
|
|
39
|
+
## Aprendizados
|
|
40
|
+
|
|
41
|
+
| # | hipótese | evidência | n | confiança | desde |
|
|
42
|
+
|---|---|---|---|---|---|
|
|
43
|
+
| | | | | baixa · média · alta | |
|