Node.js version

This commit is contained in:
2025-05-13 21:38:58 +02:00
commit f9cf455cf8
6 changed files with 443 additions and 0 deletions

3
base-node/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
dist/
node_modules/
mandelbrot.png

24
base-node/package.json Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "base-node",
"version": "1.0.0",
"description": "",
"type": "module",
"scripts": {
"dev": "tsc && node dist/main.js",
"build": "tsc",
"start": "node dist/main.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.10.0",
"dependencies": {
"canvas": "^3.1.0"
},
"devDependencies": {
"@tsconfig/node-ts": "^23.6.1",
"@tsconfig/node23": "^23.0.1",
"@types/node": "^22.15.17",
"typescript": "^5.8.3"
}
}

321
base-node/pnpm-lock.yaml generated Normal file
View File

@@ -0,0 +1,321 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
dependencies:
canvas:
specifier: ^3.1.0
version: 3.1.0
devDependencies:
'@tsconfig/node-ts':
specifier: ^23.6.1
version: 23.6.1
'@tsconfig/node23':
specifier: ^23.0.1
version: 23.0.1
'@types/node':
specifier: ^22.15.17
version: 22.15.17
typescript:
specifier: ^5.8.3
version: 5.8.3
packages:
'@tsconfig/node-ts@23.6.1':
resolution: {integrity: sha512-1E5cUp+S65pLKKI9VrGMQPWDHxOEq3dAGM2onG3fLeSRwWbylYFwhIjnzJikjSN7w2nCgwxmv8ifvUKDFkK38Q==}
'@tsconfig/node23@23.0.1':
resolution: {integrity: sha512-oJ0Y42TmsBLuLAfEbPTS5JXSbJJEEU4bULROS6zsL54Gdlw5aOy27rpsquotMKGf2auP6rkbfYsjl43WdGrNcg==}
'@types/node@22.15.17':
resolution: {integrity: sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==}
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
canvas@3.1.0:
resolution: {integrity: sha512-tTj3CqqukVJ9NgSahykNwtGda7V33VLObwrHfzT0vqJXu7J4d4C/7kQQW3fOEGDfZZoILPut5H00gOjyttPGyg==}
engines: {node: ^18.12.0 || >= 20.9.0}
chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
decompress-response@6.0.0:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
engines: {node: '>=10'}
deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
detect-libc@2.0.4:
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
engines: {node: '>=8'}
end-of-stream@1.4.4:
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
expand-template@2.0.3:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
mimic-response@3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
napi-build-utils@2.0.0:
resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
node-abi@3.75.0:
resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==}
engines: {node: '>=10'}
node-addon-api@7.1.1:
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
prebuild-install@7.1.3:
resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
engines: {node: '>=10'}
hasBin: true
pump@3.0.2:
resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
rc@1.2.8:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true
readable-stream@3.6.2:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'}
safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
semver@7.7.2:
resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
engines: {node: '>=10'}
hasBin: true
simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
simple-get@4.0.1:
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
tar-fs@2.1.2:
resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==}
tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
tunnel-agent@0.6.0:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
typescript@5.8.3:
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
engines: {node: '>=14.17'}
hasBin: true
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
snapshots:
'@tsconfig/node-ts@23.6.1': {}
'@tsconfig/node23@23.0.1': {}
'@types/node@22.15.17':
dependencies:
undici-types: 6.21.0
base64-js@1.5.1: {}
bl@4.1.0:
dependencies:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.2
buffer@5.7.1:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
canvas@3.1.0:
dependencies:
node-addon-api: 7.1.1
prebuild-install: 7.1.3
chownr@1.1.4: {}
decompress-response@6.0.0:
dependencies:
mimic-response: 3.1.0
deep-extend@0.6.0: {}
detect-libc@2.0.4: {}
end-of-stream@1.4.4:
dependencies:
once: 1.4.0
expand-template@2.0.3: {}
fs-constants@1.0.0: {}
github-from-package@0.0.0: {}
ieee754@1.2.1: {}
inherits@2.0.4: {}
ini@1.3.8: {}
mimic-response@3.1.0: {}
minimist@1.2.8: {}
mkdirp-classic@0.5.3: {}
napi-build-utils@2.0.0: {}
node-abi@3.75.0:
dependencies:
semver: 7.7.2
node-addon-api@7.1.1: {}
once@1.4.0:
dependencies:
wrappy: 1.0.2
prebuild-install@7.1.3:
dependencies:
detect-libc: 2.0.4
expand-template: 2.0.3
github-from-package: 0.0.0
minimist: 1.2.8
mkdirp-classic: 0.5.3
napi-build-utils: 2.0.0
node-abi: 3.75.0
pump: 3.0.2
rc: 1.2.8
simple-get: 4.0.1
tar-fs: 2.1.2
tunnel-agent: 0.6.0
pump@3.0.2:
dependencies:
end-of-stream: 1.4.4
once: 1.4.0
rc@1.2.8:
dependencies:
deep-extend: 0.6.0
ini: 1.3.8
minimist: 1.2.8
strip-json-comments: 2.0.1
readable-stream@3.6.2:
dependencies:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
safe-buffer@5.2.1: {}
semver@7.7.2: {}
simple-concat@1.0.1: {}
simple-get@4.0.1:
dependencies:
decompress-response: 6.0.0
once: 1.4.0
simple-concat: 1.0.1
string_decoder@1.3.0:
dependencies:
safe-buffer: 5.2.1
strip-json-comments@2.0.1: {}
tar-fs@2.1.2:
dependencies:
chownr: 1.1.4
mkdirp-classic: 0.5.3
pump: 3.0.2
tar-stream: 2.2.0
tar-stream@2.2.0:
dependencies:
bl: 4.1.0
end-of-stream: 1.4.4
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.2
tunnel-agent@0.6.0:
dependencies:
safe-buffer: 5.2.1
typescript@5.8.3: {}
undici-types@6.21.0: {}
util-deprecate@1.0.2: {}
wrappy@1.0.2: {}

