mandelbrot: adding a simple version of mandelbrot

This commit is contained in:
Sheldan
2026-02-04 20:06:25 +01:00
parent ef162a7dc2
commit 0cd89ad975
6 changed files with 519 additions and 1 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/dist/
.idea
.idea
/**/node_modules/

377
mandelbrot/package-lock.json generated Normal file
View File

@@ -0,0 +1,377 @@
{
"name": "mandel-brot",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "mandel-brot",
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"canvas-common": "file:../canvas-common"
},
"devDependencies": {
"vite": "^5.1.5"
}
},
"../canvas-common": {
"version": "1.0.0",
"license": "MIT"
},
"node_modules/@esbuild/linux-x64": {
"version": "0.21.5",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.54.0",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.54.0",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@types/estree": {
"version": "1.0.8",
"dev": true,
"license": "MIT"
},
"node_modules/canvas-common": {
"resolved": "../canvas-common",
"link": true
},
"node_modules/esbuild": {
"version": "0.21.5",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.21.5",
"@esbuild/android-arm": "0.21.5",
"@esbuild/android-arm64": "0.21.5",
"@esbuild/android-x64": "0.21.5",
"@esbuild/darwin-arm64": "0.21.5",
"@esbuild/darwin-x64": "0.21.5",
"@esbuild/freebsd-arm64": "0.21.5",
"@esbuild/freebsd-x64": "0.21.5",
"@esbuild/linux-arm": "0.21.5",
"@esbuild/linux-arm64": "0.21.5",
"@esbuild/linux-ia32": "0.21.5",
"@esbuild/linux-loong64": "0.21.5",
"@esbuild/linux-mips64el": "0.21.5",
"@esbuild/linux-ppc64": "0.21.5",
"@esbuild/linux-riscv64": "0.21.5",
"@esbuild/linux-s390x": "0.21.5",
"@esbuild/linux-x64": "0.21.5",
"@esbuild/netbsd-x64": "0.21.5",
"@esbuild/openbsd-x64": "0.21.5",
"@esbuild/sunos-x64": "0.21.5",
"@esbuild/win32-arm64": "0.21.5",
"@esbuild/win32-ia32": "0.21.5",
"@esbuild/win32-x64": "0.21.5"
}
},
"node_modules/nanoid": {
"version": "3.3.11",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"dev": true,
"license": "ISC"
},
"node_modules/postcss": {
"version": "8.5.6",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/rollup": {
"version": "4.54.0",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.8"
},
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.54.0",
"@rollup/rollup-android-arm64": "4.54.0",
"@rollup/rollup-darwin-arm64": "4.54.0",
"@rollup/rollup-darwin-x64": "4.54.0",
"@rollup/rollup-freebsd-arm64": "4.54.0",
"@rollup/rollup-freebsd-x64": "4.54.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.54.0",
"@rollup/rollup-linux-arm-musleabihf": "4.54.0",
"@rollup/rollup-linux-arm64-gnu": "4.54.0",
"@rollup/rollup-linux-arm64-musl": "4.54.0",
"@rollup/rollup-linux-loong64-gnu": "4.54.0",
"@rollup/rollup-linux-ppc64-gnu": "4.54.0",
"@rollup/rollup-linux-riscv64-gnu": "4.54.0",
"@rollup/rollup-linux-riscv64-musl": "4.54.0",
"@rollup/rollup-linux-s390x-gnu": "4.54.0",
"@rollup/rollup-linux-x64-gnu": "4.54.0",
"@rollup/rollup-linux-x64-musl": "4.54.0",
"@rollup/rollup-openharmony-arm64": "4.54.0",
"@rollup/rollup-win32-arm64-msvc": "4.54.0",
"@rollup/rollup-win32-ia32-msvc": "4.54.0",
"@rollup/rollup-win32-x64-gnu": "4.54.0",
"@rollup/rollup-win32-x64-msvc": "4.54.0",
"fsevents": "~2.3.2"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/vite": {
"version": "5.4.21",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.21.3",
"postcss": "^8.4.43",
"rollup": "^4.20.0"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
"node": "^18.0.0 || >=20.0.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
},
"optionalDependencies": {
"fsevents": "~2.3.3"
},
"peerDependencies": {
"@types/node": "^18.0.0 || >=20.0.0",
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
"sass-embedded": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"less": {
"optional": true
},
"lightningcss": {
"optional": true
},
"sass": {
"optional": true
},
"sass-embedded": {
"optional": true
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
}
}
}
},
"dependencies": {
"@esbuild/linux-x64": {
"version": "0.21.5",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-x64-gnu": {
"version": "4.54.0",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-x64-musl": {
"version": "4.54.0",
"dev": true,
"optional": true
},
"@types/estree": {
"version": "1.0.8",
"dev": true
},
"canvas-common": {
"version": "file:../canvas-common"
},
"esbuild": {
"version": "0.21.5",
"dev": true,
"requires": {
"@esbuild/aix-ppc64": "0.21.5",
"@esbuild/android-arm": "0.21.5",
"@esbuild/android-arm64": "0.21.5",
"@esbuild/android-x64": "0.21.5",
"@esbuild/darwin-arm64": "0.21.5",
"@esbuild/darwin-x64": "0.21.5",
"@esbuild/freebsd-arm64": "0.21.5",
"@esbuild/freebsd-x64": "0.21.5",
"@esbuild/linux-arm": "0.21.5",
"@esbuild/linux-arm64": "0.21.5",
"@esbuild/linux-ia32": "0.21.5",
"@esbuild/linux-loong64": "0.21.5",
"@esbuild/linux-mips64el": "0.21.5",
"@esbuild/linux-ppc64": "0.21.5",
"@esbuild/linux-riscv64": "0.21.5",
"@esbuild/linux-s390x": "0.21.5",
"@esbuild/linux-x64": "0.21.5",
"@esbuild/netbsd-x64": "0.21.5",
"@esbuild/openbsd-x64": "0.21.5",
"@esbuild/sunos-x64": "0.21.5",
"@esbuild/win32-arm64": "0.21.5",
"@esbuild/win32-ia32": "0.21.5",
"@esbuild/win32-x64": "0.21.5"
}
},
"nanoid": {
"version": "3.3.11",
"dev": true
},
"picocolors": {
"version": "1.1.1",
"dev": true
},
"postcss": {
"version": "8.5.6",
"dev": true,
"requires": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
}
},
"rollup": {
"version": "4.54.0",
"dev": true,
"requires": {
"@rollup/rollup-android-arm-eabi": "4.54.0",
"@rollup/rollup-android-arm64": "4.54.0",
"@rollup/rollup-darwin-arm64": "4.54.0",
"@rollup/rollup-darwin-x64": "4.54.0",
"@rollup/rollup-freebsd-arm64": "4.54.0",
"@rollup/rollup-freebsd-x64": "4.54.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.54.0",
"@rollup/rollup-linux-arm-musleabihf": "4.54.0",
"@rollup/rollup-linux-arm64-gnu": "4.54.0",
"@rollup/rollup-linux-arm64-musl": "4.54.0",
"@rollup/rollup-linux-loong64-gnu": "4.54.0",
"@rollup/rollup-linux-ppc64-gnu": "4.54.0",
"@rollup/rollup-linux-riscv64-gnu": "4.54.0",
"@rollup/rollup-linux-riscv64-musl": "4.54.0",
"@rollup/rollup-linux-s390x-gnu": "4.54.0",
"@rollup/rollup-linux-x64-gnu": "4.54.0",
"@rollup/rollup-linux-x64-musl": "4.54.0",
"@rollup/rollup-openharmony-arm64": "4.54.0",
"@rollup/rollup-win32-arm64-msvc": "4.54.0",
"@rollup/rollup-win32-ia32-msvc": "4.54.0",
"@rollup/rollup-win32-x64-gnu": "4.54.0",
"@rollup/rollup-win32-x64-msvc": "4.54.0",
"@types/estree": "1.0.8",
"fsevents": "~2.3.2"
}
},
"source-map-js": {
"version": "1.2.1",
"dev": true
},
"vite": {
"version": "5.4.21",
"dev": true,
"requires": {
"esbuild": "^0.21.3",
"fsevents": "~2.3.3",
"postcss": "^8.4.43",
"rollup": "^4.20.0"
}
}
}
}

