diff --git a/docs/components/Sandbox.vue b/docs/components/Sandbox.vue index 1b17301..a5397b8 100644 --- a/docs/components/Sandbox.vue +++ b/docs/components/Sandbox.vue @@ -84,10 +84,14 @@ watch( ) const keys = useMagicKeys() -const exportKey = keys.shift_cmd_e -whenever(exportKey, async () => { + +whenever(keys.cmd_control_e, async () => { const {exportVideo} = await import('./exportVideo') + exportVideo(code.value, true) +}) +whenever(keys.shift_cmd_e, async () => { + const {exportVideo} = await import('./exportVideo') exportVideo(code.value) }) diff --git a/docs/components/exportVideo.ts b/docs/components/exportVideo.ts index 3fe39fa..c8df03f 100644 --- a/docs/components/exportVideo.ts +++ b/docs/components/exportVideo.ts @@ -4,7 +4,32 @@ import saferEval from 'safer-eval' import {createDrawFunction, setupEvalContextCreator} from './createDrawFunction' -export async function exportVideo(code: string) { +export async function exportVideo(code: string, onlyCanvas = false) { + console.info('Start rendering video onlyCanvas:', onlyCanvas) + + const now = new Date() + const defaultBasename: string | null = + [now.getFullYear(), now.getMonth() + 1, now.getDate()] + .map(n => n.toString().padStart(2, '0')) + .join('-') + + '_' + + [now.getHours(), now.getMinutes()] + .map(n => n.toString().padStart(2, '0')) + .join('-') + + const promptResult = prompt('Export settings', defaultBasename + ':2') + + if (!promptResult) { + return + } + + // Parse prompt result + const [basename, durationStr] = promptResult.split(':') + const filename = `Pave_${basename}.webm` + const duration = parseFloat(durationStr) + const frameCount = 50 * duration + + // Load dependencies const monaco = await import('monaco-editor') const {default: domtoimage} = await import('dom-to-image-more') @@ -37,52 +62,49 @@ export async function exportVideo(code: string) { const frames: string[] = [] - const duration = 2 - - const frameCount = 50 * duration - for (let i = 0; i < frameCount; i++) { const time = i / frameCount - evalFn(time) - - videoContext.clearRect(0, 0, 1920, 1080) - videoContext.fillStyle = 'white' - videoContext.fillRect(0, 0, 1920, 1080) - videoContext.fillStyle = 'black' - - const codeImg = await renderCode(code, time) - - const codeWidth = 1920 - 1080 - 40 - const codeHeight = codeImg.height * (codeWidth / codeImg.width) - videoContext.drawImage( - codeImg, - 1080, - (1080 - codeHeight) / 2, - codeWidth, - codeHeight - ) - - const canvasTop = 40 - const canvasBottom = 1080 - 40 - const canvasLeft = 40 - const canvasRight = 1040 - - videoContext.strokeStyle = '#ccc' - videoContext.beginPath() - for (let i = 0; i <= 10; i++) { - videoContext.moveTo(canvasLeft + i * 100, canvasTop) - videoContext.lineTo(canvasLeft + i * 100, canvasBottom) - videoContext.moveTo(canvasLeft, canvasTop + i * 100) - videoContext.lineTo(canvasRight, canvasTop + i * 100) + if (!onlyCanvas) { + videoContext.clearRect(0, 0, 1920, 1080) + videoContext.fillStyle = 'white' + videoContext.fillRect(0, 0, 1920, 1080) + videoContext.fillStyle = 'black' + + const codeImg = await renderCode(code, time) + + const codeWidth = 1920 - 1080 - 40 + const codeHeight = codeImg.height * (codeWidth / codeImg.width) + videoContext.drawImage( + codeImg, + 1080, + (1080 - codeHeight) / 2, + codeWidth, + codeHeight + ) + + const canvasTop = 40 + const canvasBottom = 1080 - 40 + const canvasLeft = 40 + const canvasRight = 1040 + + videoContext.strokeStyle = '#ccc' + videoContext.beginPath() + for (let i = 0; i <= 10; i++) { + videoContext.moveTo(canvasLeft + i * 100, canvasTop) + videoContext.lineTo(canvasLeft + i * 100, canvasBottom) + videoContext.moveTo(canvasLeft, canvasTop + i * 100) + videoContext.lineTo(canvasRight, canvasTop + i * 100) + } + videoContext.stroke() } - videoContext.stroke() evalFn(time) videoContext.drawImage(canvas, 40, 40, 1000, 1000) const frame = await new Promise((resolve, reject) => { - videoCanvas.toBlob(blob => { + const targetCanvas = onlyCanvas ? canvas : videoCanvas + targetCanvas.toBlob(blob => { if (blob) { resolve(URL.createObjectURL(blob)) } else { @@ -120,7 +142,12 @@ export async function exportVideo(code: string) { capturer.stop() - capturer.save() + capturer.save(blob => { + const a = document.createElement('a') + a.href = URL.createObjectURL(blob) + a.download = filename + a.click() + }) async function renderCode( code: string,