0xbd11…7699

All memos sent from and to 0xbd11…7699.

gardenconst baseGridDensity = 60; const baseWeaveSteps = 10; const baseWeaveSpeed = 1.0; const baseStrokeWidth = 1.0; let angleNoiseScale = 0.015; let sizeNoiseScale = 0.06; let recursionDepth = 3; let recursionFactor = 0.4; let grainAmount = 25; const gardenPalettes = { original: [ { h: [330, 360], s: [70, 90], b: [60, 80] }, { h: [190, 230], s: [80, 100], b: [70, 90] }, { h: [40, 60], s: [60, 80], b: [30, 50] }, { h: [260, 290], s: [70, 90], b: [40, 60] }, ], 'original-rose': [ { h: [330, 360], s: [70, 90], b: [60, 80] }, { h: [4, 22], s: [76, 94], b: [68, 94] }, { h: [34, 52], s: [66, 88], b: [56, 86] }, { h: [92, 124], s: [56, 78], b: [30, 62] }, { h: [260, 290], s: [50, 72], b: [48, 78] }, { h: [330, 360], s: [4, 14], b: [5, 20] }, ], 'original-water': [ { h: [190, 230], s: [80, 100], b: [70, 90] }, { h: [166, 194], s: [68, 90], b: [48, 80] }, { h: [92, 124], s: [54, 76], b: [30, 62] }, { h: [328, 350], s: [54, 76], b: [58, 88] }, { h: [38, 56], s: [64, 86], b: [54, 84] }, { h: [194, 230], s: [4, 14], b: [5, 20] }, ], 'original-gold': [ { h: [40, 60], s: [60, 80], b: [30, 50] }, ], 'original-violet': [ { h: [260, 290], s: [70, 90], b: [40, 60] }, ], 'night-bloom': [ { h: [285, 320], s: [70, 90], b: [60, 80] }, { h: [215, 245], s: [80, 100], b: [70, 90] }, { h: [165, 190], s: [60, 80], b: [30, 50] }, { h: [325, 350], s: [70, 90], b: [40, 60] }, ], 'sunlit-earth': [ { h: [5, 25], s: [70, 90], b: [60, 80] }, { h: [28, 48], s: [80, 100], b: [70, 90] }, { h: [50, 72], s: [60, 80], b: [30, 50] }, { h: [338, 358], s: [70, 90], b: [40, 60] }, ], 'pond-glass': [ { h: [145, 175], s: [70, 90], b: [60, 80] }, { h: [178, 205], s: [80, 100], b: [70, 90] }, { h: [205, 225], s: [60, 80], b: [30, 50] }, { h: [95, 125], s: [70, 90], b: [40, 60] }, ], 'orchard-dusk': [ { h: [345, 360], s: [70, 90], b: [60, 80] }, { h: [0, 18], s: [80, 100], b: [70, 90] }, { h: [72, 100], s: [60, 80], b: [30, 50] }, { h: [275, 305], s: [70, 90], b: [40, 60] }, ], 'spring-border': [ { h: [328, 350], s: [70, 90], b: [60, 80] }, { h: [42, 62], s: [80, 100], b: [70, 90] }, { h: [92, 126], s: [60, 80], b: [30, 50] }, { h: [182, 208], s: [70, 90], b: [40, 60] }, ], 'wildflower-meadow': [ { h: [0, 18], s: [70, 90], b: [60, 80] }, { h: [202, 232], s: [80, 100], b: [70, 90] }, { h: [42, 58], s: [60, 80], b: [30, 50] }, { h: [262, 294], s: [70, 90], b: [40, 60] }, ], 'herb-garden': [ { h: [92, 118], s: [70, 90], b: [60, 80] }, { h: [70, 96], s: [80, 100], b: [70, 90] }, { h: [154, 184], s: [60, 80], b: [30, 50] }, { h: [242, 270], s: [70, 90], b: [40, 60] }, ], 'kitchen-garden': [ { h: [0, 14], s: [70, 90], b: [60, 80] }, { h: [104, 136], s: [80, 100], b: [70, 90] }, { h: [42, 60], s: [60, 80], b: [30, 50] }, { h: [274, 302], s: [70, 90], b: [40, 60] }, ], 'water-garden': [ { h: [328, 350], s: [70, 90], b: [60, 80] }, { h: [180, 210], s: [80, 100], b: [70, 90] }, { h: [72, 104], s: [60, 80], b: [30, 50] }, { h: [246, 276], s: [70, 90], b: [40, 60] }, ], 'rose-arbor': [ { h: [342, 360], s: [70, 90], b: [60, 80] }, { h: [8, 28], s: [80, 100], b: [70, 90] }, { h: [304, 332], s: [60, 80], b: [30, 50] }, { h: [88, 120], s: [70, 90], b: [40, 60] }, ], 'blush-garden': [ { h: [342, 358], s: [22, 38], b: [80, 96] }, { h: [12, 28], s: [24, 42], b: [82, 98] }, { h: [88, 112], s: [18, 34], b: [72, 90] }, { h: [252, 276], s: [20, 38], b: [76, 94] }, { h: [110, 134], s: [58, 78], b: [28, 52] }, { h: [330, 360], s: [5, 16], b: [6, 24] }, ], 'morning-border': [ { h: [44, 58], s: [20, 36], b: [84, 98] }, { h: [194, 212], s: [18, 34], b: [80, 96] }, { h: [132, 154], s: [16, 32], b: [76, 92] }, { h: [326, 344], s: [20, 38], b: [82, 97] }, { h: [126, 150], s: [60, 80], b: [26, 50] }, { h: [198, 222], s: [6, 18], b: [6, 22] }, ], 'hydrangea-mist': [ { h: [218, 238], s: [24, 42], b: [78, 94] }, { h: [268, 290], s: [20, 38], b: [80, 96] }, { h: [194, 214], s: [18, 34], b: [82, 98] }, { h: [316, 338], s: [20, 36], b: [78, 95] }, { h: [98, 126], s: [56, 76], b: [26, 50] }, { h: [242, 270], s: [8, 20], b: [6, 22] }, ], 'cottage-pastel': [ { h: [4, 18], s: [28, 46], b: [80, 96] }, { h: [44, 58], s: [22, 40], b: [82, 98] }, { h: [90, 114], s: [18, 34], b: [72, 90] }, { h: [204, 226], s: [24, 42], b: [76, 94] }, { h: [88, 118], s: [58, 78], b: [28, 52] }, { h: [0, 20], s: [5, 16], b: [6, 22] }, ], 'pressed-flowers': [ { h: [336, 352], s: [24, 42], b: [66, 84] }, { h: [36, 52], s: [28, 46], b: [70, 88] }, { h: [80, 104], s: [18, 34], b: [62, 80] }, { h: [262, 284], s: [22, 40], b: [66, 84] }, { h: [68, 94], s: [46, 66], b: [24, 46] }, { h: [248, 280], s: [4, 14], b: [5, 20] }, ], 'glasshouse-light': [ { h: [124, 150], s: [18, 34], b: [78, 94] }, { h: [174, 196], s: [18, 32], b: [82, 98] }, { h: [14, 30], s: [22, 40], b: [82, 98] }, { h: [254, 278], s: [20, 36], b: [78, 95] }, { h: [142, 166], s: [62, 82], b: [24, 48] }, { h: [178, 210], s: [5, 16], b: [5, 21] }, ], }; const gardenPaletteNames = Object.keys(gardenPalettes); const softGardenPaletteNames = new Set([ 'blush-garden', 'morning-border', 'hydrangea-mist', 'cottage-pastel', 'pressed-flowers', 'glasshouse-light', ]); const mixedGardenPaletteNames = new Set([ 'original-rose', 'original-water', ]); let colorPalette; let paletteName; let softPaletteActive = false; let mixedPaletteActive = false; let lightVector; let seed; const FALLBACK_SEED = 949032; const MAX_SEED = 999999; const DEFAULT_SIZE = 1000; const RENDER_PIXEL_DENSITY = 2; let WIDTH = window.innerWidth; let HEIGHT = window.innerHeight; let DIM = Math.min(WIDTH, HEIGHT); let M = DIM / DEFAULT_SIZE; function readArtworkSeed() { const raw = window.ARTSCRIPT_SEED ?? window.__TOKEN_STUDIO_SEED ?? new URLSearchParams(window.location.search).get('seed'); if (raw === undefined || raw === null || !/^[0-9]+$/.test(String(raw).trim())) { return FALLBACK_SEED; } return Number(BigInt(String(raw).trim()) % BigInt(MAX_SEED + 1)); } function selectPaletteName(nextSeed) { const requestedName = new URLSearchParams(window.location.search).get('palette'); if (requestedName && Object.hasOwn(gardenPalettes, requestedName)) { return requestedName; } return gardenPaletteNames[nextSeed % gardenPaletteNames.length]; } function setup() { document.body.style.margin = '0'; document.body.style.padding = '0'; document.body.style.overflow = 'hidden'; document.body.style.backgroundColor = '#111'; document.body.style.display = 'flex'; document.body.style.justifyContent = 'center'; document.body.style.alignItems = 'center'; document.body.style.height = '100vh'; DIM = Math.min(WIDTH, HEIGHT); const canvasSize = Math.max(1, Math.floor(DIM)); createCanvas(canvasSize, canvasSize); pixelDensity(RENDER_PIXEL_DENSITY); colorMode(HSB, 360, 100, 100, 100); angleMode(RADIANS); startGeneration(readArtworkSeed()); noLoop(); } function startGeneration(nextSeed) { seed = Number.isInteger(nextSeed) ? constrain(nextSeed, 0, MAX_SEED) : floor(random(1000000)); randomSeed(seed); noiseSeed(seed); if (width <= 0 || height <= 0) return; const gridStep = (DIM / baseGridDensity); const weaveSteps = baseWeaveSteps; const weaveSpeed = baseWeaveSpeed * M; const scaledBaseStrokeWidth = baseStrokeWidth * M; lightVector = p5.Vector.fromAngle(random(TWO_PI)); lightVector.normalize(); paletteName = selectPaletteName(seed); colorPalette = gardenPalettes[paletteName]; softPaletteActive = softGardenPaletteNames.has(paletteName); mixedPaletteActive = mixedGardenPaletteNames.has(paletteName); document.body.dataset.artSeed = String(seed); document.body.dataset.palette = paletteName; document.body.dataset.colorStyle = softPaletteActive ? 'soft' : mixedPaletteActive ? 'mixed' : 'legacy'; if (softPaletteActive) { background(100, 12, 13); } else if (mixedPaletteActive) { background(100, 24, 9); } else { background(100, 40, 10); } for (let y = 0; y < height; y += gridStep) { for (let x = 0; x < width; x += gridStep) { let currentPos = createVector(x, y); for (let i = 0; i < weaveSteps; i++) { let virtualX = currentPos.x / M; let virtualY = currentPos.y / M; let angle = noise(virtualX * angleNoiseScale, virtualY * angleNoiseScale) * TWO_PI * 3; let sizeFactor = noise(virtualX * sizeNoiseScale, virtualY * sizeNoiseScale); let shapeSize = map(sizeFactor, 0, 1, 2 * M, gridStep * 2.5); drawRecursiveShape(currentPos.x, currentPos.y, shapeSize, angle, recursionDepth, scaledBaseStrokeWidth); currentPos.x += cos(angle) * weaveSpeed; currentPos.y += sin(angle) * weaveSpeed; } } } applyGrain(); const infoDiv = document.querySelector('.info'); if (infoDiv) { infoDiv.innerHTML = `Seed: ${seed} | Palette: ${paletteName} | Press 's' to save.`; } notifyRendered(); } function notifyRendered() { if (typeof window.__TOKEN_STUDIO_NOTIFY !== 'function') return; window.requestAnimationFrame(() => { window.__TOKEN_STUDIO_NOTIFY('token-art:rendered'); }); } function drawRecursiveShape(x, y, size, angle, level, scaledStrokeWidth) { if (level <= 0 || size < 0.5 * M) return; push(); translate(x, y); rotate(angle); let normalVector = p5.Vector.fromAngle(angle); let lightDot = normalVector.dot(lightVector); let paletteIndex = floor(map(angle % TWO_PI, 0, TWO_PI, 0, colorPalette.length)); paletteIndex = constrain(paletteIndex, 0, colorPalette.length - 1); let selectedPalette = colorPalette[paletteIndex]; let hue = map(x, 0, width, selectedPalette.h[0], selectedPalette.h[1]); let hueShift = softPaletteActive ? map(lightDot, -1, 1, -8, 8) : mixedPaletteActive ? map(lightDot, -1, 1, -12, 12) : map(lightDot, -1, 1, -20, 20); hue = (hue + hueShift + 360) % 360; let saturation = 95; let brightness = map(lightDot, -1, 1, 40, 100); if (softPaletteActive || mixedPaletteActive) { saturation = map(x, 0, width, selectedPalette.s[0], selectedPalette.s[1]); brightness = map(lightDot, -1, 1, selectedPalette.b[0], selectedPalette.b[1]); } let sw = map(level, recursionDepth, 1, scaledStrokeWidth, scaledStrokeWidth * 0.1); strokeWeight(sw); let alpha = softPaletteActive ? map(lightDot, -1, 1, 22, 58) : mixedPaletteActive ? map(lightDot, -1, 1, 26, 68) : map(lightDot, -1, 1, 25, 70); stroke(hue, saturation, brightness, alpha); noFill(); rectMode(CENTER); rect(0, 0, size * 1.8, size, size * 0.3); let newSize = size * recursionFactor; let angleOffset = map(sin(angle), -1, 1, -QUARTER_PI, QUARTER_PI); let newAngle = angle + angleOffset; drawRecursiveShape(0, 0, newSize, newAngle, level - 1, scaledStrokeWidth); pop(); } function applyGrain() { loadPixels(); for (let i = 0; i < pixels.length; i += 4) { let grain = random(-grainAmount, grainAmount); pixels[i] = pixels[i] + grain; pixels[i + 1] = pixels[i + 1] + grain; pixels[i + 2] = pixels[i + 2] + grain; } updatePixels(); } function keyPressed() { if (key === 's' || key === 'S') { saveCanvas('In the Garden - ' + seed, 'png'); } } function windowResized() { WIDTH = window.innerWidth; HEIGHT = window.innerHeight; DIM = Math.min(WIDTH, HEIGHT); M = DIM / DEFAULT_SIZE; const canvasSize = Math.max(1, Math.floor(DIM)); resizeCanvas(canvasSize, canvasSize); startGeneration(seed); }
DOS_Loading_Arrayvar DEFAULT_SCRIPTS = [ { data: "three-v0.147.0.min.js.gz", gzip: true, label: "three.js — renderer" }, { data: "F3_Utils", gzip: true, label: "utils — core helpers" }, { data: "css3DRenderer", gzip: true, label: "css3d — surface renderer" }, { data: "CypherDudesFonts", gzip: false, label: "fonts — Andale Mono MonoPixel" }, { data: "CypherDudesLayer1", gzip: false, label: "layer1 images" }, { data: "DOS_Spritesheet", gzip: true, label: "spritesheet — icons" }, { data: "DOS_ethCalls", gzip: true, label: "eth — onchain calls" }, { data: "DOS_os", gzip: true, label: "os — operating layer" }, { data: "DOS_bip39", gzip: true, label: "bip39 — mnemonics" }, { data: "DOS_main", gzip: true, label: "main — world builder" }, { data: "DOS_palace", gzip: true, label: "cypherpalace" }, { data: "DOS_artefacts_Abis", gzip: true, label: "artefacts handler" }, { data: "DOS_communityApps", gzip: true, label: "Community Apps management" }, { data: "recompose.min.js", gzip: true, label: "recompose — chunked artifact loader" }, { data: "DOS_animate", gzip: true, label: "animate — boot init()" } ];
DOS_Loading_Array{"v":1,"algo":"raw","rawSize":1290,"storedSize":1290,"sha256raw":"0xb3de4dc8fb552ee1da6197f13d13f43385eadb1dcaf5a06a5bb96cb760c7f7bb","sha256stored":"0xb3de4dc8fb552ee1da6197f13d13f43385eadb1dcaf5a06a5bb96cb760c7f7bb"}
DOS_artefacts_Abis{"v":1,"algo":"gzip","rawSize":14444,"storedSize":3592,"sha256raw":"0xf440d01f4bf6ab5b83ccdbd771a21e241f33b2fcb5606f046b87de32d6b3edad","sha256stored":"0x676e267ebf8a36de651bdf46aec42324c44454fe6d539cb01ffb29ea54d638c0"}
artefacts_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
artefacts_0726{"v":1,"algo":"base64+gzip","rawSize":6701,"gzipSize":1889,"storedSize":2520,"sha256raw":"0x3a14b99c9861a8ef718ec28820d3da20ed01eceb08ba8cdb2cd7ac3bb8551f2b","sha256stored":"0xacaae5d9b6ebfe11f28f978547341946f100d575fa6df3c490db5fd7117fa682"}
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
cypherpager{"v":1,"algo":"base64+gzip","rawSize":82004,"gzipSize":23979,"storedSize":31972,"sha256raw":"0xb600a762826fd546d33e76eee01135cbe7ca534d96dbea2828d8141d1e322669","sha256stored":"0x454b44d1c8b036b8776c0a2c6b5dca383a8a5650dd23acfd9e9c1525241b2d3f"}
send_final.zkey{"v":1,"algo":"gzip","rawSize":4759478,"storedSize":2606601,"sha256raw":"0xde48d2030ccadd4d81fe51cf8d4d2990f9703d743b698dd51171a10c97aada24","sha256stored":"0xf16778c24cea053e4aba0afb7296187a032d2b8eb98b6f9ceb547a9313d2d6c3"}
"h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h\O04040404040404040404040404040404040404040404040404040404040404jehckhhd04040404040404040404040404040404040404040404040404040404040404jeh$bh`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`hbh`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h'14040404040404040404040404040404040404040404040404040404040404jehch`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`hah`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`hch`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h04040404040404040404040404040404040404040404040404040404040404jvah`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h`h14040404040404040404040404040404040404040404040404040404040404jeht+04040404040404040404040404040404040404040404040404040404040404jeht
ЃЃЃЃЃЃЃЃЃЃЃЃЃЃЃЃЃЃЃЃЃI=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=ԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃgI=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=I=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=ԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃe걅ԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃԃI=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=H=
send.wasm{"v":1,"algo":"gzip","rawSize":2513598,"storedSize":1013216,"sha256raw":"0x3032806606602c9fc30fca4a507c4dd7368925142fc94d8af7ad957aae792556","sha256stored":"0xd44bd58d6c169ea4df3879fedcf808ad2e830a92b8a6170b4f34bf44bedcbb24"}
snarkjs.min.js{"v":1,"algo":"gzip","rawSize":688758,"storedSize":146606,"sha256raw":"0x3f61bbd9ac0a10173902eaef65b510fa4e9a2c057f759c7f18a6d0446b20fd06","sha256stored":"0x8980f5127df2b96579a63b42eb264a2565e63d55166cea4b0b0dee73040016d4"}
DOS_loader var base = Math.min(20000, 500 * Math.pow(2, attempt || 0)); ep.cooldownUntil = Date.now() + base / 2 + Math.random() * (base / 2); } }; var rpcPool = window.rpcPool; window.rpcSleep = function (ms) { return new Promise(function (r) { setTimeout(r, ms); }); }; var rpcSleep = window.rpcSleep; // First working RPC from the RPCs array: first endpoint not cooling down // (i.e. not recently failed / rate-limited), else the first configured one. // Use this wherever a single endpoint is needed (e.g. callContract). window.firstWorkingRpc = function () { var eps = window.rpcPool.endpoints(); var now = Date.now(); for (var i = 0; i < eps.length; i++) if (eps[i].cooldownUntil <= now) return eps[i].url; return eps.length ? eps[0].url : ""; }; // Run fn(item, rpcUrl) over items with one worker per endpoint (recompose's // worker-pool U()). Failed items retry on another endpoint up to `retries`. window.parallelRpcMap = async function (items, fn, opts) { var retries = (opts && opts.retries != null) ? opts.retries : 3; var eps = rpcPool.endpoints(); if (!eps.length) { // no pool — degrade to sequential on the first rpc for (var k = 0; k < items.length; k++) { try { await fn(items[k], window.firstWorkingRpc()); } catch (e) { console.warn('parallelRpcMap:', items[k], e); } } return; } var next = 0; var workers = Array.from({ length: Math.min(eps.length, items.length) }, async function () { while (next < items.length) { var i = next++; for (var a = 0; ; a++) { var picked = rpcPool.pick(); if (picked.waitMs > 0) await rpcSleep(picked.waitMs); try { await fn(items[i], picked.ep.url); break; } catch (e) { rpcPool.cooldown(picked.ep, a); if (a >= retries) { console.warn('parallelRpcMap: item failed', items[i], e); break; } } } } }); await Promise.all(workers); }; /* --------------------------------------------- scripty getContent (eth_call) */ // Self-contained minimal ABI encode/decode: the loader runs BEFORE // COS_ethCalls.js (which is itself in the script list above). // ABI-encode getContent(string name, bytes data) with data == empty bytes (0x). // Head: two offset words; tail: string (len + padded utf8), then bytes (len 0). function encodeGetContent(name) { function word(n) { return n.toString(16).padStart(64, "0"); } var utf8 = new TextEncoder().encode(name); var hex = ""; for (var i = 0; i < utf8.length; i++) hex += utf8[i].toString(16).padStart(2, "0"); var padded = hex.padEnd(Math.max(64, Math.ceil(hex.length / 64) * 64), "0"); var strTail = word(utf8.length) + padded; // string: len + data return GETCONTENT_SELECTOR + word(0x40) + // offset of string word(0x40 + strTail.length / 2) + // offset of bytes strTail + word(0); // bytes: len 0 (== '0x') } // Decode a single ABI `bytes` return into a 0x-prefixed hex blob. function decodeBytesReturn(result) { if (!result || result === "0x") throw new Error("empty result"); var h = result.slice(2); var off = parseInt(h.slice(0, 64), 16) * 2; var len = parseInt(h.slice(off, off + 64), 16) * 2; if (!len) throw new Error("content not stored"); return "0x" + h.slice(off + 64, off + 64 + len); } // One eth_call: ScriptyStorageV2.getContent(name, 0x) on a given endpoint. async function ethGetContent(name, rpcUrl) { var payload = { jsonrpc: "2.0", method: "eth_call", params: [{ to: SCRIPTY_ADDRESS, data: encodeGetContent(name) }, "latest"], id: 1 }; var r = await fetch(rpcUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); if (!r.ok) throw new Error("HTTP " + r.status); var json = await r.json(); if (json.error) throw new Error("RPC Error: " + json.error.message); return decodeBytesReturn(json.result); } /* ------------------------------------------------- parallel prefetch pool */ // Same principle as recompose.min.js / the world's slot loader: all // getContent calls are dispatched up-front through the RPC pool (one worker // per endpoint, paced, retried across endpoints with cooldown), while // INJECTION stays strictly sequential — script order matters for execution, // but the network wait is fully overlapped. function prefetchAll(scripts) { var RETRIES = 3; var resolvers = scripts.map(function () { return {}; }); var promises = scripts.map(function (_, i) { return new Promise(function (res, rej) { resolvers[i].res = res; resolvers[i].rej = rej; }); }); async function fetchOne(sc) { var lastErr = null; var hasPool = rpcPool.endpoints().length > 0; for (var a = 0; hasPool && a <= RETRIES; a++) { var picked = rpcPool.pick(); if (picked.waitMs > 0) await rpcSleep(picked.waitMs); try { return await ethGetContent(sc.data, picked.ep.url); } catch (e) { lastErr = e; rpcPool.cooldown(picked.ep, a); } } // Local-dev fallback: `data` may be a plain URL/path (e.g. a .txt or .gz // served next to the page). Try a direct fetch before giving up. try { var r = await fetch(sc.data); if (!r.ok) throw new Error("HTTP " + r.status); return await r.text(); } catch (e) { throw lastErr || e; } } var next = 0; function worker() { if (next >= scripts.length) return Promise.resolve(); var i = next++; return fetchOne(scripts[i]) .then(function (txt) { resolvers[i].res(txt); }) .catch(function (err) { resolvers[i].rej(err); }) .then(worker); } var workers = []; var n = Math.max(1, Math.min(rpcPool.endpoints().length || 1, scripts.length)); for (var w = 0; w < n; w++) workers.push(worker()); return promises; } /* -------------------------------------------------------------------- finish */ var finished = false; function finish() { if (finished) return; finished = true; markDone(curLine); setProgress(1); if (!el.root) return; el.root.classList.add("dos-hide"); setTimeout(function () { if (el.root && el.root.parentNode) el.root.parentNode.removeChild(el.root); }, 900); } // Wait for the world to signal readiness (window.__WORLD_READY, set at the end // of init() once the scene is built and the render loop has started). // // The modules finish injecting well before the world is actually painted (the // world spends a few seconds fetching slot data + building geometry). Rather // than fade on a timer and expose a white screen, we keep the splash up and // show a "World reconstruction" phase: the radar keeps sweeping and the counter // shows the elapsed reconstruction time, until __WORLD_READY (or the hard cap). function awaitWorld() { if (window.__WORLD_READY) return finish(); // Stop the progress easing so it doesn't fight the reconstruction spin. if (raf) { cancelAnimationFrame(raf); raf = 0; } addLine("World reconstruction"); var start = Date.now(); var spinRaf = 0; (function spin() { var elapsed = (Date.now() - start) / 1000; // ~0.55 turn/sec continuous sweep (indeterminate — we can't know the total). if (el.radar) el.radar.setAttribute("transform", "rotate(" + ((elapsed * 200) % 360).toFixed(2) + " 256 256)"); if (el.pct) el.pct.textContent = elapsed.toFixed(1) + "s"; spinRaf = requestAnimationFrame(spin); })(); (function poll() { if (window.__WORLD_READY || Date.now() - start > READY_TIMEOUT_MS) { if (spinRaf) cancelAnimationFrame(spinRaf); return finish(); } setTimeout(poll, 120); })(); } /* ---------------------------------------------------------------------- boot */ async function boot() { // Run-once guard: modules are injected as classic <script>s into the shared // global scope, so a second boot would re-declare their top-level consts // (e.g. `fonts` from CypherDudesFonts) and throw "already declared". This can // happen when the same window is reused (e.g. a document.write preview that // reopens the document and re-fires DOMContentLoaded). if (window.__DOS_BOOTED) return; window.__DOS_BOOTED = true; build(); window.addEventListener("resize", layout); window.addEventListener("load", layout); if (document.fonts && document.fonts.ready) document.fonts.ready.then(layout); layout(); var n = SCRIPTS.length; // All network fetches start NOW, in parallel; the loop below only waits // for each script's bytes to arrive before injecting them in order. var prefetched = prefetchAll(SCRIPTS); for (var i = 0; i < n; i++) { addLine(SCRIPTS[i].label); // new name on the first line, previous pushed down setProgress(i / n); try { var txt = await prefetched[i]; await injectOne(txt, SCRIPTS[i]); } catch (err) { console.error("[DOSLoader] failed:", SCRIPTS[i].data, err); markError(); } setProgress((i + 1) / n); // MonoPixel changes the title metrics -> re-fit once it has loaded if (/fonts/i.test(SCRIPTS[i].data)) layout(); } markDone(curLine); // Everything is injected — DOS_animate's init() is building the world NOW. // Signal listeners (the recompose zk-preload prelude) to start their // BACKGROUND downloads (crypto/snarkjs/wasm/zkey) without having competed // with the boot fetches above. try { window.dispatchEvent(new Event("dos:world-ready")); } catch (e) {} awaitWorld(); } // Public API window.DOSLoader = { setProgress: setProgress, addLine: addLine, layout: layout, finish: finish, boot: boot }; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", boot); } else { boot(); } })();
DOS_loader/* ============================================================================= * COS_loader.js — Decentralized Operation System boot splash + script loader * ----------------------------------------------------------------------------- * Single self-contained bootloader. Include this ONE file first; it: * 1. Paints a full-screen splash: title block ("DECENTRALIZED / OPERATING / * SYSTEM" + subtitle), a page-centred radar drawing, and a terminal-style * log with the load % pinned to the first line. * 2. Fetches every script from ScriptyStorageV2 via eth_call * getContent(name, 0x) through a parallel RPC pool (one worker per * endpoint, paced + cooldown, mirroring COS_ethCalls.js rpcPool), then * gunzips + injects them strictly in order. Each script prints a new line * at the top of the log (previous pushed down); the radar sweep + % track * overall progress (one full rotation == 100%). * 3. On resize the title scales to the space above the centred drawing, and * the drawing + log match the title block's width. * 4. Once everything is loaded (init() builds the world), fades the splash out * and reveals the world. * * Configure the script list via window.DOS_SCRIPTS BEFORE this file runs, * or via DEFAULT_SCRIPTS declared by DOS_LoadingArray.js (injected by the * renderer right before this file). Each entry: * { data: "<scripty-content-name>", gzip: true|false, label: "Human name" } * RPC endpoints come from the renderer-injected RPCString / WSRPCString. * The shared RPC layer (RPCs, WS_RPCs, rpcPool, rpcSleep, parallelRpcMap, * firstWorkingRpc, parseRpcString, parseClaimOrderString) is defined HERE and * exposed on window — every script injected afterwards reuses it. * The scripty address can be overridden via window.DOS_SCRIPTY_ADDRESS. * * The world's init() (called from COS_animate.js) can signal true readiness by * setting window.__WORLD_READY = true or calling DOSLoader.finish(). * * Styling: all colours are hardcoded. Only the viewport-driven sizes are left as * CSS variables — --w (block width), --gap, and --tu (title unit, JS-refined). * ========================================================================== */ (function () { "use strict"; /* ------------------------------------------------------------------ config */ var SETTLE_MS = 1200; // (legacy) unused now that we wait for __WORLD_READY var READY_TIMEOUT_MS = 30000; // hard cap: hide even if __WORLD_READY never set // ScriptyStorageV2 — every module entry's `data` is a content name // stored on this contract; blobs are fetched via getContent(name, 0x). var SCRIPTY_ADDRESS = (typeof window.DOS_SCRIPTY_ADDRESS === "string" && window.DOS_SCRIPTY_ADDRESS) ? window.DOS_SCRIPTY_ADDRESS : "0xbD11994aABB55Da86DC246EBB17C1Be0af5b7699"; var GETCONTENT_SELECTOR = "0x2647c23d"; // getContent(string,bytes) // Module list — order matters. Each `data` is the ScriptyStorageV2 content // name, `gzip` matches how each blob was stored. DEFAULT_SCRIPTS is declared // by DOS_LoadingArray.js, injected by the renderer right before this file. // Priority: window.DOS_SCRIPTS > DEFAULT_SCRIPTS. var SCRIPTS = (window.DOS_SCRIPTS && window.DOS_SCRIPTS.length) ? window.DOS_SCRIPTS : (typeof DEFAULT_SCRIPTS !== "undefined" ? DEFAULT_SCRIPTS : []); // Script manifest for the Provenance window (os.js): on-chain content name + // injected script size in bytes, filled in as each module is injected. window.DOS_SCRIPT_INFO = SCRIPTS.map(function (sc) { return { name: sc.data, label: sc.label, bytes: null }; }); function recordScriptSize(sc, jsCode) { if (!sc || typeof jsCode !== "string") return; for (var i = 0; i < window.DOS_SCRIPT_INFO.length; i++) { if (window.DOS_SCRIPT_INFO[i].name === sc.data && window.DOS_SCRIPT_INFO[i].bytes == null) { window.DOS_SCRIPT_INFO[i].bytes = new TextEncoder().encode(jsCode).length; return; } } } /* ------------------------------------------------------------------- styles */ // Colours hardcoded; only --w / --gap / --tu are viewport-driven variables. var css = ":root{" + "--w:min(320px, 80vw);" + "--gap:clamp(14px, 3.5vh, 40px);" + "--tu:min(var(--w), calc(((100vh - var(--w)) / 2 - var(--gap)) / 1.1));" + "}" + "#dos-loader{position:fixed;inset:0;z-index:100000;background:#0a0b0d;color:#cfd3cf;" + "font-family:'Andale Mono',monospace;display:grid;" + "grid-template-rows:minmax(0,1fr) auto minmax(0,1fr);justify-items:center;" + "opacity:1;transition:opacity .8s ease;pointer-events:auto;user-select:none;overflow:hidden;}" + "#dos-loader.dos-hide{opacity:0;pointer-events:none;}" + /* 1) title + subtitle : centred block, scales down to fit remaining height */ "#dos-head{grid-row:1;align-self:end;margin-bottom:var(--gap);font-weight:normal;" + "text-align:center;box-sizing:border-box;}" + "#dos-head .l{font-family:'MonoPixel','Andale Mono',monospace;line-height:1.25;" + "letter-spacing:.02em;margin:0;white-space:nowrap;}" + "#dos-head .l1{font-size:calc(var(--tu)*0.128*1.3);}" + "#dos-head .l2{font-size:calc(var(--tu)*0.185*1.31);}" + "#dos-head .l3{font-size:calc(var(--tu)*0.278*1.31);}" + "#dos-head .sub{font-size:calc(var(--tu)*0.038*1.02);opacity:.72;letter-spacing:.02em;" + "margin:calc(var(--tu)*0.05) 0 0;white-space:nowrap;}" + /* 2) drawing : page-centred, width matched to the title block by JS */ "#dos-art{grid-row:2;width:var(--w);height:var(--w);display:block;}" + /* 3) status : terminal log (newest first) + % pinned to the first line */ "#dos-status{grid-row:3;align-self:start;margin-top:var(--gap);width:var(--w);" + "max-height:100%;overflow:hidden;display:flex;align-items:flex-start;gap:1em;" + "font-size:calc(var(--w)*0.04);letter-spacing:.02em;line-height:1.5;}" + "#dos-log{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;}" + "#dos-log .line{display:flex;gap:.5em;white-space:nowrap;min-width:0;}" + "#dos-log .line .mk{flex:0 0 auto;width:1em;color:#FFD65C;}" + "#dos-log .line .tx{overflow:hidden;text-overflow:ellipsis;}" + "#dos-log .line.cur{color:#cfd3cf;opacity:1;}" + "#dos-log .line.done{opacity:.45;}" + "#dos-log .line.err .mk{color:#ff6b6b;}" + "#dos-log .line.err{color:#ff6b6b;opacity:1;}" + "#dos-status-pct{flex:0 0 auto;font-family:'MonoPixel','Andale Mono',monospace;" + "color:#FFD65C;font-variant-numeric:tabular-nums;}" + /* SVG classes (scoped to the drawing) */ "#dos-art .cls-1{fill:#000;}" + "#dos-art .cls-2{fill:none;}" + "#dos-art .cls-1,#dos-art .cls-2,#dos-art .cls-3{stroke:#cfd3cf;stroke-miterlimit:10;}" + "#dos-art .cls-2{stroke-width:2px;}" + "#dos-art .cls-4,#dos-art .cls-5{fill:#cfd3cf;font-family:'MonoPixel','Andale Mono',monospace;}" + "#dos-art .cls-4{font-size:36px;}" + "#dos-art .cls-5{font-size:21px;}" + "#dos-art .cls-6{fill:#FFD65C;}"; /* --------------------------------------------------------------- drawing SVG */ // Concentric-orbit "atom" scaled to nearly fill the 512 frame; the central // squares stay on the foreground and the radar (#dos-radar) is filled + driven // by JS. Colours hardcoded (amber accent #FFD65C, light strokes #cfd3cf). function drawingSVG() { return '' + '<svg id="dos-art" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">' + '<g id="Calque_2" transform="translate(256 256) scale(2) translate(-256 -256)">' + // animated dashed outer ring (rotates 40s) '<g>' + '<circle cx="256" cy="256" r="127" fill="none" stroke="#FFD65C" stroke-width="2" stroke-dasharray="6 10">' + '<animate attributeName="stroke-dashoffset" values="0;-32" dur="2s" repeatCount="indefinite"/>' + '</circle>' + '<animateTransform attributeName="transform" type="rotate" from="0 256 256" to="360 256 256" dur="40s" repeatCount="indefinite"/>' + '</g>' + // orbit r=101.23 (rotates -360 / 20s) '<g>' + '<path class="cls-2" d="M256,357.23c-55.82,0-101.23-45.41-101.23-101.23s45.41-101.23,101.23-101.23,101.23,45.41,101.23,101.23-45.41,101.23-101.23,101.23Z"/>' + '<circle class="cls-3" cx="256" cy="154.77" r="6" fill="#000"/>' + '<animateTransform attributeName="transform" type="rotate" from="0 256 256" to="-360 256 256" dur="20s" repeatCount="indefinite"/>' + '</g>' + // orbit r=61.23 (rotates -360 / 12s) '<g class="cls-3">' + '<path class="cls-2" d="M256,317.23c-33.76,0-61.23-27.47-61.23-61.23s27.47-61.23,61.23-61.23,61.23,27.47,61.23,61.23-27.47,61.23-61.23,61.23Z"/>' + '<circle cx="256" cy="194.77" r="6" fill="#000"/>' + '<circle cx="256" cy="317.23" r="6" fill="#000"/>' + '<circle cx="212.71" cy="212.72" r="6" fill="#000"/>' + '<circle cx="212.71" cy="299.29" r="6" fill="#000"/>' + '<circle cx="299.28" cy="212.72" r="6" fill="#000"/>' + '<circle cx="299.28" cy="299.28" r="6" fill="#000"/>' + '<circle cx="194.77" cy="256" r="6" fill="#000"/>' + '<circle cx="317.23" cy="256" r="6" fill="#000"/>' + '<animateTransform attributeName="transform" type="rotate" from="0 256 256" to="-360 256 256" dur="12s" repeatCount="indefinite"/>' + '</g>' + // orbit r=41.23 (rotates 360 / 5s) '<g class="cls-3">' + '<circle class="cls-2" cx="256" cy="256" r="41.23"/>' + '<circle cx="256" cy="214.77" r="6" fill="#000"/>' + '<circle cx="256" cy="297.23" r="6" fill="#000"/>' + '<animateTransform attributeName="transform" type="rotate" from="0 256 256" to="360 256 256" dur="5s" repeatCount="indefinite"/>' + '</g>' + // orbit r=81.23 (rotates 360 / 10s) '<g class="cls-3">' + '<path class="cls-2" d="M256,337.23c-44.79,0-81.23-36.44-81.23-81.23s36.44-81.23,81.23-81.23,81.23,36.44,81.23,81.23-36.44,81.23-81.23,81.23Z"/>' + '<circle cx="256" cy="174.77" r="6" fill="#000"/>' + '<circle cx="218.26" cy="184.09" r="6" fill="#000"/>' + '<circle cx="189.15" cy="209.85" r="6" fill="#000"/>' + '<circle cx="175.38" cy="246.2" r="6" fill="#000"/>' + '<circle cx="180.04" cy="284.79" r="6" fill="#000"/>' + '<circle cx="202.13" cy="316.78" r="6" fill="#000"/>' + '<circle cx="236.57" cy="334.81" r="6" fill="#000"/>' + '<circle cx="293.74" cy="184.09" r="6" fill="#000"/>' + '<circle cx="322.85" cy="209.85" r="6" fill="#000"/>' + '<circle cx="336.62" cy="246.2" r="6" fill="#000"/>' + '<circle cx="331.96" cy="284.79" r="6" fill="#000"/>' + '<circle cx="309.87" cy="316.78" r="6" fill="#000"/>' + '<circle cx="275.43" cy="334.81" r="6" fill="#000"/>' + '<animateTransform attributeName="transform" type="rotate" from="0 256 256" to="360 256 256" dur="10s" repeatCount="indefinite"/>' + '</g>' + // central squares (foreground) '<rect class="cls-1" x="236" y="236" width="15" height="15"/>' + '<rect class="cls-1" x="261" y="236" width="15" height="15"/>' + '<rect class="cls-1" x="261" y="261" width="15" height="15"/>' + '<rect class="cls-1" x="236" y="261" width="15" height="15"/>' + // rotating radar (populated + driven by JS; progress == its rotation) '<g id="dos-radar"></g>' + // centre marker on top of the radar '<rect id="dos-sndmark" fill="black" stroke="#FFD65C" x="253.5" y="253.5" width="5" height="5"/>' + '</g>' + '</svg>'; } /* ------------------------------------------------------------------- build UI */ var el = {}; function build() { var style = document.createElement("style"); style.id = "dos-loader-style"; style.textContent = css; document.head.appendChild(style); var root = document.createElement("div"); root.id = "dos-loader"; root.innerHTML = '<div id="dos-head">' + '<p class="l l1">DECENTRALIZED</p>' + '<p class="l l2">OPERATING</p>' + '<p class="l l3">SYSTEM</p>' + '<p class="sub">A fully onchain world for all the cypherdudes</p>' + '</div>' + drawingSVG() + '<div id="dos-status"><div id="dos-log"></div><span id="dos-status-pct">0%</span></div>'; document.body.appendChild(root); el.root = root; el.head = root.querySelector("#dos-head"); el.art = root.querySelector("#dos-art"); el.stat = root.querySelector("#dos-status"); el.radar = root.querySelector("#dos-radar"); el.pct = root.querySelector("#dos-status-pct"); el.log = root.querySelector("#dos-log"); buildRadar(); // Sound pre-arm: clicking the drawing toggles the ambient-audio intent // (window.DOS_SOUND_ON). The click is the user gesture the AudioContext // needs, so the shared context is created/resumed HERE and reused by the // world (COS_main.js initCtx); init() then starts the drone and the HUD // sound button shows ON. The centre marker fills amber while armed. el.art.style.cursor = "pointer"; el.art.setAttribute("title", "click to toggle sound"); el.art.addEventListener("click", function () { window.DOS_SOUND_ON = !window.DOS_SOUND_ON; try { var AC = window.AudioContext || window.webkitAudioContext; if (!window.__DOS_AUDIO_CTX && AC) window.__DOS_AUDIO_CTX = new AC({ sampleRate: 44100 }); if (window.__DOS_AUDIO_CTX && window.__DOS_AUDIO_CTX.state === "suspended") window.__DOS_AUDIO_CTX.resume(); } catch (e) { } // engine already injected -> apply immediately (starts/stops the drone) if (typeof window.setSoundState === "function") window.setSoundState(window.DOS_SOUND_ON); var mark = el.art.querySelector("#dos-sndmark"); if (mark) mark.setAttribute("fill", window.DOS_SOUND_ON ? "#FFD65C" : "black"); }); } /* --------------------------------------------------------------- radar sweep */ // A leading line from the centre + a fading trail of wedges (built once). function buildRadar() { if (!el.radar) return; var ACCENT = "#FFD65C", CX = 256, CY = 256, RIN = 0, ROUT = 128, SEG = 10, TRAIL = 58; function pt(r, deg) { var a = deg * Math.PI / 180; return [CX + r * Math.sin(a), CY - r * Math.cos(a)]; } function f(n) { return n.toFixed(2); } var buf = ""; for (var k = 0; k < SEG; k++) { var a0 = -(k + 1) * (TRAIL / SEG), a1 = -k * (TRAIL / SEG); var P0i = pt(RIN, a0), P0o = pt(ROUT, a0), P1o = pt(ROUT, a1), P1i = pt(RIN, a1); var op = (0.30 * (1 - k / SEG)).toFixed(3); buf += '<path d="M' + f(P0i[0]) + ',' + f(P0i[1]) + ' L' + f(P0o[0]) + ',' + f(P0o[1]) + ' L' + f(P1o[0]) + ',' + f(P1o[1]) + ' L' + f(P1i[0]) + ',' + f(P1i[1]) + ' Z" fill="' + ACCENT + '" fill-opacity="' + op + '"/>'; } var Lo = pt(ROUT, 0), Li = pt(RIN, 0); buf += '<line x1="' + f(Li[0]) + '" y1="' + f(Li[1]) + '" x2="' + f(Lo[0]) + '" y2="' + f(Lo[1]) + '" stroke="' + ACCENT + '" stroke-width="0.5" stroke-opacity="0.95"/>'; el.radar.innerHTML = buf; } /* ----------------------------------------------------------------- progress */ // Progress drives the radar rotation (one turn == 100%) and the %. The shown // value eases toward the target so discrete script loads sweep smoothly. var shown = 0, target = 0, raf = 0; function applyProgress(t) { if (el.radar) el.radar.setAttribute("transform", "rotate(" + (t * 360).toFixed(2) + " 256 256)"); if (el.pct) el.pct.textContent = Math.round(t * 100) + "%"; } function tick() { var d = target - shown; if (Math.abs(d) < 0.001) { shown = target; applyProgress(shown); raf = 0; return; } shown += d * 0.1; applyProgress(shown); raf = requestAnimationFrame(tick); } function setProgress(t) { target = Math.max(0, Math.min(1, t)); if (!raf) raf = requestAnimationFrame(tick); } /* ------------------------------------------------------------ terminal log */ var curLine = null; function markDone(line) { if (!line) return; if (!line.classList.contains("err")) line.className = "line done"; var mk = line.querySelector(".mk"); if (mk && !line.classList.contains("err")) mk.textContent = "✓"; // ✓ } function addLine(text) { if (!el.log) return; markDone(curLine); var d = document.createElement("div"); d.className = "line cur"; d.innerHTML = '<span class="mk">▸</span><span class="tx"></span>'; // ▸ d.querySelector(".tx").textContent = text; el.log.insertBefore(d, el.log.firstChild); // newest on the first line curLine = d; } function markError() { if (!curLine) return; curLine.className = "line err"; var mk = curLine.querySelector(".mk"); if (mk) mk.textContent = "✗"; // ✗ } /* --------------------------------------------------------------- responsive */ // Title scales to the band above the centred drawing; the drawing (kept // square) and the log are then matched to the title block's measured width. function layout() { if (!el.head || !el.root) return; var vh = window.innerHeight, vw = window.innerWidth; var gap = Math.max(14, Math.min(0.035 * vh, 40)); // mirrors --gap // measure title width/height per 1px of --tu at a reference size var REF = 200; el.root.style.setProperty("--tu", REF + "px"); var r = el.head.getBoundingClientRect(); var wPer = r.width / REF, hPer = r.height / REF; if (!wPer || !hPer) return; // drawing side = title width; keep centred => title fits the band above it: // hPer*tu <= (vh - wPer*tu)/2 - gap var tuFit = (vh - 2 * gap) / (2 * hPer + wPer); var tu = Math.max(24, Math.min(320, 0.92 * vw / wPer, tuFit)); el.root.style.setProperty("--tu", tu + "px"); var w = el.head.getBoundingClientRect().width; el.art.style.width = w + "px"; el.art.style.height = w + "px"; el.stat.style.width = w + "px"; } /* ---------------------------------------------------- scripty load + inject */ // Some historical on-chain blobs (notably the stored CypherDudesLayer1) still // carry a leftover `const fonts = `…`;` that collides with the canonical one in // CypherDudesFonts → "Identifier 'fonts' has already been declared". For the // modules listed here we strip that single declaration from the fetched text // before injecting, so CypherDudesFonts' `fonts` stays the only one. var STRIP_FONTS_FROM = { CypherDudesLayer1: 1 }; // Removes the first `const|let|var fonts = <string-literal>;` from `src`. // Handles backtick / single / double quoted literals (with escapes); if the // RHS isn't a plain string literal it leaves the source untouched. function stripFontsDecl(src) { var re = /\b(?:const|let|var)\s+fonts\s*=\s*/g; var m = re.exec(src); if (!m) return src; var start = m.index; var i = re.lastIndex; var q = src.charAt(i); if (q !== "`" && q !== '"' && q !== "'") return src; // not a simple literal — leave it i++; // past the opening delimiter for (; i < src.length; i++) { var ch = src.charAt(i); if (ch === "\\") { i++; continue; } // skip escaped char if (ch === q) { i++; break; } // closing delimiter } while (i < src.length && /\s/.test(src.charAt(i))) i++; // trailing whitespace if (src.charAt(i) === ";") i++; // optional semicolon return src.slice(0, start) + src.slice(i); } // (mirrors /Loader/loader.js) async function loadHexScript(hex, isGzipped, sc) { if (hex.startsWith("0x")) hex = hex.slice(2); var bytes = new Uint8Array(hex.length / 2); for (var i = 0; i < bytes.length; i++) bytes[i] = parseInt(hex.substr(i * 2, 2), 16); var jsCode; if (isGzipped) { // Two storage conventions supported: // • RAW gzip bytes (store-artifacts.mjs / deploySepolia.js) — detected // by the gzip magic number 0x1f 0x8b; // • legacy base64-of-gzip text — decoded via atob first. var gzipBytes; if (bytes.length > 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) { gzipBytes = bytes; } else { var base64 = ""; for (var j = 0; j < bytes.length; j++) base64 += String.fromCharCode(bytes[j]); gzipBytes = Uint8Array.from(atob(base64), function (c) { return c.charCodeAt(0); }); } var stream = new Response(gzipBytes).body.pipeThrough(new DecompressionStream("gzip")); jsCode = await new Response(stream).text(); } else { jsCode = new TextDecoder("utf-8").decode(bytes); } if (sc && STRIP_FONTS_FROM[sc.data]) jsCode = stripFontsDecl(jsCode); recordScriptSize(sc, jsCode); var script = document.createElement("script"); script.textContent = jsCode; document.head.appendChild(script); // inline scripts run synchronously on append } async function injectOne(txt, sc) { txt = txt.trim(); // Heuristic: a hex blob is only [0-9a-fA-Fx]. If the fetched file is raw JS // (e.g. a plain .js during local testing), inject it verbatim. var isHex = /^(0x)?[0-9a-fA-F]+$/.test(txt); if (isHex) { await loadHexScript(txt, sc.gzip, sc); } else { if (sc && STRIP_FONTS_FROM[sc.data]) txt = stripFontsDecl(txt); recordScriptSize(sc, txt); var script = document.createElement("script"); script.textContent = txt; document.head.appendChild(script); } } /* ------------------------------------------- shared RPC layer (GLOBAL) */ // The loader is the FIRST script on the page, so the RPC plumbing lives here // and is exposed on window: every script injected afterwards // (COS_ethCalls.js, COS_main.js, recompose.min.js, ...) reuses this ONE // pool instead of rebuilding its own — shared pacing + cooldown state. // // The onchain HTML build (DOSRenderer) injects the endpoint lists as strings // BEFORE this file runs: // RPCString / WSRPCString — getRpcs()/getWsRpcs() output: "['url','url',...]" // ClaimOrderString — claimOrder storage string: "[0,1153,...]" window.parseRpcString = function (s) { if (!s || typeof s !== "string") return null; try { var a = JSON.parse(s.replace(/'/g, '"')); return Array.isArray(a) ? a : null; } catch (e) { console.warn("parseRpcString: invalid input", e); return null; } }; window.parseClaimOrderString = function (s) { if (!s || typeof s !== "string") return null; try { var a = JSON.parse(s); return Array.isArray(a) ? a.map(Number) : null; } catch (e) { console.warn("parseClaimOrderString: invalid input", e); return null; } }; // Runtime endpoint arrays (contract-fed; window.RPCs may be pre-set for dev). window.RPCs = (typeof RPCString !== "undefined" && window.parseRpcString(RPCString)) || window.RPCs || []; window.WS_RPCs = (typeof WSRPCString !== "undefined" && window.parseRpcString(WSRPCString)) || window.WS_RPCs || []; // --- Parallel RPC pool (same principle as recompose.min.js) -------------- // Every non-empty https RPC becomes an endpoint with its own request pacing // (100ms between calls ≈ 10 req/s) and a jittered exponential cooldown when // it fails / rate-limits. Work is consumed by one worker per endpoint, each // call going to whichever endpoint frees up first — so N configured RPCs // load the world roughly N times faster without hammering any provider. window.rpcPool = { eps: null, build: function () { this.eps = window.RPCs.filter(function (u) { return u; }) .map(function (url) { return { url: url, nextFree: 0, cooldownUntil: 0 }; }); return this.eps; }, endpoints: function () { return (this.eps && this.eps.length) ? this.eps : this.build(); }, pick: function () { var eps = this.endpoints(); var now = Date.now(); var best = eps[0], t = Math.max(now, best.cooldownUntil, best.nextFree); for (var i = 1; i < eps.length; i++) { var ti = Math.max(now, eps[i].cooldownUntil, eps[i].nextFree); if (ti < t) { t = ti; best = eps[i]; } } best.nextFree = t + 100; return { ep: best, waitMs: t - now }; }, cooldown: function (ep, attempt) {
DOS_loader{"v":1,"algo":"raw","rawSize":34838,"storedSize":34838,"sha256raw":"0xe70293d58b0ac2d6568e74ae0806c3efa6ca788eb2192ee3f3e5b03cd1977025","sha256stored":"0xe70293d58b0ac2d6568e74ae0806c3efa6ca788eb2192ee3f3e5b03cd1977025"}
DOS_LoadingArrayvar DEFAULT_SCRIPTS = [ { data: "three-v0.147.0.min.js.gz", gzip: true, label: "three.js — renderer" }, { data: "F3_Utils", gzip: true, label: "utils — core helpers" }, { data: "css3DRenderer", gzip: true, label: "css3d — surface renderer" }, { data: "CypherDudesFonts", gzip: false, label: "fonts — Andale Mono MonoPixel" }, { data: "CypherDudesLayer1", gzip: false, label: "layer1 images" }, { data: "DOS_Spritesheet", gzip: true, label: "spritesheet — icons" }, { data: "DOS_ethCalls", gzip: true, label: "eth — onchain calls" }, { data: "DOS_os", gzip: true, label: "os — operating layer" }, { data: "DOS_bip39", gzip: true, label: "bip39 — mnemonics" }, { data: "DOS_main", gzip: true, label: "main — world builder" }, { data: "DOS_palace", gzip: true, label: "cypherpalace" }, { data: "DOS_artefacts", gzip: true, label: "artefacts handler" }, { data: "DOS_communityApps", gzip: true, label: "Community Apps management" }, { data: "recompose.min.js", gzip: true, label: "recompose — chunked artifact loader" }, { data: "DOS_animate", gzip: true, label: "animate — boot init()" } ];
DOS_LoadingArray{"v":1,"algo":"raw","rawSize":1285,"storedSize":1285,"sha256raw":"0x06255ea0e3db0f5b0fc11798ca7f2b6c0b4516b2347bf575f09ac92538c9cc61","sha256stored":"0x06255ea0e3db0f5b0fc11798ca7f2b6c0b4516b2347bf575f09ac92538c9cc61"}
DOS_animate{"v":1,"algo":"gzip","rawSize":34602,"storedSize":9231,"sha256raw":"0x000bbfb88cbd05cbb43713e25b8200066a27d2524f54085eede2cd047ecbc5ac","sha256stored":"0x5e545284bc304bd79fa9206aad1a6e69bd9443e9af133e589c73daf883984ba3"}
DOS_communityApps{"v":1,"algo":"gzip","rawSize":99354,"storedSize":25280,"sha256raw":"0xf38306da2375d705947273f467b296e3d887186241b2863412bd0d87639c6a19","sha256stored":"0xaff25204357b77cdfc6012d0f5691fe7dc04d1f420e2c9c2a79de6821ef9542e"}
DOS_artefacts{"v":1,"algo":"gzip","rawSize":14402,"storedSize":3556,"sha256raw":"0xebc5a9805e5acb438802d1c24918f81fa4e0f6d106811f9e497ea3a64ac58809","sha256stored":"0x53ba86d0db844dc7c771f46b926a9079a91d38f8c97d9565ccf3ca72d5093ae5"}
DOS_palace{"v":1,"algo":"gzip","rawSize":177176,"storedSize":42969,"sha256raw":"0xe15294acafd9d763808b6bdd969775ea24d76d4a957c2099cf3cb83fef129ea3","sha256stored":"0xedcde24c091f1e5fb93e838673b581736c50482601f8eb67d60681388653a30f"}
DOS_main{"v":1,"algo":"gzip","rawSize":288678,"storedSize":78845,"sha256raw":"0x05d79ad8a2dc6178ce2d8d2c6b8b88f26d1c3ede481ee31c17a9bb0bf5d1aa92","sha256stored":"0xa190abe138eb4f5d10f053a27350d7b5fff77fe7e37a9fae31c0fa9bb6762876"}
DOS_os{"v":1,"algo":"gzip","rawSize":327569,"storedSize":81450,"sha256raw":"0x5260ca75dd007a694790450ebe6deb835b05a47227b61e7e6c3fcfca0ccef177","sha256stored":"0x8bd70d1636c61faf9b19e4e159850b5b0271511e7e17108dd61e389c648f04d8"}
DOS_ethCalls{"v":1,"algo":"gzip","rawSize":128469,"storedSize":32897,"sha256raw":"0x9d6819489764725c3c28628057eaab93db816a26aa0723ccaab397a5af94a83f","sha256stored":"0x781ea626a8fad71e62be65c3a2df76e70fe481f6c8b652b89904622c445da871"}
recompose.min.js{"v":1,"algo":"gzip","rawSize":12824,"storedSize":5013,"sha256raw":"0xeeba18e839756c56f9ae3e1a579c76dda314c731c93f1a0c775ed59e6dadc2e0","sha256stored":"0xafe0b9d02c0dabaeaefa7b3a47e29c01e776aceffad34945c4a4229f716fa579"}
DOS_bip39{"v":1,"algo":"gzip","rawSize":13130,"storedSize":6399,"sha256raw":"0x3ba9a0847bda0d5ad6100d01527095dd4e05ba02e5d65a89f70ff47dca070234","sha256stored":"0xac7d0381003ef6e6cb848a5005f7b192fde7e1247b1729ba1d605ba57215798b"}
DOS_Spritesheet{"v":1,"algo":"gzip","rawSize":16627,"storedSize":12579,"sha256raw":"0x1e1cbbce08db1ec08da6ecaae1129058b2f3043dea71c3db26b23edde7eb6c73","sha256stored":"0xb236630fd4ee20e3d617f3c77d7947c7c1ac0957dfcff925f33868bf3bc39c26"}
css3DRenderer{"v":1,"algo":"gzip","rawSize":6470,"storedSize":1715,"sha256raw":"0x55e8047d0a6d7383f7b451631d84c41dccb550feb29527fa425c9c8df39f5608","sha256stored":"0x57c4310c5e99179ae35e255e14fc117105e108e1b5988601990e6c140017fd59"}
Resonance drawingContext.lineJoin = 'round'; for (let i = 0; i < numStrokes; i++) { const tBase = (i + 0.3 + 0.4 * rnd()) / numStrokes; const s = tBase * totalLen; const { x, y, tx, ty } = sampleAt(s); const hairRoll = rnd(); const numHairs = hairRoll < 0.65 ? 1 : (hairRoll < 0.92 ? 2 : 3); for (let h = 0; h < numHairs; h++) { const strokeLen = baseWeight * (0.9 + 3.1 * rnd()); const baseAng = Math.atan2(ty, tx); const angJitter = (rnd() - 0.5) * 0.55; const a = baseAng + angJitter; const perpDist = (rnd() - 0.5) * (1.4 * M + baseWeight * 0.9); const px = -ty * perpDist; const py = tx * perpDist; const cosA = Math.cos(a), sinA = Math.sin(a); const cx = x + px; const cy = y + py; const x1 = cx - cosA * strokeLen / 2; const y1 = cy - sinA * strokeLen / 2; const x2 = cx + cosA * strokeLen / 2; const y2 = cy + sinA * strokeLen / 2; const variant = variants[Math.floor(rnd() * variants.length)]; const alpha = Math.floor((90 + rnd() * 130) * energyFactor); const w = baseWeight * (0.30 + 0.95 * Math.pow(rnd(), 1.35)); drawingContext.strokeStyle = `rgba(${variant.r},${variant.g},${variant.b},${alpha / 255})`; drawingContext.lineWidth = w; drawingContext.beginPath(); drawingContext.moveTo(x1, y1); drawingContext.lineTo(x2, y2); drawingContext.stroke(); } } pop(); } function drawSmoothCurve(pts) { beginShape(); curveVertex(pts[0].x, pts[0].y); for (const p of pts) curveVertex(p.x, p.y); curveVertex(pts[pts.length - 1].x, pts[pts.length - 1].y); endShape(); } function drawAnnotations(P) { const inkCol = color(P.ink); push(); stroke(red(inkCol), green(inkCol), blue(inkCol), 130); strokeWeight(0.6); drawingContext.lineCap = 'butt'; const margin = canvasSize * 0.058; const ruleY = margin * 0.6; const tickStart = margin, tickEnd = canvasSize - margin; line(tickStart, ruleY, tickEnd, ruleY); const numTicks = 24; for (let i = 0; i <= numTicks; i++) { const x = tickStart + (tickEnd - tickStart) * (i / numTicks); const tickLen = (i % 4 === 0) ? 6 : 3; line(x, ruleY - tickLen, x, ruleY); } const sbY = canvasSize - margin * 0.6; const sbX = canvasSize - margin - 80; line(sbX, sbY, sbX + 60, sbY); for (let i = 0; i <= 4; i++) { line(sbX + i * 15, sbY, sbX + i * 15, sbY - 5); } pop(); } function drawFrame(P) { const margin = canvasSize * 0.04; push(); noFill(); stroke(P.ink); strokeWeight(1); rect(margin, margin, canvasSize - 2 * margin, canvasSize - 2 * margin); stroke(red(color(P.ink)), green(color(P.ink)), blue(color(P.ink)), 90); strokeWeight(0.5); rect(margin + 6, margin + 6, canvasSize - 2 * margin - 12, canvasSize - 2 * margin - 12); pop(); } function drawInkSplatter(P) { const inkCol = color(P.ink); const r = red(inkCol), g = green(inkCol), b = blue(inkCol); push(); noStroke(); const numFine = 600; for (let i = 0; i < numFine; i++) { const u = rnd(), v = rnd(); const lf = sampleField(lowGrid, u, v); if (rnd() > Math.abs(lf) * 0.6 + 0.05) continue; const a = rrange(20, 90); fill(r, g, b, a); const sz = rrange(0.5, 1.6); circle(u * canvasSize, v * canvasSize, sz); } const numLarge = 12; for (let i = 0; i < numLarge; i++) { const u = rnd(), v = rnd(); fill(r, g, b, rrange(50, 100)); const sz = rrange(1.8, 4.5); circle(u * canvasSize, v * canvasSize, sz); if (rchance(0.6)) { fill(r, g, b, 25); circle(u * canvasSize, v * canvasSize, sz * 2.5); } } pop(); } function drawFinalOverlay(P) { const G = 384; const small = createImage(G, G); small.loadPixels(); for (let i = 0; i < G * G; i++) { const v = (rnd() - 0.5) * 12; const a = Math.abs(v); small.pixels[i * 4 + 0] = 0; small.pixels[i * 4 + 1] = 0; small.pixels[i * 4 + 2] = 0; small.pixels[i * 4 + 3] = a; } small.updatePixels(); push(); drawingContext.globalCompositeOperation = 'multiply'; drawingContext.imageSmoothingEnabled = false; image(small, 0, 0, canvasSize, canvasSize); drawingContext.imageSmoothingEnabled = true; drawingContext.globalCompositeOperation = 'source-over'; pop(); push(); const grd = drawingContext.createRadialGradient( canvasSize / 2, canvasSize / 2, canvasSize * 0.45, canvasSize / 2, canvasSize / 2, canvasSize * 0.78 ); grd.addColorStop(0, 'rgba(0,0,0,0)'); grd.addColorStop(1, 'rgba(0,0,0,0.10)'); drawingContext.fillStyle = grd; drawingContext.fillRect(0, 0, canvasSize, canvasSize); pop(); } function mousePressed() { if (seedLocked) return; // canonical on-chain piece — don't re-roll if (mouseX < 0 || mouseX > canvasSize || mouseY < 0 || mouseY > canvasSize) return; seed = Math.floor(Math.random() * 999999); location.hash = String(seed); generate(); } function keyPressed() { if (key === 's' || key === 'S') { saveCanvas('Resonance_' + seed, 'png'); } else if (key === 'p' || key === 'P') { exportPrintPng(); } else if (!seedLocked && keyCode === LEFT_ARROW) { seed = Math.max(1, seed - 1); location.hash = String(seed); generate(); } else if (!seedLocked && keyCode === RIGHT_ARROW) { seed = seed + 1; location.hash = String(seed); generate(); } } function exportPrintPng() { if (!composition) return; const screenSize = canvasSize; const screenM = M; const screenDensity = pixelDensity(); const t0 = performance.now(); console.log(`exporting ${PRINT_EXPORT_SIZE}x${PRINT_EXPORT_SIZE} print PNG...`); try { pixelDensity(PRINT_EXPORT_PIXEL_DENSITY); canvasSize = PRINT_EXPORT_SIZE; M = canvasSize / DEFAULT_SIZE; resizeCanvas(canvasSize, canvasSize); renderPaper(); renderArtwork(); saveCanvas('Resonance_' + seed, 'png'); } finally { pixelDensity(screenDensity || SCREEN_PIXEL_DENSITY); canvasSize = screenSize; M = screenM; resizeCanvas(canvasSize, canvasSize); renderPaper(); needsRender = true; redraw(); } const t1 = performance.now(); console.log(`print export ${(t1 - t0).toFixed(0)} ms`); } function windowResized() { const newSize = Math.floor(Math.min(window.innerWidth, window.innerHeight)); if (newSize !== canvasSize) { canvasSize = newSize; M = canvasSize / DEFAULT_SIZE; pixelDensity(SCREEN_PIXEL_DENSITY); resizeCanvas(canvasSize, canvasSize); if (composition) { renderPaper(); } needsRender = true; redraw(); } }
Resonance return (a * (1 - tx) + b * tx) * (1 - ty) + (c * (1 - tx) + d * tx) * ty; } function getDominantSource(x, y) { const fx = Math.max(0, Math.min(gridW - 1, Math.round(x * (gridW - 1)))); const fy = Math.max(0, Math.min(gridH - 1, Math.round(y * (gridH - 1)))); const v = domGrid[fy * gridW + fx]; return Math.round((v / 255) * (MAX_SOURCES - 1)); } function draw() { if (!composition || !needsRender) return; needsRender = false; const t0 = performance.now(); renderArtwork(); handleAutoSaveAfterRender(); const t1 = performance.now(); console.log(`render ${(t1 - t0).toFixed(0)} ms`); } function handleAutoSaveAfterRender() { if (!ifSave && !ifBulk) return; saveCanvas('Resonance_' + seed, 'png'); if (ifBulk) { setTimeout(() => { seed = Math.floor(Math.random() * 999999); location.hash = String(seed); generate(); }, 350); } } function renderArtwork() { const P = composition.palette; noStroke(); background(P.paper); if (paperImg) image(paperImg, 0, 0, canvasSize, canvasSize); setSeed(seed * 7 + 1); drawSubstrateGrain(P); setSeed(seed * 11 + 3); drawSubstrateGrid(P); setSeed(seed * 13 + 5); drawGapCircles(P); setSeed(seed * 17 + 7); drawContours(P); } function drawSubstrateGrain(P) { const G = 512; const img = createImage(G, G); img.loadPixels(); for (let i = 0; i < G * G; i++) { const v = rnd() * rnd(); if (v > 0.65) { const a = (v - 0.65) * 3.0; img.pixels[i * 4 + 0] = 0; img.pixels[i * 4 + 1] = 0; img.pixels[i * 4 + 2] = 0; img.pixels[i * 4 + 3] = Math.min(75, Math.floor(a * 110)); } else { img.pixels[i * 4 + 3] = 0; } } img.updatePixels(); push(); drawingContext.imageSmoothingEnabled = false; drawingContext.globalCompositeOperation = 'multiply'; image(img, 0, 0, canvasSize, canvasSize); drawingContext.globalCompositeOperation = 'source-over'; drawingContext.imageSmoothingEnabled = true; pop(); } function drawSubstrateGrid(P) { const inkCol = color(P.ink); const r = red(inkCol), g = green(inkCol), b = blue(inkCol); const minorCells = 200; const minorSpacing = canvasSize / minorCells; const tremor = 0.35 * M; push(); drawingContext.lineCap = 'butt'; drawingContext.strokeStyle = `rgba(${r},${g},${b},0.14)`; drawingContext.lineWidth = 0.34 * M; for (let n = 0; n <= minorCells; n++) { const x = n * minorSpacing; const ox = (Math.sin(n * 13.7 + seed * 0.011) + Math.sin(n * 41.3 + seed * 0.007) * 0.5) * tremor; drawingContext.beginPath(); drawingContext.moveTo(x + ox, 0); drawingContext.lineTo(x + ox, canvasSize); drawingContext.stroke(); } for (let n = 0; n <= minorCells; n++) { const y = n * minorSpacing; const oy = (Math.cos(n * 17.1 + seed * 0.013) + Math.cos(n * 39.7 + seed * 0.009) * 0.5) * tremor; drawingContext.beginPath(); drawingContext.moveTo(0, y + oy); drawingContext.lineTo(canvasSize, y + oy); drawingContext.stroke(); } pop(); } function drawWash(P) { const washImg = createImage(gridW, gridH); washImg.loadPixels(); const groundCol = color(P.ground); const accentCol = color(P.accent); const sec1Col = color(P.sec1); const gR = red(groundCol), gG = green(groundCol), gB = blue(groundCol); const aR = red(accentCol), aG = green(accentCol), aB = blue(accentCol); const sR = red(sec1Col), sG = green(sec1Col), sB = blue(sec1Col); for (let j = 0; j < gridH; j++) { for (let i = 0; i < gridW; i++) { const idx = (j * gridW + i) * 4; const lf = lowGrid[j * gridW + i]; const t = Math.max(0, lf); const tneg = Math.max(0, -lf) * 0.45; const alpha = Math.min(1, t * 0.55 + tneg * 0.45); const mix = tneg / (t + tneg + 0.0001); const sec1Mix = (1 - mix) * 0.25; let r = gR * (1 - mix - sec1Mix) + aR * mix + sR * sec1Mix; let g = gG * (1 - mix - sec1Mix) + aG * mix + sG * sec1Mix; let b = gB * (1 - mix - sec1Mix) + aB * mix + sB * sec1Mix; washImg.pixels[idx + 0] = r; washImg.pixels[idx + 1] = g; washImg.pixels[idx + 2] = b; washImg.pixels[idx + 3] = Math.floor(alpha * 110); } } washImg.updatePixels(); push(); drawingContext.imageSmoothingEnabled = true; image(washImg, 0, 0, canvasSize, canvasSize); pop(); } function drawRegionFills(P) { const palette = composition.palette; const colorOf = (key) => key ? color(palette[key]) : null; for (let s = 0; s < composition.numSources; s++) { const src = composition.sources[s]; if (src.fill === 'none') continue; const fillCol = colorOf(src.fillColor) || color(palette.ink); if (src.fill === 'stipple') drawStipple(s, fillCol); else if (src.fill === 'crosshatch') drawCrossHatch(s, fillCol); else if (src.fill === 'rings') drawInnerRings(s, src, fillCol); else if (src.fill === 'solid') drawSolidFill(s, fillCol); else if (src.fill === 'ribbon') drawRibbon(s, src, fillCol); else if (src.fill === 'dots-grid') drawDotsGrid(s, fillCol); } } function drawStipple(sourceIndex, fillCol) { push(); fill(red(fillCol), green(fillCol), blue(fillCol), 200); noStroke(); const step = canvasSize / 110; for (let y = 0; y < canvasSize; y += step) { for (let x = 0; x < canvasSize; x += step) { const u = (x + (rnd() - 0.5) * step) / canvasSize; const v = (y + (rnd() - 0.5) * step) / canvasSize; if (u < 0 || u > 1 || v < 0 || v > 1) continue; if (getDominantSource(u, v) !== sourceIndex) continue; const f = sampleField(fieldGrid, u, v); const lf = sampleField(lowGrid, u, v); if (lf < 0.15) continue; if (Math.abs(f) < 0.15) continue; const density = Math.abs(f) * 0.7 + lf * 0.4; if (rnd() > density * 1.6) continue; const r = step * 0.18 + Math.abs(f) * step * 0.15; circle(u * canvasSize, v * canvasSize, r); } } pop(); } function drawCrossHatch(sourceIndex, fillCol) { const baseAngle = composition.hatchAngle + (rnd() - 0.5) * 0.4; push(); drawingContext.lineCap = 'round'; for (let pass = 0; pass < 2; pass++) { const a = baseAngle + (pass === 0 ? -0.5 : 0.5); const cosA = Math.cos(a), sinA = Math.sin(a); const spacing = canvasSize / (110 + pass * 10); stroke(red(fillCol), green(fillCol), blue(fillCol), 130); strokeWeight(0.6); for (let s = -canvasSize; s < canvasSize * 2; s += spacing) { const samples = 220; let inSeg = false, segStart = null; for (let k = 0; k <= samples; k++) { const u = k / samples; const cx = canvasSize / 2 + (-sinA) * s + cosA * (u - 0.5) * canvasSize * 1.6; const cy = canvasSize / 2 + (cosA) * s + sinA * (u - 0.5) * canvasSize * 1.6; const ux = cx / canvasSize, uy = cy / canvasSize; let inRegion = false; if (ux >= 0 && ux <= 1 && uy >= 0 && uy <= 1 && getDominantSource(ux, uy) === sourceIndex) { const lf = sampleField(lowGrid, ux, uy); if (lf > 0.12) inRegion = true; } if (inRegion) { if (!inSeg) { segStart = { x: cx, y: cy }; inSeg = true; } } else { if (inSeg) { line(segStart.x, segStart.y, cx, cy); inSeg = false; } } } } } pop(); } function drawInnerRings(sourceIndex, src, fillCol) { push(); noFill(); stroke(red(fillCol), green(fillCol), blue(fillCol), 200); drawingContext.lineCap = 'round'; const cx = src.x * canvasSize, cy = src.y * canvasSize; for (let k = 1; k <= 18; k++) { const r = k * canvasSize * 0.012; strokeWeight(0.6 + (k % 3 === 0 ? 0.4 : 0)); const samples = 140; let prev = null; for (let s = 0; s <= samples; s++) { const t = s / samples; const a = t * Math.PI * 2; const px = cx + Math.cos(a) * r; const py = cy + Math.sin(a) * r; const ux = px / canvasSize, uy = py / canvasSize; if (ux < 0 || ux > 1 || uy < 0 || uy > 1) { prev = null; continue; } const inRegion = getDominantSource(ux, uy) === sourceIndex; if (inRegion && prev) line(prev.x, prev.y, px, py); prev = inRegion ? { x: px, y: py } : null; } } pop(); } function drawSolidFill(sourceIndex, fillCol) { const mw = 256, mh = 256; const img = createImage(mw, mh); img.loadPixels(); const fr = red(fillCol), fg = green(fillCol), fb = blue(fillCol); for (let j = 0; j < mh; j++) { for (let i = 0; i < mw; i++) { const u = i / (mw - 1), v = j / (mh - 1); const idx = (j * mw + i) * 4; const dom = getDominantSource(u, v); if (dom !== sourceIndex) { img.pixels[idx + 3] = 0; continue; } const lf = sampleField(lowGrid, u, v); if (lf < 0.08) { img.pixels[idx + 3] = 0; continue; } const a = Math.min(1, Math.max(0, lf * 1.4 - 0.05)); const dither = rnd() < a ? 1 : a * 0.4; img.pixels[idx + 0] = fr; img.pixels[idx + 1] = fg; img.pixels[idx + 2] = fb; img.pixels[idx + 3] = Math.floor(dither * 200); } } img.updatePixels(); push(); drawingContext.imageSmoothingEnabled = true; drawingContext.globalCompositeOperation = 'multiply'; image(img, 0, 0, canvasSize, canvasSize); drawingContext.globalCompositeOperation = 'source-over'; pop(); } function drawRibbon(sourceIndex, src, fillCol) { push(); drawingContext.lineCap = 'butt'; const cx = src.x * canvasSize, cy = src.y * canvasSize; for (let k = 0; k < 8; k++) { const baseR = k * canvasSize * 0.025 + canvasSize * 0.01; const w = canvasSize * 0.012; const a = 90 + (k % 2) * 70; stroke(red(fillCol), green(fillCol), blue(fillCol), a); strokeWeight(w); noFill(); const samples = 200; let prev = null; for (let s = 0; s <= samples; s++) { const t = s / samples; const ang = t * Math.PI * 2; const rr = baseR * (1 + 0.06 * Math.sin(ang * 5 + k * 0.7)); const px = cx + Math.cos(ang) * rr; const py = cy + Math.sin(ang) * rr; const ux = px / canvasSize, uy = py / canvasSize; if (ux < 0 || ux > 1 || uy < 0 || uy > 1) { prev = null; continue; } const inRegion = getDominantSource(ux, uy) === sourceIndex; if (inRegion && prev) line(prev.x, prev.y, px, py); prev = inRegion ? { x: px, y: py } : null; } } pop(); } function drawDotsGrid(sourceIndex, fillCol) { push(); noStroke(); fill(red(fillCol), green(fillCol), blue(fillCol), 200); const step = canvasSize / 60; for (let y = step / 2; y < canvasSize; y += step) { for (let x = step / 2; x < canvasSize; x += step) { const u = x / canvasSize, v = y / canvasSize; if (getDominantSource(u, v) !== sourceIndex) continue; const lf = sampleField(lowGrid, u, v); if (lf < 0.12) continue; const f = sampleField(fieldGrid, u, v); const r = step * 0.16 + Math.abs(f) * step * 0.12; circle(x, y, r); } } pop(); } function drawHatching(P) { const inkCol = color(P.ink); const angle = composition.hatchAngle; const spacing = canvasSize / 95; const cosA = Math.cos(angle), sinA = Math.sin(angle); push(); stroke(red(inkCol), green(inkCol), blue(inkCol), 50); strokeWeight(0.5); drawingContext.lineCap = 'round'; const hatchThreshold = -0.35; const len = canvasSize * 1.6; for (let s = -canvasSize; s < canvasSize * 2; s += spacing) { const samples = 280; let inSeg = false, segStart = null; for (let k = 0; k <= samples; k++) { const u = k / samples; const cx = canvasSize / 2 + (-sinA) * s + cosA * (u - 0.5) * len; const cy = canvasSize / 2 + (cosA) * s + sinA * (u - 0.5) * len; if (cx < 0 || cx >= canvasSize || cy < 0 || cy >= canvasSize) { if (inSeg) { line(segStart.x, segStart.y, cx, cy); inSeg = false; } continue; } const ux = cx / canvasSize, uy = cy / canvasSize; const v = sampleField(fieldGrid, ux, uy); if (v < hatchThreshold) { if (!inSeg) { segStart = { x: cx, y: cy }; inSeg = true; } } else { if (inSeg) { line(segStart.x, segStart.y, cx, cy); inSeg = false; } } } } pop(); } function drawGapCircles(P) { const inkCol = color(P.ink); const accentCol = color(P.accent); const inkR = red(inkCol), inkG = green(inkCol), inkB = blue(inkCol); const accR = red(accentCol), accG = green(accentCol), accB = blue(accentCol); const gw = gridW, gh = gridH; const gradMag = new Float32Array(gw * gh); for (let j = 1; j < gh - 1; j++) { for (let i = 1; i < gw - 1; i++) { const gx = fieldGrid[j * gw + (i + 1)] - fieldGrid[j * gw + (i - 1)]; const gy = fieldGrid[(j + 1) * gw + i] - fieldGrid[(j - 1) * gw + i]; gradMag[j * gw + i] = Math.hypot(gx, gy); } } const cd = composition.circleDensity != null ? composition.circleDensity : 0.7; const lerp = (a, b, t) => a + (b - a) * t; const gapThreshold = lerp(0.04, 0.10, cd); const cellsPerSide = lerp(70, 130, cd); const cellSizeNorm = 1 / cellsPerSide; const candidateCount = Math.max(1, Math.ceil(cellsPerSide - 0.5)); const placed = []; const HASH_CELL_NORM = 14 / DEFAULT_SIZE; const hashCols = Math.ceil(1 / HASH_CELL_NORM) + 1; const hashGrid = new Map(); const hashKey = (i, j) => i * hashCols + j; const hashAdd = (p) => { const i = Math.floor(p.u / HASH_CELL_NORM); const j = Math.floor(p.v / HASH_CELL_NORM); const k = hashKey(i, j); if (!hashGrid.has(k)) hashGrid.set(k, []); hashGrid.get(k).push(p); }; const placementCoef = lerp(0.7, 1.05, cd); const radiusBaseNorm = lerp(1.2, 1.8, cd) / DEFAULT_SIZE; const radiusRangeNorm = lerp(3.0, 5.0, cd) / DEFAULT_SIZE; const spacingBufferNorm = lerp(1.5, -2.5, cd) / DEFAULT_SIZE; const edgeClampNorm = 4 / DEFAULT_SIZE; for (let cy = 0; cy < candidateCount; cy++) { for (let cx = 0; cx < candidateCount; cx++) { const cu = (cx + 0.5) * cellSizeNorm; const cv = (cy + 0.5) * cellSizeNorm; const jU = cu + (rnd() - 0.5) * cellSizeNorm * 0.7; const jV = cv + (rnd() - 0.5) * cellSizeNorm * 0.7; if (jU < edgeClampNorm || jV < edgeClampNorm || jU > 1 - edgeClampNorm || jV > 1 - edgeClampNorm) continue; const jx = jU * canvasSize; const jy = jV * canvasSize; const gi = Math.max(1, Math.min(gw - 2, Math.round(jU * (gw - 1)))); const gj = Math.max(1, Math.min(gh - 2, Math.round(jV * (gh - 1)))); const grad = gradMag[gj * gw + gi]; if (grad > gapThreshold) continue; const placementProb = placementCoef * (1 - grad / gapThreshold); if (rnd() > placementProb) continue; const rRadiusNorm = radiusBaseNorm + radiusRangeNorm * (1 - grad / gapThreshold) * (0.5 + 0.5 * rnd()); const rRadius = rRadiusNorm * canvasSize; const hi = Math.floor(jU / HASH_CELL_NORM); const hj = Math.floor(jV / HASH_CELL_NORM); let tooClose = false; outer: for (let di = -1; di <= 1; di++) { for (let dj = -1; dj <= 1; dj++) { const bucket = hashGrid.get(hashKey(hi + di, hj + dj)); if (!bucket) continue; for (const p of bucket) { const du = p.u - jU, dv = p.v - jV; const minD = p.rNorm + rRadiusNorm + spacingBufferNorm; if (du * du + dv * dv < minD * minD) { tooClose = true; break outer; } } } } if (tooClose) continue; const newCircle = { u: jU, v: jV, rNorm: rRadiusNorm }; placed.push(newCircle); hashAdd(newCircle); } } push(); drawingContext.lineCap = 'round'; drawingContext.lineJoin = 'round'; for (const c of placed) { drawScribbledCircle(c.u * canvasSize, c.v * canvasSize, c.rNorm * canvasSize, inkR, inkG, inkB, accR, accG, accB); } pop(); } function drawScribbledCircle(cx, cy, radius, inkR, inkG, inkB, accR, accG, accB) { const numPasses = radius < 2.5 * M ? (1 + (rnd() < 0.4 ? 1 : 0)) : (2 + Math.floor(rnd() * 3)); const mixColors = rnd() < 0.4; const dominantIsAccent = rnd() < 0.18; for (let pass = 0; pass < numPasses; pass++) { const startA = rnd() * Math.PI * 2; const arcSpan = (0.7 + 1.6 * rnd()) * Math.PI * 2; const direction = rnd() < 0.5 ? 1 : -1; const segs = Math.max(8, Math.floor((radius / M) * 2.5 * (arcSpan / (Math.PI * 2)))); const noisePhase = rnd() * Math.PI * 2; const noiseFreq = 2 + rnd() * 4; const noiseAmp = radius * (0.12 + 0.20 * rnd()); let r0, g0, b0; if (mixColors) { if (rnd() < 0.35) { r0 = accR; g0 = accG; b0 = accB; } else { r0 = inkR; g0 = inkG; b0 = inkB; } } else { if (dominantIsAccent) { r0 = accR; g0 = accG; b0 = accB; } else { r0 = inkR; g0 = inkG; b0 = inkB; } } r0 += (rnd() - 0.5) * 18; g0 += (rnd() - 0.5) * 18; b0 += (rnd() - 0.5) * 18; r0 = Math.max(0, Math.min(255, r0)); g0 = Math.max(0, Math.min(255, g0)); b0 = Math.max(0, Math.min(255, b0)); const alpha = 0.30 + 0.30 * rnd(); const w = (0.5 + 0.6 * rnd()) * M; drawingContext.strokeStyle = `rgba(${r0 | 0},${g0 | 0},${b0 | 0},${alpha})`; drawingContext.lineWidth = w; drawingContext.beginPath(); for (let i = 0; i <= segs; i++) { const t = i / segs; const a = startA + direction * arcSpan * t; const wob = Math.sin(a * noiseFreq + noisePhase) * noiseAmp + Math.sin(a * (noiseFreq * 1.7) + noisePhase * 1.3) * (noiseAmp * 0.5) + (rnd() - 0.5) * radius * 0.10; const r = radius + wob; const px = cx + Math.cos(a) * r; const py = cy + Math.sin(a) * r; if (i === 0) drawingContext.moveTo(px, py); else drawingContext.lineTo(px, py); } drawingContext.stroke(); } } function drawContours(P) { const inkCol = color(P.ink); const primaryCol = color(P.primary); const accentCol = color(P.accent); const featureLevels = new Set(); const numLevels = composition.contourLevels.length; featureLevels.add(Math.floor(numLevels * 0.25)); featureLevels.add(Math.floor(numLevels * 0.75)); if (rnd() < 0.5) featureLevels.add(Math.floor(numLevels * 0.5)); for (let lvl = 0; lvl < numLevels; lvl++) { const t = composition.contourLevels[lvl]; const threshold = (t - 0.5) * 1.7; const polylines = marchingSquares(fieldGrid, gridW, gridH, threshold); let strokeCol, weight; const isFeature = featureLevels.has(lvl); const isCenter = Math.abs(t - 0.5) < 0.06; if (isCenter) { strokeCol = accentCol; weight = composition.baseWeight * 2.8 * M; } else if (isFeature) { strokeCol = primaryCol; weight = composition.baseWeight * 2.0 * M; } else { strokeCol = inkCol; weight = composition.baseWeight * (0.7 + 0.6 * Math.abs(t - 0.5) * 2) * M; } const levelWeightVariation = isCenter ? 0.92 + 0.36 * rnd() : (isFeature ? 0.80 + 0.55 * rnd() : 0.65 + 0.75 * rnd()); for (const poly of polylines) { if (poly.length < 4) continue; const polyWeightVariation = 0.82 + 0.36 * rnd(); drawPencilContour(poly, strokeCol, weight * levelWeightVariation * polyWeightVariation); } } } function drawPencilContour(polyline, col, baseWeight) { const pts = polyline.map(p => { const gx = Math.min(gridW - 1, Math.max(0, Math.round(p.x))); const gy = Math.min(gridH - 1, Math.max(0, Math.round(p.y))); return { x: (p.x / (gridW - 1)) * canvasSize, y: (p.y / (gridH - 1)) * canvasSize, gx, gy }; }); let energySum = 0; for (const p of pts) energySum += Math.abs(lowGrid[p.gy * gridW + p.gx]); const energyAvg = energySum / pts.length; const energyFactor = Math.min(1, 0.18 + energyAvg * 1.6); const tremor = Math.max(0.3 * M, 1.6 * M - baseWeight * 0.4); const tpts = pts.map((p, i) => { const dx = (Math.sin(i * 0.31 + seed * 0.013) + Math.sin(i * 0.117 + seed * 0.027) * 0.6) * tremor; const dy = (Math.cos(i * 0.27 + seed * 0.019) + Math.cos(i * 0.131 + seed * 0.033) * 0.6) * tremor; return { x: p.x + dx, y: p.y + dy }; }); const cumulative = [0]; for (let i = 1; i < tpts.length; i++) { const dx = tpts[i].x - tpts[i - 1].x; const dy = tpts[i].y - tpts[i - 1].y; cumulative.push(cumulative[i - 1] + Math.hypot(dx, dy)); } const totalLen = cumulative[cumulative.length - 1]; if (totalLen < 4 * M) return; const r = red(col), g = green(col), b = blue(col); if ((baseWeight / M) > composition.baseWeight * 1.4) { push(); noFill(); stroke(r, g, b, Math.floor(32 * energyFactor)); strokeWeight(baseWeight * 3.0); drawingContext.lineCap = 'round'; drawingContext.lineJoin = 'round'; drawSmoothCurve(tpts); pop(); } const variants = makeColorVariants(r, g, b); const unscaledWeight = baseWeight / M; const density = 0.38 + 0.82 * Math.min(1, unscaledWeight / (composition.baseWeight * 2.8)); const numStrokes = Math.max(2, Math.floor((totalLen / M) * density)); let lastIdx = 1; const sampleAt = (s) => { while (lastIdx > 1 && cumulative[lastIdx - 1] > s) lastIdx--; while (lastIdx < cumulative.length - 1 && cumulative[lastIdx] < s) lastIdx++; const i = lastIdx; const segStart = cumulative[i - 1]; const segLen = cumulative[i] - segStart; const t = segLen > 0 ? (s - segStart) / segLen : 0; const x = tpts[i - 1].x * (1 - t) + tpts[i].x * t; const y = tpts[i - 1].y * (1 - t) + tpts[i].y * t; let tx = tpts[i].x - tpts[i - 1].x; let ty = tpts[i].y - tpts[i - 1].y; const tlen = Math.hypot(tx, ty); if (tlen > 0) { tx /= tlen; ty /= tlen; } else { tx = 1; ty = 0; } return { x, y, tx, ty }; }; push(); drawingContext.lineCap = 'round';
Resonancelet RNG_STATE = 1; function setSeed(s) { RNG_STATE = (s >>> 0) || 1; } function rnd() { let t = RNG_STATE += 0x6D2B79F5; t = Math.imul(t ^ (t >>> 15), t | 1); t ^= t + Math.imul(t ^ (t >>> 7), t | 61); return ((t ^ (t >>> 14)) >>> 0) / 4294967296; } const rrange = (a, b) => a + (b - a) * rnd(); const rint = (a, b) => Math.floor(rrange(a, b + 1)); const rpick = (arr) => arr[Math.floor(rnd() * arr.length)]; const rchance = (p) => rnd() < p; const rgauss = () => { let u = 1 - rnd(), v = rnd(); return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v); }; const rshuffle = (arr) => { const a = arr.slice(); for (let i = a.length - 1; i > 0; i--) { const j = Math.floor(rnd() * (i + 1)); [a[i], a[j]] = [a[j], a[i]]; } return a; }; function makeColorVariants(r, g, b) { const clamp = v => Math.max(0, Math.min(255, v | 0)); return [ { r: clamp(r), g: clamp(g), b: clamp(b) }, { r: clamp(r + 18), g: clamp(g + 15), b: clamp(b + 10) }, { r: clamp(r - 14), g: clamp(g - 12), b: clamp(b - 8) }, { r: clamp(r + 10), g: clamp(g + 5), b: clamp(b - 2) }, { r: clamp(r - 2), g: clamp(g + 4), b: clamp(b + 14) }, ]; } const PALETTES = [ { name: 'Cyanotype', paper: '#ecdfc8', ground: '#7a96b3', primary: '#1c3a5e', accent: '#c44536', ink: '#0d1b2a', sec1: '#a8b8c8', sec2: '#5d2a1a' }, { name: 'Bauhaus', paper: '#f0e7d2', ground: '#d6a24a', primary: '#2c2a4a', accent: '#a23216', ink: '#16161a', sec1: '#9a8268', sec2: '#3a4a6c' }, { name: 'Hokusai', paper: '#e8dcc4', ground: '#7d99b3', primary: '#1d3557', accent: '#bc4b51', ink: '#1d1d1f', sec1: '#a8a48f', sec2: '#5a4838' }, { name: 'Riso', paper: '#f3eee2', ground: '#7fb3a8', primary: '#e84a5f', accent: '#2b3a67', ink: '#101820', sec1: '#c8a87a', sec2: '#3a3a3a' }, { name: 'Clay', paper: '#ece2cf', ground: '#a78a6b', primary: '#5a3825', accent: '#7a4a31', ink: '#1f1a14', sec1: '#8a6e52', sec2: '#3a2a1a' }, { name: 'Verdigris', paper: '#ecdcb8', ground: '#8aa39b', primary: '#264027', accent: '#b8553a', ink: '#181818', sec1: '#6a7a5a', sec2: '#5a3a28' }, { name: 'Sumi', paper: '#ede4d0', ground: '#b9b1a3', primary: '#2a2a2a', accent: '#9c2a1a', ink: '#0e0e0e', sec1: '#7a7468', sec2: '#4a4438' }, { name: 'Cobalt', paper: '#e6d9b8', ground: '#9aa9b8', primary: '#1f3a8a', accent: '#e0a458', ink: '#0a0a0f', sec1: '#5a6a8a', sec2: '#7a4a28' }, { name: 'Iron Oxide', paper: '#e8d8b8', ground: '#a89478', primary: '#7a2a1d', accent: '#3a3a3a', ink: '#191512', sec1: '#bfa37e', sec2: '#5a342a' }, { name: 'Lichen', paper: '#e6dcc0', ground: '#7d8a6b', primary: '#3a2e22', accent: '#a8543a', ink: '#1a1814', sec1: '#a8aa8a', sec2: '#4a3a26' }, { name: 'Chartreuse', paper: '#ece8d6', ground: '#a8a89c', primary: '#1a1a1c', accent: '#d4c834', ink: '#0d0d10', sec1: '#7a7a72', sec2: '#3a3a3c' }, { name: 'Caution', paper: '#efeadc', ground: '#9c9a8e', primary: '#15151a', accent: '#f0c020', ink: '#08080c', sec1: '#6e6c64', sec2: '#3a3a3a' }, { name: 'Newsprint', paper: '#e6dab0', ground: '#9a8e72', primary: '#1d1a14', accent: '#c8a026', ink: '#13110c', sec1: '#b6a884', sec2: '#5a4f3c' }, { name: 'Brass', paper: '#ecdec0', ground: '#8e8a82', primary: '#2a2622', accent: '#e3a82a', ink: '#14120e', sec1: '#a8a094', sec2: '#4a463e' }, { name: 'Concrete', paper: '#e4e1d2', ground: '#828086', primary: '#1c1d22', accent: '#d8b62a', ink: '#0c0d12', sec1: '#a8a6a3', sec2: '#42434a' }, { name: 'Moss', paper: '#e6dcc0', ground: '#92a87a', primary: '#324326', accent: '#b86838', ink: '#161814', sec1: '#a8b58e', sec2: '#5a4a30' }, { name: 'Plum', paper: '#ecdfc8', ground: '#9a8aa0', primary: '#4a2a52', accent: '#c89a3a', ink: '#1a1218', sec1: '#a8a0aa', sec2: '#6a3a48' }, { name: 'Indigo', paper: '#e6dac4', ground: '#92a0b0', primary: '#1a2848', accent: '#c8b58a', ink: '#0c1020', sec1: '#7a8ca0', sec2: '#3a4a68' }, { name: 'Graphite', paper: '#e2e0d8', ground: '#9c9a96', primary: '#2a2c30', accent: '#5a5c60', ink: '#0a0b0e', sec1: '#bcbab4', sec2: '#46484c' }, { name: 'Oxblood', paper: '#ece0c8', ground: '#a0827a', primary: '#5a1f24', accent: '#d4a85a', ink: '#1a0e10', sec1: '#b09080', sec2: '#3a2a26' }, { name: 'Teal', paper: '#ece4ce', ground: '#7aa8a4', primary: '#1a4a52', accent: '#d8a836', ink: '#0e1a1c', sec1: '#a0bcb6', sec2: '#5a4a30' }, { name: 'Memphis', paper: '#f0e8d6', ground: '#3ec0b8', primary: '#e63a85', accent: '#2a8acc', ink: '#101015', sec1: '#f5c032', sec2: '#1a1a22' }, { name: 'Holi', paper: '#ecdfc2', ground: '#1ea58e', primary: '#e8602a', accent: '#d92766', ink: '#1a1010', sec1: '#f0b820', sec2: '#0d3a52' }, { name: 'Suprematist', paper: '#ede1c4', ground: '#a8a098', primary: '#d4321a', accent: '#1c40a8', ink: '#0a0a0e', sec1: '#e8b820', sec2: '#1a1a1a' }, { name: 'Acid', paper: '#ece6d8', ground: '#3acfc8', primary: '#ec3a98', accent: '#a8e030', ink: '#0c0a14', sec1: '#9a3ad8', sec2: '#2a8af0' }, { name: 'Loteria', paper: '#ecdfbe', ground: '#28a8b8', primary: '#1a8aa0', accent: '#d83a82', ink: '#0e1218', sec1: '#f0a820', sec2: '#1a48a0' }, { name: 'Pop', paper: '#f2ecda', ground: '#e8c828', primary: '#f0c020', accent: '#d8261a', ink: '#0a0a0e', sec1: '#1c50c8', sec2: '#e85a9a' }, ]; const FIELD_VERT = ` precision highp float; attribute vec3 aPosition; attribute vec2 aTexCoord; varying vec2 vUv; uniform mat4 uProjectionMatrix; uniform mat4 uModelViewMatrix; void main() { vUv = aTexCoord; gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0); } `; const MAX_SOURCES = 24; const FIELD_FRAG = ` precision highp float; varying vec2 vUv; uniform int uNumSources; uniform vec2 uPos[${MAX_SOURCES}]; uniform float uFreq[${MAX_SOURCES}]; uniform float uPhase[${MAX_SOURCES}]; uniform float uAmp[${MAX_SOURCES}]; uniform float uSign[${MAX_SOURCES}]; uniform float uDecay; uniform float uWarp; uniform float uWarpFreq; float hash(vec2 p){ return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); } float vnoise(vec2 p){ vec2 i = floor(p), f = fract(p); float a = hash(i); float b = hash(i + vec2(1.0, 0.0)); float c = hash(i + vec2(0.0, 1.0)); float d = hash(i + vec2(1.0, 1.0)); vec2 u = f*f*(3.0-2.0*f); return mix(a,b,u.x) + (c-a)*u.y*(1.0-u.x) + (d-b)*u.x*u.y; } float fbm(vec2 p){ float v = 0.0, a = 0.5; for (int i = 0; i < 4; i++) { v += a * vnoise(p); p *= 2.03; a *= 0.5; } return v; } void main() { vec2 uv = vUv; vec2 w = vec2(fbm(uv * uWarpFreq + 13.1), fbm(uv * uWarpFreq + 71.7)) - 0.5; vec2 p = uv + w * uWarp; float field = 0.0; float lowfreq = 0.0; float maxLocal = -1.0; float dominantId = 0.0; for (int i = 0; i < ${MAX_SOURCES}; i++) { if (i >= uNumSources) break; vec2 c = uPos[i]; float d = distance(p, c); float wave = cos(d * uFreq[i] - uPhase[i]) * uAmp[i] * uSign[i]; float falloff = 1.0 / (1.0 + uDecay * d * d); field += wave * falloff; lowfreq += uSign[i] * uAmp[i] * exp(-d * d * 6.0); float infl = uAmp[i] * exp(-d * d * 6.0); if (infl > maxLocal) { maxLocal = infl; dominantId = float(i) / float(${MAX_SOURCES} - 1); } } float fEnc = clamp(field * 0.5 + 0.5, 0.0, 1.0); float bEnc = clamp(lowfreq * 0.5 + 0.5, 0.0, 1.0); gl_FragColor = vec4(fEnc, dominantId, bEnc, 1.0); } `; const PAPER_FRAG = ` precision highp float; varying vec2 vUv; uniform float uSeed; uniform vec3 uPaperColor; float hash(vec2 p){ return fract(sin(dot(p, vec2(127.1, 311.7)) + uSeed) * 43758.5453); } float vnoise(vec2 p){ vec2 i = floor(p), f = fract(p); float a = hash(i); float b = hash(i + vec2(1.0, 0.0)); float c = hash(i + vec2(0.0, 1.0)); float d = hash(i + vec2(1.0, 1.0)); vec2 u = f*f*(3.0-2.0*f); return mix(a,b,u.x) + (c-a)*u.y*(1.0-u.x) + (d-b)*u.x*u.y; } float fbm(vec2 p){ float v = 0.0, a = 0.5; for (int i = 0; i < 5; i++) { v += a * vnoise(p); p *= 2.07; a *= 0.5; } return v; } void main() { vec2 uv = vUv; float macroTone = fbm(uv * 1.6 + vec2(7.3, 11.1)) * 2.0 - 0.5; macroTone = clamp(macroTone, -0.5, 1.0); float midTone = fbm(uv * 3.0) * 0.5 + 0.5; vec2 fdir = vec2(fbm(uv * 8.0 + 1.7), fbm(uv * 8.0 + 9.3)) - 0.5; vec2 anis = uv * vec2(180.0, 180.0) + fdir * 6.0; float fibers = vnoise(anis * vec2(1.0, 0.18)); float grain = hash(floor(uv * 1100.0)); vec3 warmTint = uPaperColor * vec3(0.97, 0.92, 0.84) * 0.93; vec3 coolTint = uPaperColor * vec3(0.95, 0.96, 0.99) * 0.97; float warmFactor = clamp(macroTone, 0.0, 1.0); float coolFactor = clamp(-macroTone, 0.0, 1.0); vec3 baseCol = uPaperColor; baseCol = mix(baseCol, warmTint, warmFactor * 0.65); baseCol = mix(baseCol, coolTint, coolFactor * 0.55); float dark = 1.0 - midTone * 0.05 - fibers * 0.08 - grain * 0.06; vec2 cv = uv - 0.5; float vig = 1.0 - dot(cv, cv) * 0.22; vec2 cornerPick = vec2( step(0.5, fract(uSeed * 0.71)) * 2.0 - 1.0, step(0.5, fract(uSeed * 0.31)) * 2.0 - 1.0 ); vec2 cornerPos = vec2(0.5, 0.5) + cornerPick * 0.5; float cornerDist = distance(uv, cornerPos); float cornerAge = smoothstep(0.7, 0.0, cornerDist) * 0.08; vig -= cornerAge; vec3 col = baseCol * dark * vig; gl_FragColor = vec4(col, 1.0); } `; let composition = null; function buildComposition() { const palette = rpick(PALETTES); const numSources = rint(5, 12); const sources = []; const gridN = Math.ceil(Math.sqrt(numSources * 1.6)); const cells = []; for (let i = 0; i < gridN; i++) for (let j = 0; j < gridN; j++) cells.push([i, j]); const shuffled = rshuffle(cells); const regime = rpick(['intricate', 'open', 'mixed', 'dense']); let baseFreq, freqSpread, ampDist; if (regime === 'intricate') { baseFreq = 90; freqSpread = 50; ampDist = 'flat'; } if (regime === 'open') { baseFreq = 38; freqSpread = 20; ampDist = 'tilted'; } if (regime === 'mixed') { baseFreq = 55; freqSpread = 70; ampDist = 'tilted'; } if (regime === 'dense') { baseFreq = 130; freqSpread = 70; ampDist = 'flat'; } for (let i = 0; i < numSources; i++) { const [ci, cj] = shuffled[i]; const cellSize = 1 / gridN; const x = (ci + 0.2 + 0.6 * rnd()) * cellSize; const y = (cj + 0.2 + 0.6 * rnd()) * cellSize; const freq = baseFreq + rgauss() * freqSpread * 0.4; const phase = rrange(0, Math.PI * 2); let amp; if (ampDist === 'flat') amp = rrange(0.7, 1.0); else amp = (i === 0) ? rrange(0.9, 1.1) : rrange(0.3, 0.8); const sign = rchance(0.5) ? 1 : -1; sources.push({ x, y, freq: Math.max(8, freq), phase, amp, sign }); } const targetFeatureCount = rint(2, 3); const featureIndices = []; const sourceOrder = rshuffle(Array.from({ length: numSources }, (_, i) => i)); for (const idx of sourceOrder) { if (featureIndices.length >= targetFeatureCount) break; const c = sources[idx]; let ok = true; for (const fi of featureIndices) { const fc = sources[fi]; const dx = c.x - fc.x, dy = c.y - fc.y; if (dx * dx + dy * dy < 0.18 * 0.18) { ok = false; break; } } if (ok) featureIndices.push(idx); } const featureSet = new Set(featureIndices); const allStyles = ['stipple', 'crosshatch', 'rings', 'solid', 'ribbon', 'dots-grid']; const stylePool = rshuffle(allStyles).slice(0, rint(2, 3)); const colorPool = rshuffle(['accent', 'primary', 'sec2']); for (let i = 0; i < numSources; i++) { if (featureSet.has(i)) { sources[i].fill = rpick(stylePool); const featPos = featureIndices.indexOf(i); sources[i].fillColor = colorPool[featPos % colorPool.length]; } else { sources[i].fill = 'none'; sources[i].fillColor = null; } } const densityMode = (() => { const r = rnd(); if (r < 0.25) return 'sparse'; if (r < 0.85) return 'balanced'; return 'dense'; })(); let numContours; if (densityMode === 'sparse') numContours = rint(12, 18); else if (densityMode === 'balanced') numContours = rint(24, 34); else numContours = rint(36, 48); const contourLevels = []; for (let i = 0; i < numContours; i++) contourLevels.push((i + 0.5) / numContours); const decay = rrange(0.8, 2.5); const warp = rrange(0.0, 0.05); const warpFreq = rrange(2, 5); const showHatch = rchance(0.7); const showFrame = rchance(0.7); const showAnnotations = rchance(0.55); const showSplatter = rchance(0.7); const baseWeight = rrange(0.6, 1.3); const hatchAngle = rnd() * Math.PI; const circleDensity = Math.sqrt(rnd()); return { palette, sources, numSources, contourLevels, decay, warp, warpFreq, showHatch, showFrame, showAnnotations, showSplatter, baseWeight, regime, hatchAngle, densityMode, circleDensity }; } function marchingSquares(field, w, h, threshold) { const segments = []; const get = (i, j) => field[j * w + i]; for (let j = 0; j < h - 1; j++) { for (let i = 0; i < w - 1; i++) { const a = get(i, j); const b = get(i + 1, j); const c = get(i + 1, j + 1); const d = get(i, j + 1); let code = 0; if (a > threshold) code |= 1; if (b > threshold) code |= 2; if (c > threshold) code |= 4; if (d > threshold) code |= 8; if (code === 0 || code === 15) continue; const top = () => ({ x: i + (threshold - a) / (b - a), y: j }); const right = () => ({ x: i + 1, y: j + (threshold - b) / (c - b) }); const bottom = () => ({ x: i + (threshold - d) / (c - d), y: j + 1 }); const left = () => ({ x: i, y: j + (threshold - a) / (d - a) }); switch (code) { case 1: case 14: segments.push([left(), top()]); break; case 2: case 13: segments.push([top(), right()]); break; case 3: case 12: segments.push([left(), right()]); break; case 4: case 11: segments.push([right(), bottom()]); break; case 6: case 9: segments.push([top(), bottom()]); break; case 7: case 8: segments.push([left(), bottom()]); break; case 5: { const center = (a + b + c + d) * 0.25; if (center > threshold) { segments.push([left(), top()]); segments.push([right(), bottom()]); } else { segments.push([left(), bottom()]); segments.push([top(), right()]); } break; } case 10: { const center = (a + b + c + d) * 0.25; if (center > threshold) { segments.push([top(), right()]); segments.push([left(), bottom()]); } else { segments.push([left(), top()]); segments.push([right(), bottom()]); } break; } } } } return stitchSegments(segments); } function stitchSegments(segments) { const PREC = 1000; const key = (p) => `${Math.round(p.x * PREC)}_${Math.round(p.y * PREC)}`; const map = new Map(); segments.forEach((s, idx) => { const k0 = key(s[0]); const k1 = key(s[1]); if (!map.has(k0)) map.set(k0, []); map.get(k0).push({ idx, end: 0 }); if (!map.has(k1)) map.set(k1, []); map.get(k1).push({ idx, end: 1 }); }); const used = new Array(segments.length).fill(false); const polylines = []; for (let start = 0; start < segments.length; start++) { if (used[start]) continue; used[start] = true; const poly = [segments[start][0], segments[start][1]]; let extending = true; while (extending) { extending = false; const tail = poly[poly.length - 1]; const list = map.get(key(tail)) || []; for (const { idx, end } of list) { if (used[idx]) continue; const seg = segments[idx]; const other = seg[1 - end]; poly.push(other); used[idx] = true; extending = true; break; } } extending = true; while (extending) { extending = false; const head = poly[0]; const list = map.get(key(head)) || []; for (const { idx, end } of list) { if (used[idx]) continue; const seg = segments[idx]; const other = seg[1 - end]; poly.unshift(other); used[idx] = true; extending = true; break; } } if (poly.length >= 3) polylines.push(poly); } return polylines; } const DEFAULT_SIZE = 1000; const SCREEN_PIXEL_DENSITY = 2; const PRINT_EXPORT_SIZE = 5000; const PRINT_EXPORT_PIXEL_DENSITY = 1; let ifSave = false; let ifBulk = false; let canvasSize = 800; let M = 1; let fieldFBO, fieldShader; let paperFBO, paperShader, paperImg; let fieldGrid, domGrid, lowGrid; let gridW = 0, gridH = 0; let mainCanvas; let seed = 1; let needsRender = false; let seedLocked = false; // --- On-chain seed ----------------------------------------------------- // The contract's tokenURI builds this page on-chain and injects the current // seed as window.ARTSCRIPT_SEED in a <script> before this sketch. When the // holder calls updateSeed(...), tokenURI regenerates with the new seed, so // the piece always reflects current on-chain state — no URL, no RPC. With no // injected seed the file runs in "studio mode": a random, explorable seed. // Reduce any uint256 to the 32-bit value the renderer's RNG uses. Small // curated seeds (e.g. 931222) are preserved exactly. function reduceSeed(big) { const MOD = 4294967296n; // 2^32 return Number(((big % MOD) + MOD) % MOD); } // Read the seed the contract injected into the page. The on-chain tokenURI // emits an inline script setting window.ARTSCRIPT_SEED before this sketch, // so the rendered piece always reflects current on-chain state. function readInjectedSeed() { if (typeof window.ARTSCRIPT_SEED === 'undefined' || window.ARTSCRIPT_SEED === null) return null; const raw = String(window.ARTSCRIPT_SEED).trim(); if (!/^[0-9]+$/.test(raw)) return null; try { return reduceSeed(BigInt(raw)); } catch (e) { return null; } } function setup() { // The on-chain HTML wrapper is minimal — ensure page styling + holder. document.documentElement.style.cssText = 'margin:0;padding:0;width:100%;height:100%'; document.body.style.cssText = 'margin:0;padding:0;width:100%;height:100%;background:#1a1a1a;overflow:hidden;display:flex;align-items:center;justify-content:center'; let holder = document.getElementById('canvas-holder'); if (!holder) { holder = document.createElement('div'); holder.id = 'canvas-holder'; holder.style.cssText = 'display:flex;align-items:center;justify-content:center;width:100vmin;height:100vmin'; document.body.appendChild(holder); } canvasSize = Math.floor(Math.min(window.innerWidth, window.innerHeight)); M = canvasSize / DEFAULT_SIZE; pixelDensity(SCREEN_PIXEL_DENSITY); mainCanvas = createCanvas(canvasSize, canvasSize); mainCanvas.parent(holder); const FBO_RES = 384; fieldFBO = createGraphics(FBO_RES, FBO_RES, WEBGL); fieldFBO.pixelDensity(1); fieldShader = fieldFBO.createShader(FIELD_VERT, FIELD_FRAG); fieldFBO.shader(fieldShader); const PAPER_RES = 1024; paperFBO = createGraphics(PAPER_RES, PAPER_RES, WEBGL); paperFBO.pixelDensity(1); paperShader = paperFBO.createShader(FIELD_VERT, PAPER_FRAG); const injected = readInjectedSeed(); if (injected !== null) { seed = injected; // seed delivered on-chain by the contract seedLocked = true; } else { seed = Math.floor(Math.random() * 999999); // studio mode (no injected seed) location.hash = String(seed); } generate(); noLoop(); } function uploadFieldUniforms() { const N = composition.sources.length; const posArr = []; const freqArr = []; const phaseArr = []; const ampArr = []; const signArr = []; for (let i = 0; i < MAX_SOURCES; i++) { if (i < N) { posArr.push(composition.sources[i].x, composition.sources[i].y); freqArr.push(composition.sources[i].freq); phaseArr.push(composition.sources[i].phase); ampArr.push(composition.sources[i].amp); signArr.push(composition.sources[i].sign); } else { posArr.push(0, 0); freqArr.push(0); phaseArr.push(0); ampArr.push(0); signArr.push(0); } } fieldShader.setUniform('uNumSources', N); fieldShader.setUniform('uPos', posArr); fieldShader.setUniform('uFreq', freqArr); fieldShader.setUniform('uPhase', phaseArr); fieldShader.setUniform('uAmp', ampArr); fieldShader.setUniform('uSign', signArr); fieldShader.setUniform('uDecay', composition.decay); fieldShader.setUniform('uWarp', composition.warp); fieldShader.setUniform('uWarpFreq', composition.warpFreq); } function renderFieldToGrid() { fieldFBO.noStroke(); fieldFBO.shader(fieldShader); fieldFBO.rect(-fieldFBO.width / 2, -fieldFBO.height / 2, fieldFBO.width, fieldFBO.height); fieldFBO.loadPixels(); gridW = fieldFBO.width; gridH = fieldFBO.height; fieldGrid = new Float32Array(gridW * gridH); domGrid = new Uint8Array(gridW * gridH); lowGrid = new Float32Array(gridW * gridH); const px = fieldFBO.pixels; for (let j = 0; j < gridH; j++) { for (let i = 0; i < gridW; i++) { const idx = (j * gridW + i) * 4; fieldGrid[j * gridW + i] = (px[idx + 0] / 255) * 2 - 1; domGrid[j * gridW + i] = px[idx + 1]; lowGrid[j * gridW + i] = (px[idx + 2] / 255) * 2 - 1; } } } function renderPaper() { const palette = composition.palette; const c = color(palette.paper); paperFBO.shader(paperShader); paperShader.setUniform('uSeed', seed % 1000); paperShader.setUniform('uPaperColor', [red(c) / 255, green(c) / 255, blue(c) / 255]); paperFBO.noStroke(); paperFBO.rect(-paperFBO.width / 2, -paperFBO.height / 2, paperFBO.width, paperFBO.height); paperImg = paperFBO.get(); } function generate() { setSeed(seed); composition = buildComposition(); uploadFieldUniforms(); renderFieldToGrid(); renderPaper(); needsRender = true; redraw(); } function sampleField(grid, x, y) { const fx = x * (gridW - 1); const fy = y * (gridH - 1); const i0 = Math.floor(fx), j0 = Math.floor(fy); const i1 = Math.min(gridW - 1, i0 + 1); const j1 = Math.min(gridH - 1, j0 + 1); const tx = fx - i0, ty = fy - j0; const a = grid[j0 * gridW + i0]; const b = grid[j0 * gridW + i1]; const c = grid[j1 * gridW + i0]; const d = grid[j1 * gridW + i1];
ousia-sketch-v1// Ousia sketch - ON-CHAIN build (upload to ScriptyStorage as "ousia-sketch-v1"). // currentID, hexData, canvasSize, showPunk, showSphere are INJECTED by the OusiaRenderer // contract in a preceding <script>, so they must NOT be declared here: two top-level // 'let' of the same name across <script> tags is a SyntaxError that breaks the animation. // The standalone/test version (with those vars set to a sample punk) is in sketch.js. let gaskets = []; let spheres = []; let baseSize = 800; let scaleFactor; let minRadius; let seed const epsilon = 0.1; let index = 0; let gasketBuffer; let punkBuffer; let punkImageData; p5.RendererGL.prototype._drawPoints = function(points, buffer) { if (!points.length || !this.curStrokeColor) { return; } const gl = this.GL; const shader = this._getImmediatePointShader(); this._setPointUniforms(shader); this._bindBuffer(buffer, gl.ARRAY_BUFFER, this._vToNArray(points), Float32Array, gl.STATIC_DRAW); shader.enableAttrib(shader.attributes.aPosition, 3); this._applyColorBlend(this.curStrokeColor); gl.drawArrays(gl.POINTS, 0, points.length); shader.unbindShader(); }; function setup() { scaleFactor = canvasSize / baseSize; createCanvas(canvasSize, canvasSize, WEBGL); pixelDensity(1); angleMode(DEGREES); ortho(); let pxNumber = pData.numPixels; let colNumber = pData.numColors; minRadius = getMinRadius(pxNumber, scaleFactor); punkImageData = hexStringToUint8Array(hexData); punkBuffer = createGraphics(canvasSize, canvasSize, WEBGL); punkBuffer.ortho(); punkBuffer.angleMode(DEGREES); drawPunkToBuffer(punkBuffer); seed = currentID * colNumber * pxNumber; generateGaskets(seed, minRadius, pxNumber, canvasSize) assignColorsToCircles(gaskets, pData.colors); createSpheresFromCircles(gaskets, seed, scaleFactor); gasketBuffer = createGraphics(canvasSize, canvasSize, WEBGL); gasketBuffer.ortho(); gasketBuffer.angleMode(DEGREES); gasketBuffer.blendMode(ADD); for (let gasket of gaskets) { gasket.show(gasketBuffer); } } function draw() { background(0); if (showPunk){ image(punkBuffer, -width/2, -height/2); } if (showSphere) { blendMode(ADD); image(gasketBuffer, -width/2, -height/2); blendMode(BLEND); } for (let sphere of spheres) { sphere.show(); } } function drawPunkToBuffer(pg) { let imageData = punkImageData; let originalSize = 24; let basePixelSize = baseSize / originalSize; let reductionFactor = 6; let pixelSize = (basePixelSize * scaleFactor) / reductionFactor; let offsetX = -pg.width / 2; let offsetY = pg.height / 2 - (pixelSize * originalSize) - 10; pg.noStroke(); for (let y = 0; y < originalSize; y++) { for (let x = 0; x < originalSize; x++) { let i = (y * originalSize + x) * 4; if (i + 3 < imageData.length) { let r = imageData[i]; let g = imageData[i + 1]; let b = imageData[i + 2]; let a = imageData[i + 3]; if (r === 0 && g === 0 && b === 0 && a === 0) { continue; } pg.fill(r, g, b); pg.rect(x * pixelSize + offsetX, y * pixelSize + offsetY, pixelSize, pixelSize); } } } } //======================Circles============================== class Circle { constructor(bend, x, y, index) { this.center = new Complex(x, y); this.bend = bend; this.radius = abs(1 / this.bend); this.index = index; this.color = color(0); } show(pg) { pg.noStroke(); let r = pg.red(this.color); let g = pg.green(this.color); let b = pg.blue(this.color); for (let i = 0.0; i < 1.0; i += 0.05) { pg.fill(r, g, b, (1.2 - i) * 100 * i); pg.circle(this.center.a, this.center.b, this.radius * 1.2 * i); } } dist(other) { return dist(this.center.a, this.center.b, other.center.a, other.center.b); } setColor(newColor) { this.color = newColor; } } //======================EndCircles=========================== //======================Spheres============================== class Sphere { constructor(a, b, radius, col, seed, scaleFactor) { this.a = a; this.b = b; this.r = radius; this.color = col; this.seed = seed; this.scaleFactor = scaleFactor; this.rot = randomFromSeed(seed, 0, 360); this.rotX = randomFromSeed(seed + 1, 1, 10); let NSpossibleValues = [8, 10, 12, 14]; this.NSdotAmount = NSpossibleValues[ Math.floor(randomFromSeed(seed + 2, 0, NSpossibleValues.length)) ]; this.NSlinesAmount = Math.floor(randomFromSeed(seed + 3, 4, 10)); this.SSdotsAmount = Math.floor(randomFromSeed(seed + 4, 3, 5)); this.SSthetaFactor = Math.floor(randomFromSeed(seed + 5, 6, 8)); this.sphereKey = Math.floor(randomFromSeed(seed + 6, 0, 2)); this.angleAmplitude = Math.floor(randomFromSeed(seed + 7, 0, 360)); } show() { stroke(this.color); this.strokeSphere(); push(); translate(this.a, this.b); rotate(this.rot); rotateX(millis() / 50 * this.rotX); if (this.sphereKey == 0) { this.showNormalSphere(); } else { this.showSphericalSphere(); } } showSphericalSphere() { beginShape(POINTS); for (let theta = 0; theta < 360 / 2; theta += this.SSdotsAmount) { let x = this.r * cos(theta); let y = this.r * sin(theta) * sin(theta * this.SSthetaFactor); let z = this.r * sin(theta) * cos(theta * this.SSthetaFactor); vertex(x, y, z); } endShape(); pop(); } showNormalSphere() { beginShape(POINTS); for (let phi = 0; phi < 190; phi += 190 / this.NSdotAmount) { let angleOffset = map(phi, 0, 190, 0, this.angleAmplitude); for (let theta = 0; theta < 360; theta += 360 / this.NSlinesAmount) { let x = this.r * cos(phi); let y = this.r * sin(phi) * sin(theta + angleOffset); let z = this.r * sin(phi) * cos(theta + angleOffset); vertex(x, y, z); } } endShape(); pop(); } strokeSphere() { let weight; if (this.r > 150) { weight = 6; } else if (this.r > 100) { weight = 5; } else if (this.r > 50) { weight = 4; } else if (this.r > 25) { weight = 3; } else { weight = 2; } strokeWeight(constrain(weight * this.scaleFactor, 0.5, 10)); } } //======================EndSpheres=========================== //======================Functions============================ function randomFromSeed(seed, min, max) { let x = Math.sin(seed) * 10000; return min + (x - Math.floor(x)) * (max - min); } function getMinRadius(pxNumber, scaleFactor) { if (pxNumber >= 250) { return 8 * scaleFactor; } else if (pxNumber >= 170 && pxNumber < 250) { return 10 * scaleFactor; } else if (pxNumber <= 169) { return 12 * scaleFactor; } } function getTotalCircles() { return gaskets .map((gasket) => gasket.allCircles.length) .reduce((sum, count) => sum + count, 0); } function removeMinCircles(gaskets, count) { let allCirclesWithInfo = gaskets.flatMap((gasket) => gasket.getCirclesWithInfo() ); allCirclesWithInfo.sort((a, b) => a.circle.radius - b.circle.radius); let allCirclesToRemove = []; for (let i = 0; i < count; i++) { let { index, gasket } = allCirclesWithInfo[i]; allCirclesToRemove.push({ index: index, gasket: gasket }); } allCirclesToRemove.sort((a, b) => b.index - a.index); allCirclesToRemove.forEach(({ index, gasket }) => { gasket.removeCircle(index); }); } function createSpheresFromCircles(gaskets, baseSeed, scaleFactor) { let counter = 0; for (let gasket of gaskets) { for (let circle of gasket.allCircles) { let seed = baseSeed + counter; let sphere = new Sphere(circle.center.a, circle.center.b, circle.radius, circle.color, seed, scaleFactor); spheres.push(sphere); counter++; } } } //======================EndFunctions========================= //======================Functions2=========================== function hexStringToUint8Array(hex) { if (hex.startsWith('0x')) { hex = hex.slice(2); } let array = new Uint8Array(hex.length / 2); for (let i = 0; i < hex.length; i += 2) { array[i / 2] = parseInt(hex.substr(i, 2), 16); } return array; } let pData = extractData(hexData); function assignColorsToCircles(gaskets, colors) { let rgbColors = colors.filter(color => color !== '0,0,0').map(color => `rgb(${color})`); let nonEmptyGaskets = gaskets.filter(gasket => gasket.allCircles.length > 0); let colorIndex = 0; for (let gasket of nonEmptyGaskets) { let assignedColor = rgbColors[colorIndex % rgbColors.length]; for (let circle of gasket.allCircles) { circle.setColor(assignedColor); } colorIndex++; } } function extractData(hexData) { let imageData = hexStringToUint8Array(hexData); let colorCount = {}; let totalPixels = 0; let originalSize = 24; for (let y = 0; y < originalSize; y++) { for (let x = 0; x < originalSize; x++) { let i = (y * originalSize + x) * 4; if (i + 3 < imageData.length) { let r = imageData[i]; let g = imageData[i + 1]; let b = imageData[i + 2]; let a = imageData[i + 3]; if (r === 0 && g === 0 && b === 0 && a === 0) { continue; } let colorKey = `${r},${g},${b}`; if (colorCount[colorKey] === undefined) { colorCount[colorKey] = 0; } colorCount[colorKey]++; totalPixels++; } } } let sortedColors = Object.keys(colorCount).sort((a, b) => colorCount[b] - colorCount[a]); return { numColors: sortedColors.length, numPixels: totalPixels, colors: sortedColors }; } //======================EndFunctions2======================== //======================Gaskets============================== function generateGaskets(seed, minRadius, pxNumber, canvasSize){ gaskets.push(new Gasket(seed, minRadius, 0, 0, canvasSize / 2)); while (getTotalCircles() < pxNumber) { let allMaxCircles = []; for (let gasket of gaskets) { let circle = gasket.getMaxCircle(); allMaxCircles.push(circle.radius); } let maxCircle = Math.max(...allMaxCircles); let maxCircleGasketIndex = allMaxCircles.indexOf(maxCircle); let nextGP = gaskets[maxCircleGasketIndex].getMaxCircle(); let newGasket = new Gasket( seed + gaskets.length, minRadius, nextGP.center.a, nextGP.center.b, nextGP.radius ); gaskets.push(newGasket); gaskets[maxCircleGasketIndex].allCircles.splice( gaskets[maxCircleGasketIndex].maxIndex, 1 ); if (getTotalCircles() > pxNumber) { let circlesToRemove = getTotalCircles() - pxNumber; removeMinCircles(gaskets, circlesToRemove); } } } class Gasket { constructor(seed, minRadius, x, y, r) { this.allCircles = []; this.queue = []; this.seed = seed; this.minRadius = minRadius; let c1 = new Circle(-1 / r, x, y, index); let r2 = randomFromSeed(seed, c1.radius / 8, c1.radius / 2); let angle = randomFromSeed(seed + 1, 0, 360); let vX = (c1.radius - r2) * cos(angle); let vY = (c1.radius - r2) * sin(angle); let c2 = new Circle(1 / r2, x + vX, y + vY, index); let r3 = sqrt(vX * vX + vY * vY); angle += 180; vX = (c1.radius - r3) * cos(angle); vY = (c1.radius - r3) * sin(angle); let c3 = new Circle(1 / r3, x + vX, y + vY, index); this.allCircles = [c1, c2, c3]; this.queue = [[c1, c2, c3]]; let len = -1; while (this.allCircles.length !== len) { len = this.allCircles.length; this.nextGeneration(); } this.allCircles.shift(); } getMaxCircle() { this.radii = this.allCircles.map((circle) => circle.radius); this.maxRadius = Math.max(...this.radii); this.maxIndex = this.radii.indexOf(this.maxRadius); return this.allCircles[this.maxIndex]; } getCirclesWithInfo() { return this.allCircles.map((circle, index) => ({ circle, index, gasket: this, })); } removeCircle(index) { this.allCircles.splice(index, 1); } nextGeneration() { let nextQueue = []; for (let triplet of this.queue) { let [c1, c2, c3] = triplet; let k4 = descartes(c1, c2, c3); let newCircles = complexDescartes(c1, c2, c3, k4); for (let newCircle of newCircles) { if (validate(newCircle, c1, c2, c3, this.allCircles, this.minRadius)) { this.allCircles.push(newCircle); let t1 = [c1, c2, newCircle]; let t2 = [c1, c3, newCircle]; let t3 = [c2, c3, newCircle]; nextQueue = nextQueue.concat([t1, t2, t3]); } } } this.queue = nextQueue; } show(pg) { for (let i = 0; i < this.allCircles.length; i++) { this.allCircles[i].show(pg); } } } function isTangent(c1, c2) { let d = c1.dist(c2); let r1 = c1.radius; let r2 = c2.radius; let a = abs(d - (r1 + r2)) < epsilon; let b = abs(d - abs(r2 - r1)) < epsilon; return a || b; } function validate(c4, c1, c2, c3, allCircles, minRadius) { if (c4.radius < minRadius) return false; for (let other of allCircles) { let d = c4.dist(other); let radiusDiff = abs(c4.radius - other.radius); if (d < epsilon && radiusDiff < epsilon) { return false; } } if (!isTangent(c4, c1)) return false; if (!isTangent(c4, c2)) return false; if (!isTangent(c4, c3)) return false; return true; } function complexDescartes(c1, c2, c3, k4) { let k1 = c1.bend; let k2 = c2.bend; let k3 = c3.bend; let z1 = c1.center; let z2 = c2.center; let z3 = c3.center; let zk1 = z1.scale(k1); let zk2 = z2.scale(k2); let zk3 = z3.scale(k3); let sum = zk1.add(zk2).add(zk3); let root = zk1.mult(zk2).add(zk2.mult(zk3)).add(zk1.mult(zk3)); root = root.sqrt().scale(2); let center1 = sum.add(root).scale(1 / k4[0]); let center2 = sum.sub(root).scale(1 / k4[0]); let center3 = sum.add(root).scale(1 / k4[1]); let center4 = sum.sub(root).scale(1 / k4[1]); return [ new Circle(k4[0], center1.a, center1.b), new Circle(k4[0], center2.a, center2.b), new Circle(k4[1], center3.a, center3.b), new Circle(k4[1], center4.a, center4.b), ]; } function descartes(c1, c2, c3) { let k1 = c1.bend; let k2 = c2.bend; let k3 = c3.bend; let sum = k1 + k2 + k3; let product = abs(k1 * k2 + k2 * k3 + k1 * k3); let root = 2 * sqrt(product); return [sum + root, sum - root]; } //============================EndGaskets================================== //============================Complex===================================== class Complex { constructor(a, b) { this.a = a; this.b = b; } add(other) { return new Complex(this.a + other.a, this.b + other.b); } sub(other) { return new Complex(this.a - other.a, this.b - other.b); } scale(value) { return new Complex(this.a * value, this.b * value); } mult(other) { let a = this.a * other.a - this.b * other.b; let b = this.a * other.b + other.a * this.b; return new Complex(a, b); } sqrt() { let m = sqrt(this.a * this.a + this.b * this.b); let angle = atan2(this.b, this.a); m = sqrt(m); angle = angle / 2; return new Complex(m * cos(angle), m * sin(angle)); } } //===========================EndComplex=====================================
TMIT_Rendereru+aOg/nUjjTTMBE+KgG2xOX+CSE8q5viQtp1QlaOFjcJhtj7G4iyldLP7iE4m5fw7xlv7XhfVyrUdlt+xR0eW6kEzE+od/O4phWeF/8c6QmkrW1IAgPjcKyrjCqJmmWUtATMNvPOdoLR/bRIFgkm/o3+5KiSbZfXagbEFCp2XrhXKZ0xIikudspkc0E38bgci34/yUM4Q7pxtlbycVQrXO5LKV7C0Llcy8NAUqE4hHZ+lSaSsHK7KC0ELCqIcLpUxQvDN74tMOnvAjGstDXfZ0Jc2wvJwlC7kpvGNx/nPqaVwikzMrntJQMxk8jGFKKuxL4LPK2VhkQQjcF+UijODQ4gcm1jQLiKS9DE8U+SpvU71BFvXBNSzop+OC9SI/jy91j3/IWsy4hR6WnnkY/DhLw0YOLhkHBzL8jcQTyCPRmMBlOh/k81YC93tlg7CIrM8CBek5N0oCPlogccEVhy/hflAFdyFgLpKRzXqxGM8CUDnFZCyYYLw+qPibGAPKOZCDW0ZWCXeQt3WXS622xuUjCEy5vpWeYfHl63u+2BQ+Du/M8VwTNCZweOtPxqVx1uxrCNEmsvmPizM4tx83Odn2IeQfaTUkrk4Lvvga2ghdqDKFhEx+VTrPm7xJ4gxeImm3SEYsd5e9o1zExMwvQM5bgjJTnhj4NSK17ie+PZzf0JS0YH7TdRNB5cl9jugHS1/SI+xCKb1VjpZIlO54MVug/NhbRE3HDTQjztvWMQlQYkvgMl6Zd17ornKm9I0RpUexbHBO0IemgQxP7jn92Hp1gSCNKZ5/HOP5g+ZWpWfv2LIzhKBgMds0xC0f+22ddgEj3+U22YHnLnbWz7+bmiIDWnnWPG6YC6XK4tOe+d2Ls6x1AT3hnDQmFkAeY4UJAJ1V1XCHF0UYCRcTHBEOEKF7+eTIZn6qkSqYTm3TC55PETUbWL1OzmRuOktZYLeGM/8JrY/KT7DoJs/E6DpYGB//2tXBE3+3pJO8ZSIKOOIuxdssyk1rvG/my2Kf98vli64oW+r0JYJEmHZbTCYIW7gCo3O5aGG4VIZhKEzp+XqKnzzYfvRsb9sP7eD4ClWe0kwEadSQ7Ro4vnbx6jt+FaM06jCUE0AqJjZZ4l0APohJg7n6V9gDwPDKP8rWIQ2YkLSz06l7Ow07NcAwLYTRRLVetVXUM6I+QaFzUQpWkArZYdnfkjjhEHySDw37OgTs0cuEctS9z8SxSZPNOjqHDmWJTIAAI2KsyHImYCBF7UI4sWNQX9fLOlRilBY7WtR778qemZtRJ9Bd+a5o8f2Cq+86P5n4/lbg8pJGlqXWlvdAtMYI9WH757G47hXwKy7UC5xLzHaTeWvStr87/Ltjf2/w7w3PqLcCZSg1sjjDF8n8QQVhPO857Av6XJiac65DStN6QC8/5qv2l2an7vpeAfapzE0sGGhlOWy00FbQKrL5GSsePI08K1+qbiJHvlVQpDS65idLOMeKWM5oMt7IPfkxLmT7+ccViaiGMENOPgchrHH8UFdKKzNOyFsneVki9uC+9502jDMjBFFHeeYMwiELbvPS9US/BV+0ZCxu0Ea0Yu6Z2DeuacBaq17JgX6obijm26hwVNIThQLR57Qn/J5kpysJtaLmywACpBaM5M5Qlaub/GbviSUNYW0iWojfzCfA+Wnf0jHok6vStmH6ayKC9FaLRYFDLU9E1y8IJsoqCGnpYodcvNBonh9FJ7HvgnSWGk8kUUbYWQ0qgu+lxkRHbQY5cVt5GHuET900UuHF4By7JByliqcsYhAr2nQDBzZExosoe7KbPN/ZerjNwhQXuJAgGo2CbIQhZxrvdfxjrASgnRbjqdAOTakP85MXOGPsijAOey4ai+k0AAPWAOqLzK4oUTeasDC8yjSO6/hEEVOhEG6e8Q0rLAwL2Qc9FtKOIPLM/5FmlnUa9SYLM/G34+myNCzNegLpSf3VQwel5KKPYcn8GCUhQtxbzInX+u1oOLvPYmTVhhwmf/6QWN8ImdqFuxrYcCZF4YRCblrZI3ekz1t+MwQu7WcQkIRDCk6ZTUvOk3nN7lOssvwi0D6OeuV2MeBgdg4jyi5UCsJYPTuUOrGmPCxc0qQPdzLPd3riunmOMPoCgKrpHKduUXQ8ojw/9rhcjnXhM9EXDK8gIj48c8OlSQuRF0W7Ya/yCpuKdpDUxwOpiEi0AK/Ye/5QECsbfOyizqen8EAP4lBNcLJayzU+bia2bYkcdQIARnHDYGqobTTcXvTXqqeQefj25JWK6GmxJwamOsc6c7NGPri6UcEFK/1lvO7q/e5+ib8dQ5wDMQ+nCoRc/GFTEjHaPSUJNkCS9kmPpqL7THNe/H9Os4xIo/oBAA==
TMIT_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
TMIT_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
1-50 of 439