19
mandelbrot/package.json Normal file
View File

@@ -0,0 +1,19 @@
{
"name": "mandel-brot",
"version": "1.0.0",
"description": "",
"private": true,
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "MIT",
"dependencies": {
"canvas-common": "file:../canvas-common"
},
"devDependencies": {
"vite": "^5.1.5"
}
}

22
mandelbrot/src/index.html Normal file
View File

@@ -0,0 +1,22 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>mandelBrot</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html, body, div, canvas {
margin: 0;
padding: 0;
}
html, body { width:100%; height:100%; }
canvas { display:block; }
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="module" src="js/main.js"></script>
</body>
</html>

90
mandelbrot/src/js/main.js Normal file
View File

@@ -0,0 +1,90 @@
import {
createRainbowColors,
docReady, getIndexForCoordinate, randomInteger
} from "canvas-common";
let canvas;
let ctx;
let imageData = {};
let final_data;
let config = {
size: {
height: window.innerHeight,
width: window.innerWidth
}
};
config.mandelBrot = {
fps: 60,
};
// 100 colors
let rainbowColors = createRainbowColors(1/16);
function translatePoint(x, y) {
return {x: x / (config.size.width / 3), y: y / (config.size.height / 3)}
}
function setup() {
final_data = imageData.data;
for (let y = -config.size.height / 2; y < config.size.height / 2; y++) {
let yToUse = Math.floor(y)
for (let x = -config.size.width / 2; x < config.size.width / 2; x++) {
let xToUse = Math.floor(x);
let translated = translatePoint(xToUse, yToUse)
let iterations = getIterations(translated.x, translated.y);
let color = rainbowColors[iterations];
let actualX = x + config.size.width / 2;
let actualY = y + config.size.height / 2;
let index = getIndexForCoordinate(config, actualX, actualY);
final_data[index] = color.r;
final_data[index + 1] = color.g;
final_data[index + 2] = color.b;
final_data[index + 3] = 255;
}
}
ctx.putImageData(imageData, 0, 0);
}
function getIterations(x, y) {
let z_i = {r: 0, i: 0}
let c_r = x;
let c_i = y;
let visited = {}
let iterations = 0;
for (let i = 0; i < 100; i++) {
z_i = getValue(i, z_i.r, z_i.i, c_r, c_i)
let key = z_i.r + '' + z_i.i;
if (key in visited) {
return 0;
}
iterations = i;
if(z_i.r === Infinity || z_i.i === Infinity) {
return iterations;
}
visited[key] = 1
}
return iterations;
}
// 0 + 0.5i
// 0 + 0.5i^2 + 0.5i -> -0.25 + 0.5i
// (-0.25 + 0.5i)^2 + 0.5i -> -0.25 * -0.25 + -0.25 * 0.5i + -0.25 * 0.5i + 0.5i * 0.5i + 0.5i
// -3/16 * -3/16 + - 3/16 * 0.25i - 3/16 * 0.25i + 0.25i * 0.25i + 0.5i
function getValue(i, z_r, z_i, c_r, c_i) {
let iFactor = z_r < 0 ? -1 : 1
return {r: z_r ** 2 + (Math.abs(z_i ** 2) * -1) + c_r, i: z_i * z_r * 2 + c_i}
}
docReady(function() {
canvas = document.getElementById('canvas')
canvas.width = config.size.width;
canvas.height = config.size.height;
ctx = canvas.getContext("2d");
canvas.style.backgroundColor = 'rgba(0, 0, 0, 1)';
imageData = ctx.getImageData(0, 0, config.size.width, config.size.height);
setup()
});

View File

@@ -0,0 +1,9 @@
import { defineConfig } from 'vite'
export default defineConfig({
base: './',
root: 'src',
build: {
outDir: '../../dist/mandelbrot'
}
})