Split renderer bundles by feature
This commit is contained in:
1 parent
7bf18636d6
commit
fa8c52b239
3 files changed
+85
-15
No files matched your search
+2
-2
@@ -28,7 +28,6 @@ import ClipartDrawer from './components/ClipartDrawer.vue'
|
|||||||
import SceneDrawer from './components/SceneDrawer.vue'
|
import SceneDrawer from './components/SceneDrawer.vue'
|
||||||
import DocumentDrawer from './components/DocumentDrawer.vue'
|
import DocumentDrawer from './components/DocumentDrawer.vue'
|
||||||
import DocumentSettings from './components/DocumentSettings.vue'
|
import DocumentSettings from './components/DocumentSettings.vue'
|
||||||
import ExportDialog from './components/ExportDialog.vue'
|
|
||||||
import FullscreenPreview from './components/FullscreenPreview.vue'
|
import FullscreenPreview from './components/FullscreenPreview.vue'
|
||||||
import PropertiesPanel from './components/PropertiesPanel.vue'
|
import PropertiesPanel from './components/PropertiesPanel.vue'
|
||||||
import SvgLayerPanel from './components/SvgLayerPanel.vue'
|
import SvgLayerPanel from './components/SvgLayerPanel.vue'
|
||||||
@@ -46,7 +45,6 @@ import { usePlaybackLoop } from './composables/usePlaybackLoop'
|
|||||||
import { useTimeFormat } from './composables/useTimeFormat'
|
import { useTimeFormat } from './composables/useTimeFormat'
|
||||||
import { useProjectName } from './composables/useProjectName'
|
import { useProjectName } from './composables/useProjectName'
|
||||||
import { shouldChromeClickDeselect } from './lib/chromeClick'
|
import { shouldChromeClickDeselect } from './lib/chromeClick'
|
||||||
import { renderSceneToStillImage } from './lib/stillImageExport'
|
|
||||||
import { ProjectFileError, pickProjectFile } from './lib/projectFile'
|
import { ProjectFileError, pickProjectFile } from './lib/projectFile'
|
||||||
import { readAnyProjectFile } from './lib/ruwFile'
|
import { readAnyProjectFile } from './lib/ruwFile'
|
||||||
import {
|
import {
|
||||||
@@ -73,6 +71,7 @@ const helpOpen = ref(false)
|
|||||||
const TestOverlay = import.meta.env.DEV
|
const TestOverlay = import.meta.env.DEV
|
||||||
? defineAsyncComponent(() => import('./devtools/TestOverlay.vue'))
|
? defineAsyncComponent(() => import('./devtools/TestOverlay.vue'))
|
||||||
: null
|
: null
|
||||||
|
const ExportDialog = defineAsyncComponent(() => import('./components/ExportDialog.vue'))
|
||||||
const TIMELINE_HEIGHT_KEY = 'animatr:timelineHeight'
|
const TIMELINE_HEIGHT_KEY = 'animatr:timelineHeight'
|
||||||
const DEFAULT_TIMELINE_HEIGHT = 220
|
const DEFAULT_TIMELINE_HEIGHT = 220
|
||||||
const MIN_TIMELINE_HEIGHT = 120
|
const MIN_TIMELINE_HEIGHT = 120
|
||||||
@@ -313,6 +312,7 @@ async function copyStillToClipboard() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
const { renderSceneToStillImage } = await import('./lib/stillImageExport')
|
||||||
const scene = JSON.parse(JSON.stringify(store.scene))
|
const scene = JSON.parse(JSON.stringify(store.scene))
|
||||||
const blob = await renderSceneToStillImage(scene, store.playhead, 'png')
|
const blob = await renderSceneToStillImage(scene, store.playhead, 'png')
|
||||||
// ClipboardItem is widely available in modern Chromium / Firefox
|
// ClipboardItem is widely available in modern Chromium / Firefox
|
||||||
|
|||||||
@@ -12,14 +12,6 @@ import {
|
|||||||
PhGif,
|
PhGif,
|
||||||
} from '@phosphor-icons/vue'
|
} from '@phosphor-icons/vue'
|
||||||
import { useSceneStore } from '@/stores/scene'
|
import { useSceneStore } from '@/stores/scene'
|
||||||
import { downloadExampleHtml, downloadRuntime, downloadSceneExport } from '@/lib/exportPlayer'
|
|
||||||
import { downloadSceneAsVideo, pickMimeType } from '@/lib/videoExport'
|
|
||||||
import { downloadSceneAsGif } from '@/lib/gifExport'
|
|
||||||
import { downloadSceneAsApng, downloadSceneAsApngPreview } from '@/lib/apngExport'
|
|
||||||
import { hasDesktopRender, renderMp4OnDesktop } from '@/lib/desktopRenderExport'
|
|
||||||
import { downloadFromServer } from '@/lib/serverExport'
|
|
||||||
import { downloadRuwFile } from '@/lib/ruwFile'
|
|
||||||
import { downloadSceneAsStillImage } from '@/lib/stillImageExport'
|
|
||||||
import { useProjectName } from '@/composables/useProjectName'
|
import { useProjectName } from '@/composables/useProjectName'
|
||||||
import type { ButtonAsset, Layer } from '@/types/scene'
|
import type { ButtonAsset, Layer } from '@/types/scene'
|
||||||
import { Modal } from '@/components/ui'
|
import { Modal } from '@/components/ui'
|
||||||
@@ -39,7 +31,20 @@ interface ProgressState {
|
|||||||
}
|
}
|
||||||
const progress = ref<ProgressState | null>(null)
|
const progress = ref<ProgressState | null>(null)
|
||||||
|
|
||||||
const videoSupported = pickMimeType() !== null
|
const VIDEO_MIME_CANDIDATES = [
|
||||||
|
'video/webm;codecs=vp9',
|
||||||
|
'video/webm;codecs=vp8',
|
||||||
|
'video/webm',
|
||||||
|
'video/mp4;codecs=h264',
|
||||||
|
'video/mp4',
|
||||||
|
]
|
||||||
|
|
||||||
|
function canRecordVideo(): boolean {
|
||||||
|
if (typeof MediaRecorder === 'undefined') return false
|
||||||
|
return VIDEO_MIME_CANDIDATES.some((mime) => MediaRecorder.isTypeSupported?.(mime))
|
||||||
|
}
|
||||||
|
|
||||||
|
const videoSupported = canRecordVideo()
|
||||||
|
|
||||||
// Opt-in: strip layers that are hidden in the editor (`editorHidden`)
|
// Opt-in: strip layers that are hidden in the editor (`editorHidden`)
|
||||||
// from the exported scene. Default off — editor-hide is a workflow
|
// from the exported scene. Default off — editor-hide is a workflow
|
||||||
@@ -198,17 +203,20 @@ function activeSceneClone() {
|
|||||||
return scene
|
return scene
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportScene() {
|
async function exportScene() {
|
||||||
|
const { downloadSceneExport } = await import('@/lib/exportPlayer')
|
||||||
downloadSceneExport(projectClone())
|
downloadSceneExport(projectClone())
|
||||||
emit('update:modelValue', false)
|
emit('update:modelValue', false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportRuntime() {
|
async function exportRuntime() {
|
||||||
|
const { downloadRuntime } = await import('@/lib/exportPlayer')
|
||||||
downloadRuntime()
|
downloadRuntime()
|
||||||
emit('update:modelValue', false)
|
emit('update:modelValue', false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportRuwBundle() {
|
async function exportRuwBundle() {
|
||||||
|
const { downloadRuwFile } = await import('@/lib/ruwFile')
|
||||||
// Re-import target: .ruw is the round-trippable format the welcome
|
// Re-import target: .ruw is the round-trippable format the welcome
|
||||||
// dialog + file-picker accept. Pull the project via projectForSave
|
// dialog + file-picker accept. Pull the project via projectForSave
|
||||||
// so the editor-session UI state (zoom, toggles, …) rides along.
|
// so the editor-session UI state (zoom, toggles, …) rides along.
|
||||||
@@ -219,7 +227,8 @@ function exportRuwBundle() {
|
|||||||
emit('update:modelValue', false)
|
emit('update:modelValue', false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportHtml() {
|
async function exportHtml() {
|
||||||
|
const { downloadExampleHtml } = await import('@/lib/exportPlayer')
|
||||||
downloadExampleHtml(projectClone())
|
downloadExampleHtml(projectClone())
|
||||||
emit('update:modelValue', false)
|
emit('update:modelValue', false)
|
||||||
}
|
}
|
||||||
@@ -234,6 +243,7 @@ async function exportStillImage(format: 'png' | 'jpg') {
|
|||||||
const opts = targetSizeChanged.value
|
const opts = targetSizeChanged.value
|
||||||
? { targetWidth: targetWidth.value, targetHeight: targetHeight.value }
|
? { targetWidth: targetWidth.value, targetHeight: targetHeight.value }
|
||||||
: undefined
|
: undefined
|
||||||
|
const { downloadSceneAsStillImage } = await import('@/lib/stillImageExport')
|
||||||
await downloadSceneAsStillImage(
|
await downloadSceneAsStillImage(
|
||||||
activeSceneClone(),
|
activeSceneClone(),
|
||||||
store.playhead,
|
store.playhead,
|
||||||
@@ -255,6 +265,7 @@ async function exportWebm() {
|
|||||||
}
|
}
|
||||||
store.pause()
|
store.pause()
|
||||||
try {
|
try {
|
||||||
|
const { downloadSceneAsVideo } = await import('@/lib/videoExport')
|
||||||
await downloadSceneAsVideo(activeSceneClone(), {
|
await downloadSceneAsVideo(activeSceneClone(), {
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
onProgress: (p) => {
|
onProgress: (p) => {
|
||||||
@@ -283,6 +294,7 @@ async function exportGif() {
|
|||||||
}
|
}
|
||||||
store.pause()
|
store.pause()
|
||||||
try {
|
try {
|
||||||
|
const { downloadSceneAsGif } = await import('@/lib/gifExport')
|
||||||
await downloadSceneAsGif(
|
await downloadSceneAsGif(
|
||||||
activeSceneClone(),
|
activeSceneClone(),
|
||||||
frameExportOpts(controller, (p) => {
|
frameExportOpts(controller, (p) => {
|
||||||
@@ -311,6 +323,7 @@ async function exportApng() {
|
|||||||
}
|
}
|
||||||
store.pause()
|
store.pause()
|
||||||
try {
|
try {
|
||||||
|
const { downloadSceneAsApng } = await import('@/lib/apngExport')
|
||||||
await downloadSceneAsApng(
|
await downloadSceneAsApng(
|
||||||
activeSceneClone(),
|
activeSceneClone(),
|
||||||
frameExportOpts(controller, (p) => {
|
frameExportOpts(controller, (p) => {
|
||||||
@@ -339,6 +352,7 @@ async function exportApngPreview() {
|
|||||||
}
|
}
|
||||||
store.pause()
|
store.pause()
|
||||||
try {
|
try {
|
||||||
|
const { downloadSceneAsApngPreview } = await import('@/lib/apngExport')
|
||||||
await downloadSceneAsApngPreview(
|
await downloadSceneAsApngPreview(
|
||||||
activeSceneClone(),
|
activeSceneClone(),
|
||||||
frameExportOpts(controller, (p) => {
|
frameExportOpts(controller, (p) => {
|
||||||
@@ -370,6 +384,7 @@ async function exportMp4Server() {
|
|||||||
store.pause()
|
store.pause()
|
||||||
try {
|
try {
|
||||||
const scene = activeSceneClone()
|
const scene = activeSceneClone()
|
||||||
|
const { hasDesktopRender, renderMp4OnDesktop } = await import('@/lib/desktopRenderExport')
|
||||||
if (hasDesktopRender()) {
|
if (hasDesktopRender()) {
|
||||||
const result = await renderMp4OnDesktop(scene, {
|
const result = await renderMp4OnDesktop(scene, {
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
@@ -384,6 +399,7 @@ async function exportMp4Server() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const { downloadFromServer } = await import('@/lib/serverExport')
|
||||||
await downloadFromServer(scene, {
|
await downloadFromServer(scene, {
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
fps: targetFps.value,
|
fps: targetFps.value,
|
||||||
|
|||||||
@@ -5,6 +5,60 @@ import { fileURLToPath, URL } from 'node:url'
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
base: './',
|
base: './',
|
||||||
plugins: [vue()],
|
plugins: [vue()],
|
||||||
|
build: {
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
manualChunks(id) {
|
||||||
|
if (id.includes('/src/i18n/')) return 'i18n'
|
||||||
|
if (
|
||||||
|
id.includes('/src/components/CanvasStage.vue') ||
|
||||||
|
id.includes('/src/components/AssetSidebar.vue') ||
|
||||||
|
id.includes('/src/components/PropertiesPanel.vue') ||
|
||||||
|
id.includes('/src/components/ActionEditor.vue') ||
|
||||||
|
id.includes('/src/components/FontPicker.vue') ||
|
||||||
|
id.includes('/src/components/RangeSlider.vue') ||
|
||||||
|
id.includes('/src/components/SvgLayerPanel.vue') ||
|
||||||
|
id.includes('/src/stores/scene.ts') ||
|
||||||
|
id.includes('/src/types/scene.ts') ||
|
||||||
|
id.includes('/src/lib/render.ts') ||
|
||||||
|
id.includes('/src/lib/interpolate.ts') ||
|
||||||
|
id.includes('/src/lib/wiggle.ts') ||
|
||||||
|
id.includes('/src/lib/kaleido.ts') ||
|
||||||
|
id.includes('/src/lib/clipBounds.ts') ||
|
||||||
|
id.includes('/src/lib/actions.ts') ||
|
||||||
|
id.includes('/src/lib/sceneOrder.ts') ||
|
||||||
|
id.includes('/src/composables/useButtonRuntime.ts')
|
||||||
|
) {
|
||||||
|
return 'editor'
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
id.includes('/src/components/Timeline.vue') ||
|
||||||
|
id.includes('/src/lib/timelineSnap.ts') ||
|
||||||
|
id.includes('/src/composables/useAudioWaveform.ts')
|
||||||
|
) {
|
||||||
|
return 'timeline'
|
||||||
|
}
|
||||||
|
if (!id.includes('/node_modules/')) return undefined
|
||||||
|
if (id.includes('/@phosphor-icons/vue/')) return 'icons'
|
||||||
|
if (id.includes('/konva/') || id.includes('/vue-konva/')) return 'canvas'
|
||||||
|
if (
|
||||||
|
id.includes('/gifenc/') ||
|
||||||
|
id.includes('/upng-js/')
|
||||||
|
) {
|
||||||
|
return 'encoders'
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
id.includes('/vue/') ||
|
||||||
|
id.includes('/@vue/') ||
|
||||||
|
id.includes('/pinia/')
|
||||||
|
) {
|
||||||
|
return 'framework'
|
||||||
|
}
|
||||||
|
return 'vendor'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
server: {
|
server: {
|
||||||
port: 5200,
|
port: 5200,
|
||||||
|
|||||||
Reference in new issue
Block a user