memoscan
← all memos

Memo 0x2565fb12…48d3c5 on Ethereum

const project = "Time Between the Lines is Thread Through the Mind"; console.log(`${project} v5.0 © Matto 2024`); console.log(`TOKEN ENTROPY: ${tokenData.hash}`); let skeuomorphic = tokenData.plot == true ? false : true; const tokenId = tokenData.tokenId; const attributes = {}; const urlParams = new URLSearchParams(window.location.search); const customSig = urlParams.get("signature"); let customOp = urlParams.get("optimization"); if (customOp) { customOp = customOp.toUpperCase(); } const altMode = urlParams.get("alternate"); const skeuMode = urlParams.get("skeuomorphic"); let modeDesc = ["SKEUOMORPHIC", "SIMPLE"]; let spreadDesc = ["MINIMUM", "SOME", "MORE", "MAXIMUM"]; let penSuggestion = []; if (skeuMode == "true") { skeuomorphic = true; console.log(`CUSTOM MODE: ${modeDesc[0]}`); } else if (skeuMode == "false") { skeuomorphic = false; console.log(`CUSTOM MODE: ${modeDesc[1]}`); } else { console.log("DEFAULT MODE: " + (skeuomorphic ? modeDesc[0] : modeDesc[1])); } console.log(""); let seed = makeSeed(tokenData.hash); let nonce = 0; let showSignature = customSig == "false" ? false : true; let circlesCount = 0; const numGroups = selectByProbs([5,6,4,7,3], fractionalRand()); const m = (rand(0, 200) / 100) - 1; let svg, sig; let groupedLines = ""; let texturedLines = ""; let gappedPoints = []; let palettes = []; let points = []; const allOptDesc = ["ANTI", "LAPS", "STANDARD", "MAXIMUM"]; const defaultOpt = selectByProbs([3, 2, 1, 0], fractionalRand()); let optimization = allOptDesc.indexOf(customOp); if (optimization === -1) { optimization = defaultOpt; } let optDesc = allOptDesc[optimization]; let dark = selectByProbs([0, 1], fractionalRand()); if (altMode == "true") { console.log("Alternate Mode selected, switching paper and pens."); dark = dark == 1 ? 0 : 1; } let perpGap = selectByProbs([true, false], fractionalRand()); const bkg = dark == 1 ? 22 : 250; const penCollection = dark == 0 ? "Stabilo" : "Gelly Roll"; const paletteArray = [ [ { hex: "#83553b", name: "Brown", id: 45 }, { hex: "#d74143", name: "Dark Red", id: 50 }, { hex: "#f75c45", name: "Carmine", id: 48 }, { hex: "#ff8b15", name: "Pale Vermillion", id: 30 }, { hex: "#ffb814", name: "Orange", id: 54 }, { hex: "#ffd913", name: "Yellow", id: 44 }, { hex: "#fff248", name: "Lemon Yellow", id: 24 }, { hex: "#b7c800", name: "Light Green", id: 33 }, { hex: "#4c8b06", name: "Leaf Green", id: 43 }, { hex: "#1c6a27", name: "Green", id: 36 }, { hex: "#3d47b3", name: "Ultramarine", id: 32 }, { hex: "#3074e5", name: "Dark Blue", id: 41 }, { hex: "#3093f8", name: "Light Blue", id: 31 }, { hex: "#58b6ff", name: "Azure", id: 57 }, { hex: "#c9c4c4", name: "Light Cold Gray", id: 94 }, { hex: "#a59da5", name: "Medium Cold Gray", id: 95 }, { hex: "#665e61", name: "Dark Gray", id: 96 }, { hex: "#2d2828", name: "Black", id: 46 }, ], [ { hex: "#E9E9E9", name: "Platinum", id: 50 }, { hex: "#85CFF5", name: "Pale Azure", id: 425 }, { hex: "#7696DC", name: "Vista Blue", id: "437p" }, { hex: "#2A6CD0", name: "Celtic Blue", id: 438 }, { hex: "#109EE0", name: "Celestial Blue", id: 436 }, { hex: "#97DCD6", name: "Tiffany Blue", id: "426p" }, { hex: "#28DBD5", name: "Turquoise", id: 429 }, { hex: "#85D18A", name: "Emerald", id: 428 }, { hex: "#E1EC7A", name: "Mindaro", id: "403p" }, { hex: "#E7B968", name: "Earth Yellow", id: "405p" }, { hex: "#D0866D", name: "Burnt Sienna", id: 412 }, { hex: "#DB5D6E", name: "Indian Red", id: 419 }, { hex: "#CE6ABC", name: "Sky Magenta", id: 421 }, { hex: "#9774D3", name: "Amethyst", id: 424 }, { hex: "#AB98E0", name: "Wisteria", id: 423 }, { hex: "#D2AFDB", name: "Lilac", id: "420p" }, { hex: "#838A93", name: "Slate Gray", id: 444 }, { hex: "#513E3A", name: "Van Dyke", id: 417 }, ], [ { hex: "#EDECE4", name: "Metallic Silver", id: 553 }, { hex: "#FFD062", name: "Metallic Gold", id: 551 }, { hex: "#F8BEB6", name: "Metallic Red", id: 519 }, ] ]; if (dark == 1 && numGroups == 3) { dark = 2; } const startingColor = rand(0, paletteArray[dark].length - 1); const paletteSpread = dark < 2 ? selectByProbs([1,2,3,4], fractionalRand()) : 1; console.log("EXTENDED ATTRIBUTES:"); for (let i = 0; i < numGroups + 1; i++) { palettes[i] = paletteArray[dark][(startingColor + (i * paletteSpread)) % paletteArray[dark].length]; let name = `Group ${i + 1} Color`; if (i == numGroups) { name = "Signature Color"; } penSuggestion[i] = `Suggested Pen Color: ${penCollection} #${palettes[i].id}`; console.log(`${name}: ${palettes[i].name} (${palettes[i].hex}) - ${penSuggestion[i]}`); } addAttribute("COLOR GROUPS", `${numGroups}`); addAttribute("COLOR SPREAD", spreadDesc[paletteSpread - 1]); addAttribute("PAPER", dark > 0 ? "DARK" : "LIGHT"); addAttribute("COMPOSITION", perpGap ? "BISECTED" : "WHOLE"); addAttribute("SLOPE", -1 * m.toFixed(2)); addAttribute("OPTIMIZATION", optDesc); const svgStart = `<?xml version="1.0" encoding="utf-8"?><svg viewBox="0 0 1000 1000" style="background-color:rgb(${bkg},${bkg},${bkg})" xmlns="http://www.w3.org/2000/svg">`; const suggestedThickness = "Suggested line thickness: plot side length (mm) divided by 400."; draw(); function setup() { noCanvas(); noLoop(); } function draw() { const ySpacing = 2.6 - (1 - Math.abs(m)) / 3; let lineNum = 0; for (let b = -2000; b < 2000; b += ySpacing ) { const x0 = Math.max(0, -b / m); const x1 = Math.min(1000, (1000 - b) / m); const y0 = b + x0 * m; const y1 = b + x1 * m; const clipped = getClippedLine(x0, y0, x1, y1); if (clipped) { lineWithGaps(clipped.x0, clipped.y0, clipped.x1, clipped.y1, lineNum); } lineNum++; } // 0: anti, 1: laps (handled elsewhere), 2: normal, 3: maximum if (optimization == 0) { points = sortPointPairs(points, true, false); } else if (optimization == 2) { points = sortPointPairs(points, false, true); } else if (optimization == 3) { points = sortPointPairs(points, true, true); } const linesPerGroup = Math.ceil(points.length / numGroups); let pointIndex = 0; for (let i = 0; i < numGroups; i++) { groupedLines += G(i + 1, palettes[i].hex, 2.5, palettes[i].name, penSuggestion[i]); texturedLines += G(i + 1, palettes[i].hex, 1.5, palettes[i].name, penSuggestion[i]); for (let j = 0; j < linesPerGroup && pointIndex < points.length; j++) { if (isNaN(points[pointIndex].y2)) { break; } groupedLines += P([points[pointIndex].x1, points[pointIndex].y1, points[pointIndex].x2, points[pointIndex].y2]); if (skeuomorphic) { texturedLines += line2dots(points[pointIndex].x1, points[pointIndex].y1, points[pointIndex].x2, points[pointIndex].y2); } pointIndex++; } groupedLines += "</g>"; texturedLines +="</g>"; } console.log(`Background Line Segments: ${pointIndex}`); if (skeuomorphic) { console.log(`Composing Circles: ${circlesCount}`); } console.log(suggestedThickness); console.log("License: CC BY-NC 4.0"); sig = signature(); svg = skeuomorphic ? svgStart + texturedLines : svgStart + groupedLines; updateSVG(); } function signature() { let sigLinePoints = [ [924,956,920,956], [920,956,920,860], [920,860,940,872], [940,872,960,860], [960,860,960,956], [960,956,956,956], [928,902,940,872], [940,872,952,902], [934,888,946,888], [920,902,960,902], [932,902,932,926], [948,902,948,926] ]; let str; if (skeuomorphic) { str = G("signature", palettes[numGroups].hex, 1.5, palettes[numGroups].name, penSuggestion[numGroups]); for (let i=0; i<sigLinePoints.length; i++) { str += line2dots(sigLinePoints[i][0], sigLinePoints[i][1], sigLinePoints[i][2], sigLinePoints[i][3]); } str += circle2dots(940, 940, 15); } else { str = G("signature", palettes[numGroups].hex, 2.5, palettes[numGroups].name, penSuggestion[numGroups]); str += `<polyline points="924,956 920,956 920,860 940,872 960,860 960,956 956,956" stroke-linecap="round" stroke-linejoin="round"/>`; str += `<polyline points="928,902 940,872 952,902" stroke-linejoin="bevel" />`; str = str + P(sigLinePoints[8]) + P(sigLinePoints[9]) + P(sigLinePoints[10]) + P(sigLinePoints[11]); str += C([940, 940, 15]); } str += "</g>"; return str; } function G(groupNum, hex, strokeW, paletteName, penSuggestion) { return `<g id="group-${groupNum}-${hex}-${paletteName}" style="stroke:${hex}; stroke-width: ${strokeW}px; stroke-opacity:1; fill-opacity:0"><desc>${paletteName} - ${penSuggestion}. ${suggestedThickness}</desc>`; } function P(vars) { return `<path d="M ${vars[0]} ${vars[1]} L ${vars[2]} ${vars[3]}" stroke-linecap="round" />` } function C(vars) { return `<circle cx="${vars[0]}" cy="${vars[1]}" r="${vars[2]}" />`; } function crossesBisector(x1, y1, x2, y2) { const xIntersection = ((500 + 500 / m + m * x1 - y1) / (m + 1 / m)); const yIntersection = 500 - (1 / m) * (xIntersection - 500); return xIntersection >= Math.min(x1, x2) && xIntersection <= Math.max(x1, x2) && yIntersection >= Math.min(y1, y2) && yIntersection <= Math.max(y1, y2); } function addAttribute(trait_type, value) { console.log(`${trait_type}: ${value}`); attributes[trait_type] = value; } function makeSeed(input) { let s = 1; for (let i = 0; i < (input.length - 2) / 2; i++) { let v = parseInt(input.slice(2 + i * 2, 4 + i * 2), 16); s = ((s * v) % 999999999999) + 1 } return s; } function fractionalRand() { return rand(1,100)/100; } function rand(min, max) { const range = max - min + 1; const v = (seed % range) + min; newSeed(); return Math.floor(v); } function newSeed() { nonce++; let bigSeed = BigInt(seed); const bigNonce = BigInt(nonce); const bigMultiplier = BigInt(35932678341237); const bigModulus = BigInt(999999999999); bigSeed = (bigSeed * bigMultiplier + bigNonce) % bigModulus + BigInt(1); if (bigSeed <= Number.MAX_SAFE_INTEGER) { seed = Number(bigSeed); } else { console.log("Seed exceeded safe range, reseeding..."); seed %= 999999999999; } } document.addEventListener("keydown", function (event) { if (!tokenData.plot) { const k = event.key.toUpperCase(); if (k === "H") { console.log(`Toggling signature, please be patient. ${circlesCount} circles need to be redrawn...`); showSignature = !showSignature; document.body.innerHTML = ''; updateSVG(); } else if (k === "S") { let mS = skeuomorphic ? modeDesc[0] : modeDesc[1]; console.log(`Saving ${mS}-mode SVG with ${optDesc} Optimization...`) saveStrings([assembleComp() + "</svg>"], `TBTLITTTM-${tokenId}-${mS}-${optDesc}`, "svg"); } } }); function saveStrings(data, filename, extension) { const blob = new Blob([data], {type: 'text/plain'}); let anchor = document.createElement('a'); anchor.download = `${filename}.${extension}`; anchor.href = window.URL.createObjectURL(blob); anchor.style.display = 'none'; document.body.appendChild(anchor); anchor.click(); document.body.removeChild(anchor); } function assembleComp() { let comp = svg; if (showSignature) { comp += sig; } return comp; } function updateSVG() { document.body.insertAdjacentHTML('beforeend', assembleComp() + "</svg>"); } function selectByProbs(list, randomValue) { const totalWeight = list.reduce(function(acc, item, index) { return acc + (1 / (index + 2)); }, 0); const threshold = totalWeight * randomValue; let currentSum = 0; for (let i = 0; i < list.length; i++) { currentSum += 1 / (i + 2); if (currentSum >= threshold) { return list[i]; } } return list[list.length - 1]; } function getY(x0, y0, x1, y1, x) { const m = (y1 - y0) / (x1 - x0); const b = y0 - m * x0; const y = m * x + b; return y; } function lineWithGaps(x0, y0, x1, y1, lineNum) { let xT, yT, xE, yE; let tempPoints = []; if(x0 > x1) { xT = x0; yT = y0; x0 = x1; y0 = y1; x1 = xT; y1 = yT; } let xS = x0; let yS = y0; let lfg = true; while (lfg) { let dS; let dnm = [[60,4,48,12],[80,12,40,8]]; dS = 0; let lSeg = rand((1000 / dnm[dS][0]), (1000 / dnm[dS][1])); let gSeg = rand((1000 / dnm[dS][2]), (1000 / dnm[dS][3])); xS + lSeg > x1 ? xE = x1 : xE = xS + lSeg; yE = getY(x0, y0, x1, y1, xE); if (!perpGap || !crossesBisector(xS, yS, xE, yE)) { tempPoints.push({x1: xS, y1: yS, x2: xE, y2: yE}); } xE + gSeg > x1 ? lfg = false : xS = xE + gSeg; xS = xE + gSeg; yS = getY(x0, y0, x1, y1, xS); } for (let i = 0; i < tempPoints.length; i++) { if (optimization == 1 && lineNum % 2 == 1) { // laps optimization const j = tempPoints.length - i - 1; points.push({x1: tempPoints[j].x2, y1: tempPoints[j].y2, x2: tempPoints[j].x1, y2: tempPoints[j].y1}); } else { points.push(tempPoints[i]); } } } function getClippedLine(x0, y0, x1, y1) { const xmin = rand(1, 100) < 33 ? rand(4, 100) : rand(4, 20); const ymin = rand(1, 100) < 33 ? rand(4, 100) : rand(4, 20); const xmax = 1000 - rand(4, 20); const ymax = rand(1,100) < 33 ? 1000 - rand(4, 60) : 1000 - rand(4, 20); const inside = (x, y) => x >= xmin && x <= xmax && y >= ymin && y <= ymax; if (inside(x0, y0) && inside(x1, y1)) { return { x0, y0, x1, y1 }; } const m = (y1 - y0) / (x1 - x0); const b = y0 - m * x0; const xLeft = xmin; const yLeft = m * xLeft + b; const xRight = xmax; const yRight = m * xRight + b; const yTop = ymin; const xTop = (yTop - b) / m; const yBottom = ymax; const xBottom = (yBottom - b) / m; const intersections = [ { x: xLeft, y: yLeft }, { x: xRight, y: yRight }, { x: xTop, y: yTop }, { x: xBottom, y: yBottom } ]; const validIntersections = intersections.filter(p => inside(p.x, p.y)); if (validIntersections.length >= 2) { return { x0: validIntersections[0].x, y0: validIntersections[0].y, x1: validIntersections[1].x, y1: validIntersections[1].y }; } return null; } function distance(x1, y1, x2, y2) { return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2); } function sortPointPairs(pointPairs, allowReverse, optimize) { const sortedPairs = [pointPairs.shift()]; while (pointPairs.length > 0) { let selectedPairIndex = 0; let selectedDistance = optimize ? Infinity : -Infinity; let reverse = false; for (let i = 0; i < pointPairs.length; i++) { const pair = pointPairs[i]; const lastPair = sortedPairs[sortedPairs.length - 1]; const distances = [ distance(lastPair.x2, lastPair.y2, pair.x1, pair.y1), distance(lastPair.x2, lastPair.y2, pair.x2, pair.y2) ]; if (allowReverse) { distances.push( distance(lastPair.x2, lastPair.y2, pair.x2, pair.y2), distance(lastPair.x2, lastPair.y2, pair.x1, pair.y1) ); } distances.forEach((dist, index) => { if (optimize ? dist < selectedDistance : dist > selectedDistance) { selectedDistance = dist; selectedPairIndex = i; reverse = index % 2 !== 0; } }); } let selectedPair = pointPairs.splice(selectedPairIndex, 1)[0]; if (reverse && allowReverse) { [selectedPair.x1, selectedPair.x2] = [selectedPair.x2, selectedPair.x1]; [selectedPair.y1, selectedPair.y2] = [selectedPair.y2, selectedPair.y1]; } sortedPairs.push(selectedPair); } return sortedPairs; } function line2dots(x1, y1, x2, y2) { const d = .4; let texture = ""; const totalDistance = distance(x1, y1, x2, y2); const steps = totalDistance / d; const xStep = (x2 - x1) / steps; const yStep = (y2 - y1) / steps; for (let i = 0; i <= steps; i++) { const r = fractionalRand() * .75; let tempX = x1 + i * xStep; let tempY = y1 + i * yStep; if (i === steps) { tempX = x2; tempY = y2; } texture += C([tempX.toFixed(2), tempY.toFixed(2), r]); circlesCount++; } return texture; } function circle2dots(cx, cy, r) { const d = 0.4; let texture = ""; const circumference = 2 * Math.PI * r; const steps = circumference / d; for (let i = 0; i < steps; i++) { const theta = (i / steps) * 2 * Math.PI; const dotX = cx + r * Math.cos(theta); const dotY = cy + r * Math.sin(theta); const dotR = fractionalRand() * 0.75; texture += C([dotX.toFixed(2), dotY.toFixed(2), dotR]); circlesCount++; } return texture; }