View File

@@ -0,0 +1,2 @@
onlyBuiltDependencies:
- canvas

86
base-node/src/main.ts Normal file
View File

@@ -0,0 +1,86 @@
import { createCanvas } from 'canvas';
import { writeFileSync } from 'fs';
const WIDTH = 1024*2;
const HEIGHT = 1024*2;
const MAX_ITER = 1000;
const ZOOM = 0.8;
const X_CENTER = -0.75;
const Y_CENTER = 0.0;
// Converts HSV to RGB [0..1] input/output
function hsvToRgb(h: number, s: number, v: number): [number, number, number] {
let c = v * s;
let x = c * (1 - Math.abs(((h / 60) % 2) - 1));
let m = v - c;
let r = 0, g = 0, b = 0;
if (0 <= h && h < 60) [r, g, b] = [c, x, 0];
else if (60 <= h && h < 120) [r, g, b] = [x, c, 0];
else if (120 <= h && h < 180) [r, g, b] = [0, c, x];
else if (180 <= h && h < 240) [r, g, b] = [0, x, c];
else if (240 <= h && h < 300) [r, g, b] = [x, 0, c];
else if (300 <= h && h < 360) [r, g, b] = [c, 0, x];
return [
Math.round((r + m) * 255),
Math.round((g + m) * 255),
Math.round((b + m) * 255)
];
}
const canvas = createCanvas(WIDTH, HEIGHT);
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(WIDTH, HEIGHT);
const data = imageData.data;
const start = new Date();
for (let y = 0; y < HEIGHT; y++) {
for (let x = 0; x < WIDTH; x++) {
const cx = (x - WIDTH / 2) * (4 / WIDTH) * ZOOM + X_CENTER;
const cy = (y - HEIGHT / 2) * (4 / HEIGHT) * ZOOM + Y_CENTER;
let zx = 0, zy = 0;
let iter = 0;
while (zx * zx + zy * zy < 4 && iter < MAX_ITER) {
const tmp = zx * zx - zy * zy + cx;
zy = 2 * zx * zy + cy;
zx = tmp;
iter++;
}
// Smooth coloring
let pixelIndex = 4 * (y * WIDTH + x);
if (iter === MAX_ITER) {
// In set: black
data[pixelIndex + 0] = 0;
data[pixelIndex + 1] = 0;
data[pixelIndex + 2] = 0;
data[pixelIndex + 3] = 255;
} else {
// Smooth iteration count
let zn = Math.sqrt(zx * zx + zy * zy);
let nu = Math.log(Math.log(zn)) / Math.log(2);
let smoothIter = iter + 1 - nu;
// Color wheel! Vivid colors by wraparound on hue (try other formulas for variety)
let hue = 360 * smoothIter * smoothIter / MAX_ITER; // [0, 360]
let rgb = hsvToRgb(hue, 1, 1);
data[pixelIndex + 0] = rgb[0];
data[pixelIndex + 1] = rgb[1];
data[pixelIndex + 2] = rgb[2];
data[pixelIndex + 3] = 255;
}
}
}
const stop = new Date();
ctx.putImageData(imageData, 0, 0);
writeFileSync('mandelbrot.png', canvas.toBuffer('image/png'));
const doneSecs = (stop.getTime()-start.getTime())/1000;
console.log(`Done! in ${doneSecs} sec`);

7
base-node/tsconfig.json Normal file
View File

@@ -0,0 +1,7 @@
{
"extends": ["@tsconfig/node23/tsconfig.json", "@tsconfig/node-ts/tsconfig.json"],
"compilerOptions": {
"sourceMap": true,
"outDir": "dist"
},
}