feat: browser based renderer

This commit is contained in:
aarthificial
2022-03-30 00:16:34 +02:00
parent 754fa6d27d
commit 13dc24ca69
4 changed files with 48 additions and 114 deletions

11
package-lock.json generated
View File

@@ -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",

View File

@@ -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",

View File

@@ -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));
}
}

View File

@@ -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);