mirror of
https://github.com/motion-canvas/motion-canvas.git
synced 2026-01-11 06:48:12 -05:00
feat: browser based renderer
This commit is contained in:
11
package-lock.json
generated
11
package-lock.json
generated
@@ -9,6 +9,7 @@
|
||||
"version": "1.2.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/wicg-file-system-access": "^2020.9.5",
|
||||
"canvas": "^2.9.0",
|
||||
"image-size": "^1.0.1",
|
||||
"konva": "^8.3.2",
|
||||
@@ -239,6 +240,11 @@
|
||||
"integrity": "sha512-D8AoV7h2kbCfrv/DcebHOFh1WDwyus3HdooBkAwcBikXArdqnsQ38PQ85JCunnvun160oA9jz53GszF3zch3tg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/wicg-file-system-access": {
|
||||
"version": "2020.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/wicg-file-system-access/-/wicg-file-system-access-2020.9.5.tgz",
|
||||
"integrity": "sha512-UYK244awtmcUYQfs7FR8710MJcefL2WvkyHMjA8yJzxd1mo0Gfn88sRZ1Bls7hiUhA2w7ne1gpJ9T5g3G0wOyA=="
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz",
|
||||
@@ -4400,6 +4406,11 @@
|
||||
"integrity": "sha512-D8AoV7h2kbCfrv/DcebHOFh1WDwyus3HdooBkAwcBikXArdqnsQ38PQ85JCunnvun160oA9jz53GszF3zch3tg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/wicg-file-system-access": {
|
||||
"version": "2020.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/wicg-file-system-access/-/wicg-file-system-access-2020.9.5.tgz",
|
||||
"integrity": "sha512-UYK244awtmcUYQfs7FR8710MJcefL2WvkyHMjA8yJzxd1mo0Gfn88sRZ1Bls7hiUhA2w7ne1gpJ9T5g3G0wOyA=="
|
||||
},
|
||||
"@types/ws": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz",
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
"prepare": "npm run build",
|
||||
"build": "tsc",
|
||||
"test:serve": "node ./tools/serve.mjs ./test/player.ts",
|
||||
"test:render": "node ./tools/render.mjs ./test/render.ts",
|
||||
"test:render": "node ./tools/serve.mjs ./test/render.ts",
|
||||
"test:image": "node ./tools/image.mjs ./test/img ./test/animations.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/wicg-file-system-access": "^2020.9.5",
|
||||
"canvas": "^2.9.0",
|
||||
"image-size": "^1.0.1",
|
||||
"konva": "^8.3.2",
|
||||
|
||||
@@ -1,25 +1,38 @@
|
||||
import type {Project} from './Project';
|
||||
import {Util} from 'konva/lib/Util';
|
||||
|
||||
export const Renderer =
|
||||
(factory: () => Project) => (createCanvas: any, Image: any) => {
|
||||
Util.createCanvasElement = () => {
|
||||
const node = createCanvas(300, 300);
|
||||
const monkey = node.getContext;
|
||||
node.getContext = (type: string, options: Record<any, any>) => {
|
||||
return monkey.call(node, type, {
|
||||
...options,
|
||||
pixelFormat: 'RGB30',
|
||||
});
|
||||
};
|
||||
if (!node['style']) {
|
||||
node['style'] = {};
|
||||
}
|
||||
return node;
|
||||
};
|
||||
Util.createImageElement = () => {
|
||||
return new Image();
|
||||
};
|
||||
export const Renderer = (factory: () => Project) => {
|
||||
document.addEventListener('click', () =>
|
||||
render(factory()).catch(console.error),
|
||||
);
|
||||
};
|
||||
|
||||
return factory();
|
||||
};
|
||||
async function render(project: Project) {
|
||||
let totalSize = 0;
|
||||
const startTime = Date.now();
|
||||
|
||||
project.start();
|
||||
const directory = await window.showDirectoryPicker();
|
||||
|
||||
while (!(await project.next())) {
|
||||
project.draw();
|
||||
const name = project.frame.toString().padStart(6, '0');
|
||||
const content = await new Promise<Blob>(resolve => project.toCanvas().toBlob(resolve, 'image/png'));
|
||||
const size = (content.size) / 1024;
|
||||
totalSize += size;
|
||||
|
||||
const file = await directory.getFileHandle(`frame-${name}.png`, {
|
||||
create: true,
|
||||
});
|
||||
const stream = await file.createWritable();
|
||||
await stream.write(content);
|
||||
await stream.close();
|
||||
|
||||
console.log(
|
||||
`Frame: ${name}, Size: ${Math.round(size)} kB, Total: ${Math.round(
|
||||
totalSize,
|
||||
)} kB, Elapsed: ${Math.round((Date.now() - startTime) / 1000)}`,
|
||||
);
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import 'konva';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import webpack from 'webpack';
|
||||
import {fileURLToPath} from 'url';
|
||||
import canvas from 'canvas';
|
||||
const {createCanvas, Image} = canvas;
|
||||
|
||||
const projectFile = path.resolve(process.cwd(), process.argv[2]);
|
||||
const output = path.resolve(process.cwd(), process.argv[3] ?? 'output');
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const isLinked = !__dirname.includes('node_modules');
|
||||
|
||||
fs.mkdirSync(output, {recursive: true});
|
||||
|
||||
function build(entry) {
|
||||
return new Promise((resolve, reject) => {
|
||||
webpack(
|
||||
{
|
||||
entry,
|
||||
devtool: false,
|
||||
mode: 'development',
|
||||
target: 'node',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
loader: 'ts-loader',
|
||||
exclude: /node_modules([\\]+|\/)+(?!@aarthificial)/,
|
||||
options: {
|
||||
allowTsInNodeModules: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.ts', '.tsx'],
|
||||
alias: {
|
||||
MC: path.resolve(__dirname, isLinked ? '../src' : '../dist'),
|
||||
},
|
||||
},
|
||||
output: {
|
||||
filename: `result.js`,
|
||||
path: output,
|
||||
library: {
|
||||
type: 'commonjs-module',
|
||||
},
|
||||
},
|
||||
},
|
||||
(error, stats) => {
|
||||
if (error || stats.hasErrors()) {
|
||||
reject(error || stats);
|
||||
}
|
||||
resolve();
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
(async () => {
|
||||
await build(projectFile);
|
||||
const setup = await import(
|
||||
/* webpackIgnore: true */
|
||||
`file://${path.join(output, 'result.js')}`
|
||||
);
|
||||
|
||||
let totalSize = 0;
|
||||
const startTime = Date.now();
|
||||
const project = setup.default.default(createCanvas, Image);
|
||||
project.start();
|
||||
while (!project.next()) {
|
||||
project.draw();
|
||||
const name = String(project.frame).padStart(6, '0');
|
||||
const content = project.toDataURL().replace(/^data:image\/png;base64,/, '');
|
||||
const size = (content.length * 2) / 1024;
|
||||
totalSize += size;
|
||||
|
||||
fs.writeFileSync(path.resolve(output, `frame-${name}.png`), content, {
|
||||
encoding: 'base64',
|
||||
});
|
||||
process.stdout.clearLine(0);
|
||||
process.stdout.cursorTo(0);
|
||||
process.stdout.write(
|
||||
`Frame: ${name}, Size: ${Math.round(size)} kB, Total: ${Math.round(
|
||||
totalSize,
|
||||
)} kB, Elapsed: ${Math.round((Date.now() - startTime) / 1000)}`,
|
||||
);
|
||||
}
|
||||
})().catch(console.error);
|
||||
Reference in New Issue
Block a user