Skip to content

Instantly share code, notes, and snippets.

@keevitaja
Created September 26, 2025 11:32
Show Gist options
  • Select an option

  • Save keevitaja/3a7a83fa2d97c60cedd427b21939ae5f to your computer and use it in GitHub Desktop.

Select an option

Save keevitaja/3a7a83fa2d97c60cedd427b21939ae5f to your computer and use it in GitHub Desktop.
#!/usr/bin/env node
/* Barnsley fern → PNG (Node.js + pngjs)
* Usage: node fern.js [width] [height] [iterations] [outfile]
*/
const fs = require("fs");
const { PNG } = require("pngjs");
const width = parseInt(process.argv[2] || "2000", 10);
const height = parseInt(process.argv[3] || "3000", 10);
const iters = parseInt(process.argv[4] || "3000000", 10);
const out = process.argv[5] || "fern.png";
// Barnsley fern koordinaadid (mahu kaardistamiseks)
const XMIN = -2.1820, XMAX = 2.6558;
const YMIN = 0.0, YMAX = 9.9983;
// Kaardistus maailmast pikslitesse (säilitab proportsiooni)
const sx = (width - 1) / (XMAX - XMIN);
const sy = (height - 1) / (YMAX - YMIN);
// Histogrammi puhvrid toonide jaoks
const counts = new Uint32Array(width * height);
// Algpunkt
let x = 0, y = 0;
// IFS transformatsioonid ja nende tõenäosused
for (let i = 0; i < iters; i++) {
const r = Math.random() * 100;
let xn, yn;
if (r < 1) {
// Tüvi
xn = 0;
yn = 0.16 * y;
} else if (r < 86) {
// Suur haru
xn = 0.85 * x + 0.04 * y;
yn = -0.04 * x + 0.85 * y + 1.6;
} else if (r < 93) {
// Väike haru 1
xn = 0.20 * x - 0.26 * y;
yn = 0.23 * x + 0.22 * y + 1.6;
} else {
// Väike haru 2
xn = -0.15 * x + 0.28 * y;
yn = 0.26 * x + 0.24 * y + 0.44;
}
x = xn; y = yn;
// Kaardista pikslisse (Y telg ekraanil alla)
const px = Math.round((x - XMIN) * sx);
const py = height - 1 - Math.round((y - YMIN) * sy);
if (px >= 0 && px < width && py >= 0 && py < height) {
counts[py * width + px]++;
}
}
// Leia max loendus normaliseerimiseks (kasuta log-skaalat detailide esiletõstmiseks)
let maxCount = 0;
for (let i = 0; i < counts.length; i++) {
if (counts[i] > maxCount) maxCount = counts[i];
}
// Värvi PNG: must taust, roheline leht (logaritmiline intensiivsus)
const png = new PNG({ width, height });
for (let i = 0; i < counts.length; i++) {
const c = counts[i];
const idx = i << 2; // *4
if (c === 0) {
// taust (must)
png.data[idx + 0] = 0;
png.data[idx + 1] = 0;
png.data[idx + 2] = 0;
png.data[idx + 3] = 255;
} else {
// log-normaliseerimine
const v = Math.log(1 + c) / Math.log(1 + maxCount); // 0..1
const g = Math.min(255, Math.floor(255 * v));
// pehme roheline; soovi korral muuda RGB-d
png.data[idx + 0] = Math.floor(g * 0.2); // R
png.data[idx + 1] = g; // G
png.data[idx + 2] = Math.floor(g * 0.3); // B
png.data[idx + 3] = 255; // A
}
}
// Kirjuta fail
png
.pack()
.pipe(fs.createWriteStream(out))
.on("finish", () => {
console.log(`OK: ${out} (${width}×${height}, ${iters.toLocaleString()} iteratsiooni)`);
})
.on("error", (e) => {
console.error("Kirjutamise viga:", e);
process.exit(1);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment