0x457e…eea6

All memos sent from and to 0x457e…eea6.

p5.disableFriendlyErrors = true;!:`. backgroundParaA$/* START UTILS */erer; const USE_ZERO_COPY K`precision highp float; uniform!G vec2 canvasSiz!passOffsetX; // per-@(int x_origin, @ VERTEX_SHADER farow>< P CQ @ &K@^, width, height!i 1.61803398875;`
Ex Nihilo (Cosmos) is the latest work in Casey REAS’ Still Life series. The series draws on the forms and conceptual framework of the five Platonic solids: cube, tetrahedron, octahedron, dodecahedron, and icosahedron. Plato’s Theory of Forms is central to this lineage, shaping his understanding of truth, beauty, and knowledge. For Plato, the world grasped through the senses is not fully real, but an imitation of a higher, invisible realm of perfect, eternal, and unchanging Forms. Ex Nihilo (Cosmos) explores the dodecahedron, and future works will engage the remaining four solids. Ex Nihilo (Cosmos) connects Plato’s worldview to computer graphics, where images are generated ex nihilo—from code rather than physical materials. Forms are not represented directly, but instantiated through mathematical rules and procedural processes. What appears on screen is not a depiction of an object, but a series of Forms articulated through lines and resolved into pixels. In the Still Life series, Platonic solids are not depicted as stable volumes, but decomposed into pixels. Each pixel’s values are translated into lines of varying position and color. From these simple rules emerge visual fields that oscillate between structure and dissolution. Designed to run continuously, the work never repeats. Rather than producing fixed compositions, the series operates as a kinetic system that unfolds over time. Platonic Solids in Still Life software series: Cube → EARTH Tetrahedron → FIRE Octahedron → AIR Dodecahedron → COSMOS Icosahedron → WATER This work is co-presented by Art Blocks and Feral File in March 2026. The Still Life exhibitions began in 2016 with There’s No Distance at bitforms, New York. The most recent, Purely Platonic, was presented at DAM Projects, Berlin, in summer 2025. Key Commands 'R' — Show/hide the Red channel 'G' — Show/hide the Green channel 'B' — Show/hide the Blue channel 'W' — Toggle colors to White 'S' — Adjust Speed 'P' — Pause Spacebar — Generate a new Still Life
*923 Empty Rooms* is an artwork about simulation and the history of visual representation and abstraction. Each room is a space to explore. Each of the 923 unique rooms contains a simulated still life, an arrangement of forms. There are six primary forms, each linked to a city: Sun (Tokyo), Shard (Berlin), Cargo (London), Hive (New York), Pyramid (CDMX), and Moon (Los Angeles). A series of rooms will be minted over the course of a simultaneous, six-day exhibition at galleries in each city. There are 923 rooms in total to iterate through every possible combination of the six shapes: 1 form = 6 unique combinations 2 forms = 21 unique combinations 3 forms = 56 unique combinations 4 forms = 126 unique combinations 5 forms = 252 unique combinations 6 forms = 462 unique combinations *923 Empty Rooms* is an evolution of *An Empty Room*, commissioned by the Los Angeles County Museum of Art (LACMA) for the Coded: Art Enters the Computer Age, 1952–1982 exhibition. *An Empty Room* was installed at LACMA from 9 April to 2 July 2023.
*923 Empty Rooms* is an evolution of *An Empty Room*, commissioned by the Los Angeles County Museum of Art (LACMA) for the Coded: Art Enters the Computer Age, 1952–1982 exhibition. An Empty Room was installed at LACMA from 9 April to 2 July 2023. Each of the 923 unique rooms contains a simulated still life, an arrangement of forms. There are six primary forms, each linked to a city: Sun (Tokyo), Shard (Berlin), Cargo (London), Hive (New York), Pyramid (CDMX), and Moon (Los Angeles). A series of rooms will be minted for each city over the course of a simultaneous, six-day exhibition at galleries in each city. There are 923 rooms in total to iterate through every possible combination of the six shapes: 1 form = 6 unique combinations 2 forms = 21 unique combinations 3 forms = 56 unique combinations 4 forms = 126 unique combinations 5 forms = 252 unique combinations 6 forms = 462 unique combinations *923 Empty Rooms* is an artwork about simulation and the history of visual representation and abstraction. Each room is a space to explore.
*923 Empty Rooms* is an evolution of *An Empty Room*, commissioned by the Los Angeles County Museum of Art (LACMA) for the Coded: Art Enters the Computer Age, 1952–1982 exhibition. *An Empty Room* was installed at LACMA from 9 April to 2 July 2023. Each of the 923 unique rooms contains a simulated still life, an arrangement of forms. There are six primary forms, each linked to a city: Sun (Tokyo), Shard (Berlin), Cargo (London), Hive (New York), Pyramid (CDMX), and Moon (Los Angeles). There are 923 total rooms to iterate through every possible combination of these shapes: 1 form = 6 unique combinations 2 forms = 21 unique combinations 3 forms = 56 unique combinations 4 forms = 126 unique combinations 5 forms = 252 unique combinations 6 forms = 462 unique combinations An Empty Room is an artwork about simulation and the history of visual representation and abstraction.
923 Empty Rooms is an evolution of *An Empty Room*, commissioned by the Los Angeles County Museum of Art (LACMA) for the Coded: Art Enters the Computer Age, 1952–1982 exhibition.
let allCombinations = [ 999999, 100000, 110000, 120000, 130000, 140000, 111000, 112000, 113000, 114000, 115000, 116000, 123000, 124000, 134000, 111100, 111200, 111300, 111400, 111500, 111600, 112200, 113300, 112300, 112400, 112500, 112600, 113400, 113500, 113600, 114500, 114600, 115600, 123400, 123500, 124500, 111110, 111120, 111130, 111140, 111150, 111160, 111220, 111330, 111440, 111550, 111660, 111230, 111240, 111250, 111260, 111340, 111350, 111360, 111450, 111460, 111560, 112230, 112240, 113320, 112250, 112260, 114420, 113340, 113350, 114430, 113360, 112340, 112350, 112360, 112450, 112460, 112560, 113450, 113460, 113560, 114560, 123450, 111111, 111112, 111113, 111114, 111115, 111116, 111122, 111133, 111144, 111155, 111166, 111123, 111124, 111125, 111126, 111134, 111135, 111136, 111145, 111146, 111156, 111222, 111333, 111223, 111224, 111225, 111226, 111332, 111442, 111552, 111662, 111334, 111335, 111336, 111443, 111553, 111663, 111445, 111446, 111554, 111664, 111556, 111665, 111234, 111235, 111236, 111245, 111246, 111256, 111345, 111346, 111356, 111456, 112233, 112244, 112255, 113344, 113355, 112234, 112235, 113324, 112236, 112245, 113325, 114423, 112246, 113326, 112256, 114426, 115524, 114435, 113356, 112345, 112346, 112356, 112456, 113456, 200000, 220000, 230000, 240000, 250000, 222000, 221000, 223000, 224000, 225000, 226000, 234000, 235000, 245000, 222200, 222100, 222300, 222400, 222500, 222600, 223300, 224400, 221300, 221400, 221500, 221600, 223400, 223500, 223600, 224500, 224600, 225600, 234500, 234600, 235600, 222220, 222210, 222230, 222240, 222250, 222260, 222110, 222330, 222440, 222550, 222660, 222130, 222140, 222150, 222160, 222340, 222350, 222360, 222450, 222460, 222560, 223340, 223350, 224430, 223360, 223310, 225530, 224450, 224460, 225540, 224410, 221340, 221350, 221360, 221450, 221460, 221560, 223450, 223460, 223560, 224560, 234560, 222222, 222221, 222223, 222224, 222225, 222226, 222211, 222233, 222244, 222255, 222266, 222213, 222214, 222215, 222216, 222234, 222235, 222236, 222245, 222246, 222256, 222333, 222444, 222113, 222114, 222115, 222116, 222331, 222441, 222551, 222661, 222334, 222335, 222336, 222443, 222553, 222663, 222445, 222446, 222554, 222664, 222556, 222665, 222134, 222135, 222136, 222145, 222146, 222156, 222345, 222346, 222356, 222456, 223344, 223355, 223366, 224455, 223345, 223346, 224435, 223314, 223356, 224436, 225534, 223315, 224413, 223316, 226634, 225536, 225513, 224415, 224416, 221345, 221346, 221356, 221456, 223456, 300000, 330000, 340000, 350000, 360000, 333000, 331000, 332000, 334000, 335000, 336000, 345000, 346000, 356000, 333300, 333100, 333200, 333400, 333500, 333600, 334400, 335500, 336600, 331200, 331400, 331500, 331600, 332400, 332500, 332600, 334500, 334600, 335600, 345600, 314500, 333330, 333310, 333320, 333340, 333350, 333360, 333110, 333220, 333440, 333550, 333660, 333120, 333140, 333150, 333160, 333240, 333250, 333260, 333450, 333460, 333560, 334450, 334460, 335540, 334410, 334420, 336640, 335560, 335510, 336650, 335520, 331240, 331250, 331260, 331450, 331460, 331560, 332450, 332460, 332560, 334560, 314560, 333333, 333331, 333332, 333334, 333335, 333336, 333311, 333322, 333344, 333355, 333366, 333312, 333314, 333315, 333316, 333324, 333325, 333326, 333345, 333346, 333356, 333444, 333555, 333666, 333112, 333114, 333115, 333116, 333221, 333441, 333551, 333661, 333224, 333225, 333226, 333442, 333552, 333662, 333445, 333446, 333554, 333664, 333556, 333665, 333124, 333125, 333126, 333145, 333146, 333156, 333245, 333246, 333256, 333456, 334455, 334466, 334456, 334415, 335546, 334416, 335514, 334425, 336645, 334426, 335524, 331145, 334412, 331146, 336624, 335526, 335512, 336625, 331245, 331246, 331256, 331456, 332456, 400000, 440000, 450000, 460000, 444000, 441000, 442000, 443000, 445000, 446000, 456000, 415000, 416000, 426000, 444400, 444100, 444200, 444300, 444500, 444600, 445500, 446600, 441100, 441200, 441300, 441500, 441600, 442300, 442500, 442600, 443500, 443600, 445600, 415600, 425600, 444440, 444410, 444420, 444430, 444450, 444460, 444110, 444220, 444330, 444550, 444660, 444120, 444130, 444150, 444160, 444230, 444250, 444260, 444350, 444360, 444560, 445560, 445510, 446650, 445520, 441150, 446610, 445530, 441160, 446620, 446630, 441230, 441250, 441260, 441350, 441360, 441560, 442350, 442360, 442560, 443560, 412560, 444444, 444441, 444442, 444443, 444445, 444446, 444411, 444422, 444433, 444455, 444466, 444412, 444413, 444415, 444416, 444423, 444425, 444426, 444435, 444436, 444456, 444555, 444666, 444111, 444112, 444113, 444115, 444116, 444221, 444331, 444551, 444661, 444223, 444225, 444226, 444332, 444552, 444662, 444335, 444336, 444553, 444663, 444556, 444665, 444123, 444125, 444126, 444135, 444136, 444156, 444235, 444236, 444256, 444356, 445566, 441155, 441166, 445516, 446615, 445526, 441156, 445512, 446625, 445536, 445513, 446635, 441125, 446612, 442256, 445523, 441136, 446623, 441235, 441236, 441256, 441356, 442356, 500000, 550000, 560000, 510000, 555000, 551000, 552000, 553000, 554000, 556000, 516000, 526000, 512000, 513000, 555500, 555100, 555200, 555300, 555400, 555600, 556600, 551100, 552200, 551200, 551300, 551400, 551600, 552300, 552400, 552600, 553400, 553600, 554600, 512600, 513600, 555550, 555510, 555520, 555530, 555540, 555560, 555110, 555220, 555330, 555440, 555660, 555120, 555130, 555140, 555160, 555230, 555240, 555260, 555340, 555360, 555460, 556610, 551160, 556620, 556630, 551120, 552260, 556640, 551130, 552210, 551140, 551230, 551240, 551260, 551340, 551360, 551460, 552340, 552360, 552460, 553460, 512360, 555555, 555551, 555552, 555553, 555554, 555556, 555511, 555522, 555533, 555544, 555566, 555512, 555513, 555514, 555516, 555523, 555524, 555526, 555534, 555536, 555546, 555666, 555111, 555222, 555112, 555113, 555114, 555116, 555221, 555331, 555441, 555661, 555223, 555224, 555226, 555332, 555442, 555662, 555334, 555336, 555443, 555663, 555446, 555664, 555123, 555124, 555126, 555134, 555136, 555146, 555234, 555236, 555246, 555346, 551166, 552266, 553366, 556612, 551126, 556613, 551136, 552216, 556614, 556623, 551146, 556624, 551123, 553316, 556634, 552246, 551134, 552214, 551234, 551236, 551246, 551346, 552346, 600000, 660000, 610000, 620000, 666000, 661000, 662000, 663000, 664000, 665000, 612000, 613000, 623000, 666600, 666100, 666200, 666300, 666400, 666500, 661100, 662200, 661200, 661300, 661400, 661500, 662300, 662400, 662500, 663400, 663500, 664500, 612300, 612400, 613400, 666660, 666610, 666620, 666630, 666640, 666650, 666110, 666220, 666330, 666440, 666550, 666120, 666130, 666140, 666150, 666230, 666240, 666250, 666340, 666350, 666450, 661120, 661130, 662210, 661140, 661150, 663310, 662230, 662240, 663320, 662250, 661230, 661240, 661250, 661340, 661350, 661450, 662340, 662350, 662450, 663450, 612340, 666666, 666661, 666662, 666663, 666664, 666665, 666611, 666622, 666633, 666644, 666655, 666612, 666613, 666614, 666615, 666623, 666624, 666625, 666634, 666635, 666645, 666111, 666222, 666112, 666113, 666114, 666115, 666221, 666331, 666441, 666551, 666223, 666224, 666225, 666332, 666442, 666552, 666334, 666335, 666443, 666553, 666445, 666554, 666123, 666124, 666125, 666134, 666135, 666145, 666234, 666235, 666245, 666345, 661122, 661133, 662244, 661123, 661124, 662213, 661125, 661134, 662214, 663312, 661135, 662215, 661145, 663314, 663315, 664413, 662235, 662245, 661234, 661235, 661245, 661345, 662345, 612345 ];
var seed = parseInt(tokenData.hash.slice(0, 16), 16); let projectNumber = Math.floor(parseInt(tokenData.tokenId) / 1000000); let mintNumber = parseInt(tokenData.tokenId) % 1000000; p5.disableFriendlyErrors = true; let rezs = [150, 200, 300]; let cIndex = 1; let lineThickness; let lineDepth; let lineLength; let lineSpacing; let depth = 255.0; let displayRed = true; let displayGreen = true; let displayBlue = true; let stillLifeDim = -1; let stillLifeDepthNeg = 0; let stillLifeDepthPos = 0; let depthScalar = 1.0; let speedScalar = 1.0; let speeds = [0.25, 0.5, 1.0, 2.0, 0.0]; let speedIndex = 2; let SEED = 0; let lengthScalar = 1.3; let index = 0; let laIndex = 771; let combination = []; let angle = 0.0; let alphapix; let cla, cny, cberlin, ccdmx, clondon, ctokyo; let s1, s2, s3, s4; let sc; let foregrounds = []; let bColor = 246; let shapes = []; let gl; let stillLifePO2 = 2; let ext; let pgl; let viewDiagram = false; let viewMatrix; let modelViewMatrix; let dispMapTexture; let CDMXSpin = 1; const vertCode = `precision highp float; uniform mat4 uViewMatrix; uniform mat4 uProjectionMatrix; uniform mat4 uModelViewMatrix; uniform mat4 uModelViewProjectionMatrix; uniform vec2 canvasSize; uniform float stillLifeDim; uniform float stillLifePO2; uniform float stillLifeDepthNeg; uniform float stillLifeDepthPos; uniform float depthScalar; uniform float lineThickness; uniform float lineDepth; uniform float lineLength; uniform vec3 color; uniform sampler2D displacementMap; attribute vec3 coordinates; float map(float value, float min1, float max1, float min2, float max2) { return min2 + (value - min1) * (max2 - min2) / (max1 - min1); } struct Line { vec3 start; vec3 end; }; Line getLineFromDisplacementMap(int x_origin, int y_origin) { Line l; vec2 imageCoords = vec2(x_origin, y_origin); imageCoords.x += .5; imageCoords.y += .5; vec2 samplePos = imageCoords.xy/stillLifePO2; vec4 dispMapColor = texture2D(displacementMap, samplePos); float maxEdge = max(canvasSize.x, canvasSize.y); float x = float(x_origin); float y = float(y_origin); float z = map(dot(dispMapColor.xyz, color), 0.0, 1.0, -stillLifeDepthNeg, stillLifeDepthPos); l.start.x = map(x, 0.0, stillLifeDim, -maxEdge / 2.0, maxEdge / 2.0); l.start.y = map(y, 0.0, stillLifeDim, -maxEdge / 2.0, maxEdge / 2.0); l.start.z = -z; l.end.x = map(x, 0.0, stillLifeDim, -maxEdge / 2.0, maxEdge / 2.0) - lineDepth; l.end.y = map(y, 0.0, stillLifeDim, -maxEdge / 2.0, maxEdge / 2.0) - lineDepth; l.end.z = -lineLength - z; return l; } void main() { bool lineStart = false; if (coordinates.y == 0.0) lineStart = true; if (coordinates.y == 1.0) lineStart = true; if (coordinates.y == 2.0) lineStart = false; if (coordinates.y == 3.0) lineStart = true; if (coordinates.y == 4.0) lineStart = false; if (coordinates.y == 5.0) lineStart = false; int imageCoordsY = int(floor(coordinates.x / stillLifeDim)); int imageCoordsX = int(floor(coordinates.x - float(imageCoordsY) * stillLifeDim)); Line l = getLineFromDisplacementMap(imageCoordsX, imageCoordsY); vec3 vertexPosition; if (lineStart) { vertexPosition = l.start; } else { vertexPosition = l.end; } vec4 finalPos = vec4(vertexPosition, 1.0); finalPos = uModelViewProjectionMatrix * finalPos; vec4 projLineStart = uModelViewProjectionMatrix * vec4(l.start, 1.0); vec4 projLineEnd = uModelViewProjectionMatrix * vec4(l.end, 1.0); vec2 lineDirection = projLineStart.xy - projLineEnd.xy; lineDirection = vec2(-lineDirection.y, lineDirection.x); float maxEdge = max(canvasSize.x, canvasSize.y); lineDirection /= canvasSize / maxEdge; vec2 displacement = normalize(lineDirection); displacement /= canvasSize; displacement *= lineThickness; if (coordinates.y == 0.0) finalPos.xy -= displacement; if (coordinates.y == 2.0) finalPos.xy -= displacement; if (coordinates.y == 5.0) finalPos.xy -= displacement; if (coordinates.y == 1.0) finalPos.xy += displacement; if (coordinates.y == 3.0) finalPos.xy += displacement; if (coordinates.y == 4.0) finalPos.xy += displacement; finalPos.z = 0.0; gl_Position = finalPos; } `; const fragCode = `precision highp float; uniform vec3 color; void main() { gl_FragColor = vec4(color, 1.0); } `; let triangle_buffer; let numTris; function setupGeometry() { let triangles = []; numTris = 0; for (let y = 0; y < rezs[cIndex]; y += 1) { for (let x = 0; x < rezs[cIndex]; x += 1) { triangles.push(x + y * stillLifeDim, 0, 0); triangles.push(x + y * stillLifeDim, 1, 0); triangles.push(x + y * stillLifeDim, 2, 0); triangles.push(x + y * stillLifeDim, 3, 0); triangles.push(x + y * stillLifeDim, 4, 0); triangles.push(x + y * stillLifeDim, 5, 0); numTris += 6; } } triangle_buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, triangle_buffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangles), gl.STATIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER, null); } function setupShapes() { let sss = 0.72; shapes = []; for (let i = 0; i < combination.length; i++) { shapes.push( new VShape( -stillLifeDim / 2, -stillLifeDim / 2, stillLifeDim * sss, combination[i] ) ); } theDetails(); } function theDetails() { let maxSide = max(width, height); if (maxSide < 400) { depthScalar = map(maxSide, 50, 400, 0.05, 0.3); } else { depthScalar = map(maxSide, 400, 3840, 0.3, 2.0); } stillLifeDepthNeg = 255.0; stillLifeDepthPos = 255.0; lengthScalar = 1.0; if (index < 155) { tokyoParams(); } else if (index < 309) { berlinParams(); } else if (index < 463) { londonParams(); } else if (index < 617) { nycParams(); } else if (index < laIndex) { cdmxParams(); } else { laParams(); } } let shaderProgram; function setupShaders() { let vertShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertShader, vertCode); gl.compileShader(vertShader); const vertError = gl.getShaderInfoLog(vertShader); if (vertError.length > 0) { throw vertError; } let fragShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragShader, fragCode); gl.compileShader(fragShader); const fragError = gl.getShaderInfoLog(fragShader); if (fragError.length > 0) { throw fragError; } shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertShader); gl.attachShader(shaderProgram, fragShader); gl.linkProgram(shaderProgram); } function createDisplacementMapTexture() { dispMapTexture = gl.createTexture(); while (stillLifePO2 < stillLifeDim) { stillLifePO2 *= 2; } } function transferDisplacementMap() { let img = alphapix.get(); img.loadPixels(); let uvTexture = Array(stillLifePO2 * stillLifePO2 * 4).fill(255); const randomStuff = new Uint8Array(uvTexture); for (let x = 0; x < stillLifeDim; ++x) { for (let y = 0; y < stillLifeDim; ++y) { const index1 = 4 * (y * stillLifePO2 + x); const index2 = 4 * (y * stillLifeDim + x); randomStuff[index1 + 0] = img.pixels[index2 + 0]; randomStuff[index1 + 1] = img.pixels[index2 + 1]; randomStuff[index1 + 2] = img.pixels[index2 + 2]; } } gl.bindTexture(gl.TEXTURE_2D, dispMapTexture); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, stillLifePO2, stillLifePO2, 0, gl.RGBA, gl.UNSIGNED_BYTE, randomStuff ); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.bindTexture(gl.TEXTURE_2D, null); gl.activeTexture(gl.TEXTURE2); gl.bindTexture(gl.TEXTURE_2D, dispMapTexture); const displaceMapLocation = gl.getUniformLocation( shaderProgram, "displacementMap" ); gl.uniform1i(displaceMapLocation, 2); } function setMatrices() { const viewMatrix = this._renderer._curCamera.cameraMatrix; const projectionMatrix = this._renderer.uPMatrix; const modelViewMatrix = this._renderer.uMVMatrix; const modelViewProjectionMatrix = modelViewMatrix.copy(); modelViewProjectionMatrix.mult(projectionMatrix); gl.uniformMatrix4fv( gl.getUniformLocation(shaderProgram, "uViewMatrix"), false, viewMatrix.mat4 ); gl.uniformMatrix4fv( gl.getUniformLocation(shaderProgram, "uProjectionMatrix"), false, projectionMatrix.mat4 ); gl.uniformMatrix4fv( gl.getUniformLocation(shaderProgram, "uModelViewMatrix"), false, modelViewMatrix.mat4 ); gl.uniformMatrix4fv( gl.getUniformLocation(shaderProgram, "uModelViewProjectionMatrix"), false, modelViewProjectionMatrix.mat4 ); } function setUniforms() { gl.uniform2f( gl.getUniformLocation(shaderProgram, "canvasSize"), width, height ); gl.uniform1f( gl.getUniformLocation(shaderProgram, "stillLifeDim"), stillLifeDim ); gl.uniform1f( gl.getUniformLocation(shaderProgram, "stillLifePO2"), stillLifePO2 ); gl.uniform1f( gl.getUniformLocation(shaderProgram, "depthScalar"), depthScalar ); gl.uniform1f( gl.getUniformLocation(shaderProgram, "stillLifeDepthNeg"), stillLifeDepthNeg * depthScalar ); gl.uniform1f( gl.getUniformLocation(shaderProgram, "stillLifeDepthPos"), stillLifeDepthPos * depthScalar ); gl.uniform1f( gl.getUniformLocation(shaderProgram, "lineThickness"), lineThickness ); gl.uniform1f(gl.getUniformLocation(shaderProgram, "lineLength"), lineLength); gl.uniform1f(gl.getUniformLocation(shaderProgram, "lineDepth"), lineDepth); } function beginLinesShader() { gl.useProgram(shaderProgram); gl.bindBuffer(gl.ARRAY_BUFFER, triangle_buffer); transferDisplacementMap(); setUniforms(); const coord = gl.getAttribLocation(shaderProgram, "coordinates"); gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(coord); gl.enable(gl.BLEND); gl.disable(gl.DEPTH_TEST); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.viewport(0, 0, canvas.width, canvas.height); } function endLinesShader() { gl.useProgram(null); } function drawLines() { beginLinesShader(); setMatrices(); gl.uniform3f(gl.getUniformLocation(shaderProgram, "color"), 1, 0, 0); if (displayRed) { gl.drawArrays(gl.TRIANGLES, 0, numTris); } translate(lineSpacing, 0.0, 0.1); setMatrices(); gl.uniform3f(gl.getUniformLocation(shaderProgram, "color"), 0, 1, 0); if (displayGreen) { gl.drawArrays(gl.TRIANGLES, 0, numTris); } translate(lineSpacing, 0.0, 0.1); setMatrices(); gl.uniform3f(gl.getUniformLocation(shaderProgram, "color"), 0, 0, 1); if (displayBlue) { gl.drawArrays(gl.TRIANGLES, 0, numTris); } endLinesShader(); } function setupTransform() { ortho(); scale(1.45); rotateY(0.33); rotateX(-0.33); } function setupCombination(code) { combination = []; let comb = str(code); for (let i = 0; i < comb.length; i++) { let char = comb[i]; if (char != "0") { let c = int(comb[i]) - 1; combination.push(c); } } } function defineColors() { let aaa = 254; ctokyo = color(227, 143, 53, aaa); // Orange cberlin = color(53, 155, 227, aaa); // Blue clondon = color(231, 71, 71, aaa); // Red cny = color(166, 79, 206, aaa); // Lavender ccdmx = color(76, 205, 82, aaa); // Green cla = color(238, 211, 30, aaa); // Yellow foregrounds = [ctokyo, cberlin, clondon, cny, ccdmx, cla]; s1 = color(255, 226, 204); s2 = color(204, 255, 226); s3 = color(225, 204, 226); s4 = color(164, 204, 255); sc = [s1, s2, s3, s4]; } function windowResized() { resizeCanvas(windowWidth, windowHeight); theDetails(); } function setup() { createCanvas(windowWidth, windowHeight, WEBGL); r = new RND(seed); defineRez(); if (mintNumber >= 924) { index = int(random(0, 924)); } else { index = mintNumber; } defineColors(); imageMode(CENTER); gl = document.getElementById("defaultCanvas0").getContext("webgl"); stillLifeDim = rezs[cIndex]; alphapix = createGraphics(stillLifeDim, stillLifeDim, WEBGL); pgl = alphapix._renderer.GL; pgl.disable(gl.DEPTH_TEST); setupShaders(); doIt(); } function defineRez() { cIndex = 1; } function doIt() { stillLifeDim = rezs[cIndex]; alphapix.resizeCanvas(stillLifeDim, stillLifeDim); setupCombination(allCombinations[index]); setupShapes(); setupGeometry(); createDisplacementMapTexture(); createStillLife(); } function createGround() { if (speedIndex != 4) { angle += 0.0005; } let ss = map(sin(angle), -1, 1, 0, 1); let c1 = lerpColor(sc[0], sc[1], ss); let c2 = lerpColor(sc[1], sc[2], ss); let c3 = lerpColor(sc[2], sc[3], ss); let c4 = lerpColor(sc[3], sc[1], ss); alphapix.background(255); alphapix.blendMode(BLEND); alphapix.beginShape(); alphapix.fill(c1); alphapix.vertex(-alphapix.width/2, -alphapix.height/2); alphapix.fill(c2); alphapix.vertex(alphapix.width/2, -alphapix.height/2); alphapix.fill(c3); alphapix.vertex(alphapix.width/2, alphapix.height/2); alphapix.fill(c4); alphapix.vertex(-alphapix.width/2, alphapix.height/2); alphapix.endShape(); } function createStillLife() { createGround(); alphapix.blendMode(MULTIPLY); for (let i = 0; i < shapes.length; i++) { shapes[i].move(); shapes[i].display(alphapix); } } function draw() { let scaleFactor = max(width, height) / 1200.0; if (cIndex == 2) { lineThickness = 1.66 * scaleFactor; lineLength = 3.0 * lengthScalar * scaleFactor; } else if (cIndex == 0) { lineThickness = 3.33 * scaleFactor; lineLength = 8.0 * lengthScalar * scaleFactor; } else { lineThickness = 2.22 * scaleFactor; lineLength = 12.0 * lengthScalar * scaleFactor; } lineDepth = 2 * scaleFactor; lineSpacing = 2.22 * scaleFactor; createStillLife(); background(bColor); push(); setupTransform(); drawLines(); pop(); if (viewDiagram) { fill(255); noStroke(); rect(0, 0, -stillLifeDim/2, -stillLifeDim/2); image(alphapix, 0, 0); } if (speedIndex != 4) { CDMXSpin++; } } class VShape { constructor(xin, yin, uin, win) { this.scale = 1.0; this.targetScale = 1.0; this.scaleStep = 0.2; this.dia = uin * 0.75; this.mdia = uin * 0.8; this.rdia = uin * 0.66; this.ddia = uin * 0.55; this.tdia = uin * 0.8; this.tdia2 = uin * 0.7; this.hu = uin * 0.5; this.qr1 = uin * 0.3; this.qr2 = uin * 0.2; this.sr = uin * 0.4; this.x = xin; this.y = yin; this.unit = stillLifeDim; this.rx = this.x + (this.unit - this.rdia) / 2; this.ry = this.y + (this.unit - this.rdia) / 2; this.cx = this.x + this.unit / 2; this.cy = this.y + this.unit / 2; this.cindex = win; this.sindex = win; this.movex = 0; this.movey = 0; this.hexx = uin * 0.2; this.hexy = uin * 0.346; this.moonAngle = r.rb(0, TWO_PI); this.moveyval = r.rb(0.0005, 0.002); this.movexval = r.rb(0.0005, 0.002); if (r.rb(1) > 0.5) { this.moveyval *= -1; } if (r.rb(1) > 0.5) { this.movexval *= -1; } } resetScale() { this.targetScale = 1.0; } upScale() { this.targetScale += this.scaleStep; } downScale() { this.targetScale -= this.scaleStep; this.targetScale = max(0.0, this.targetScale); } move() { this.movex += this.movexval * speedScalar; this.movey += this.moveyval * speedScalar; this.scale = (this.targetScale - this.scale) * 0.05 + this.scale; } display(pg) { if (this.sindex == 0) { this.sTokyo(pg); } else if (this.sindex == 1) { this.sBerlin(pg); } else if (this.sindex == 2) { this.sLondon(pg); } else if (this.sindex == 3) { this.sNYC(pg); } else if (this.sindex == 4) { this.sCDMX(pg); } else if (this.sindex == 5) { this.sLA(pg); } } sTokyo(pg) { pg.noStroke(); pg.push(); pg.scale(this.scale); pg.translate(this.cx, this.cy); pg.rotateY(this.movey); pg.rotateX(this.movex); pg.fill(foregrounds[this.cindex]); pg.ellipse(0, 0, this.dia, this.dia); pg.pop(); } sBerlin(pg) { pg.noStroke(); pg.fill(foregrounds[this.cindex]); pg.push(); pg.scale(this.scale); pg.beginShape(); pg.translate(this.cx, this.cy); pg.rotateX(this.movex); pg.rotateY(this.movey); pg.vertex(-this.qr1, -this.hu); pg.vertex(this.qr1, -this.qr2); pg.vertex(this.qr1, this.hu); pg.vertex(-this.qr1, this.qr2); pg.endShape(); pg.pop(); } sLondon(pg) { pg.push(); pg.scale(this.scale); pg.translate(this.rx + this.rdia / 2, this.ry + this.rdia / 2); pg.rotateY(this.movey); pg.rotateX(this.movex); pg.noStroke(); pg.fill(foregrounds[this.cindex]); pg.beginShape(); pg.vertex(-this.rdia / 2, -this.rdia / 2); pg.vertex(this.rdia / 2, -this.rdia / 2); pg.vertex(this.rdia / 2, this.rdia / 2); pg.vertex(-this.rdia / 2, this.rdia / 2); pg.endShape(); pg.pop(); } sNYC(pg) { pg.push(); pg.scale(this.scale); pg.translate(this.rx + this.rdia / 2, this.ry + this.rdia / 2); pg.rotateY(this.movey); pg.rotateX(this.movex); pg.noStroke(); pg.fill(foregrounds[this.cindex]); pg.beginShape(); pg.vertex(this.hexx, -this.hexy); pg.vertex(this.hexx*2, 0); pg.vertex(this.hexx, this.hexy); pg.vertex(-this.hexx, this.hexy); pg.vertex(-this.hexx*2, 0); pg.vertex(-this.hexx, -this.hexy); pg.endShape(); pg.pop(); } sCDMX(pg) { pg.push(); pg.scale(this.scale); pg.translate(this.rx + this.rdia / 2, this.ry + this.rdia / 2.66); pg.rotateY(this.movey); pg.rotateX(this.movex); pg.rotateZ(CDMXSpin/1000.0); pg.noStroke(); pg.fill(foregrounds[this.cindex]); pg.beginShape(); pg.vertex(0, -this.tdia / 2); pg.vertex(this.tdia / 2, this.tdia2 / 2); pg.vertex(-this.tdia / 2, this.tdia2 / 2); pg.endShape(); pg.pop(); } sLA(pg) { pg.noStroke(); pg.fill(foregrounds[this.cindex]); pg.push(); pg.scale(this.scale); pg.translate(this.cx, this.cy); pg.rotate(this.moonAngle); pg.rotateX(this.movex); pg.rotateY(this.movey); pg.rotateZ(CDMXSpin/1000.0); pg.arc(0, 0, this.mdia, this.mdia, 0.7, TWO_PI - 0.7, CHORD); pg.pop(); } } function tokyoParams() { displayRed = true; displayGreen = true; displayBlue = true; bColor = 246; lengthScalar = 0.8; } function berlinParams() { displayRed = false; displayGreen = true; displayBlue = true; bColor = 15; lengthScalar = 0.5; if (index === 155) { stillLifeDepthNeg = 350.0; stillLifeDepthPos = 150.0; } } function londonParams() { displayRed = true; displayGreen = false; displayBlue = true; bColor = 246; lengthScalar = 0.5; } function nycParams() { displayRed = false; displayGreen = false; displayBlue = true; bColor = 246; lengthScalar = 0.7; if (index === 463) { stillLifeDepthNeg = 400.0; stillLifeDepthPos = 100.0; } } function cdmxParams() { displayRed = false; displayGreen = true; displayBlue = false; bColor = 51; lengthScalar = 0.7; if (index === 617) { stillLifeDepthNeg = 500.0; stillLifeDepthPos = 0.0; } } function laParams() { displayRed = true; displayGreen = true; displayBlue = true; bColor = 26; lengthScalar = 0.8; } function keyPressed() { if (key == '=' || key == '+') { for (let i = 0; i < shapes.length; i++) { shapes[i].upScale(); } } else if (key == '-' || key == '_') { for (let i = 0; i < shapes.length; i++) { shapes[i].downScale(); } } else if (key == 'd' || key == 'D') { viewDiagram = !viewDiagram; } else if (key == ' ') { bColor -= 26; if (bColor <= 0) { bColor = 255; } } else if (key == 'r' || key == 'R') { displayRed = !displayRed; } else if (key == 'g' || key == 'G') { displayGreen = !displayGreen; } else if (key == 'b' || key == 'B'){ displayBlue = !displayBlue; } else if (key == '1') { tokyoParams(); } else if (key == '2') { berlinParams(); } else if (key == '3') { londonParams(); } else if (key == '4') { nycParams(); } else if (key == '5') { cdmxParams(); } else if (key == '6') { laParams(); } else if (keyCode == UP_ARROW) { stillLifeDepthNeg += 26; stillLifeDepthPos += 26; } else if (keyCode == DOWN_ARROW) { stillLifeDepthNeg -= 26; stillLifeDepthPos -= 26; } else if (key == 's' || key == 'S') { speedIndex++; speedIndex = speedIndex % speeds.length; speedScalar = speeds[speedIndex]; } else if (key == '0') { lengthScalar += 0.2; } else if (key == '9') { if (lengthScalar > 0.4) { lengthScalar -= 0.2; } } else if (key == 't' || key == 'T') { cIndex++; if (cIndex >= rezs.length) { cIndex = 0; } doIt(); } else if (key == 'p' || key == 'P') { saveCanvas(nf(index,3) + '-' + allCombinations[index] + "-" + frameCount + ".png", 0, 0, width, height); } } class RND { constructor(seed) { this.seed = seed; } rd() { this.seed ^= this.seed << 13; this.seed ^= this.seed >> 17; this.seed ^= this.seed << 5; return ((this.seed < 0 ? ~this.seed + 1 : this.seed) % 1000) / 1000; } rb(a, b) { return a + (b - a) * this.rd(); } }
let seed = parseInt(tokenData.hash.slice(0, 16), 16); let projectNumber = Math.floor(parseInt(tokenData.tokenId) / 1000000) let mintNumber = parseInt(tokenData.tokenId) % 1000000; let surface = 0; let growth = 0; let origin = 0; let networkMode = 0; let r; let numToDisplay = 1; let globalSpin = 0.0125; let numCells = 100; let cells = new Array(numCells); let largestElement; let smallestElement; let canvasEdge; let freeze = true; let frame; let drawCenter = true; let drawPerimeter = true; let drawAngle = true; let fillCell = false; let drawBackground = false; let textOn = false; let lineThickness = 0; let elementColor; let centerColor; let angleColor; let textColor; let networkColor; let grayNetworkColor; let bgcolor; function setup() { createCanvas(window.innerWidth, window.innerHeight); pixelDensity(displayDensity()); frameRate(30); textFont('monospace'); mintNumber += 1; surface = mintNumber % 8; origin = mintNumber % 3; growth = mintNumber % 5; if (surface == 0) { surface = 8; } if (origin == 0) { origin = 3 ; } if (growth == 0) { growth = 5; } totalReset(); } function totalReset() { r = new RND(); numToDisplay = 1; canvasEdge = dist(0, 0, width, height); if (width == height) { largestElement = canvasEdge * 0.055; smallestElement = canvasEdge * 0.008; } else { largestElement = canvasEdge * 0.06; smallestElement = canvasEdge * 0.008; } frame = canvasEdge / 40; lineThickness = map(canvasEdge, 2202, 4493, 1.0, 2.0); if (lineThickness < 1.0) { lineThickness = 1.0; } for (let i = 0; i < numCells; i++) { let ss = 0; if (growth == 1) { ss = map(i, 0, numCells, smallestElement, largestElement); } else if (growth == 2) { ss = map(i, 0, numCells, largestElement, smallestElement); } else if (growth == 3) { ss = map(i, 0, numCells, smallestElement * 4, smallestElement * 4); } else if (growth == 4) { ss = map(i, 0, numCells, largestElement * 0.8, largestElement * 0.8); } else if (growth == 5) { ss = map(i, 0, numCells, 0.0, 1.0); ss = pow(ss, 5); ss = map(ss, 0, 1, smallestElement, largestElement * 2); } let midX = 0; let midY = 0; if (origin == 1) { midX = width / 2; midY = height / 2; } else if (origin == 2) { midX = r.rb(frame, width - frame); midY = height / 2; } else if (origin == 3) { midX = r.rb(frame, width - frame); midY = r.rb(frame, height - frame); } let r1 = r.rb(0, TWO_PI); let r2 = r.rb(0, TWO_PI); cells[i] = new Cell(midX, midY, ss, i, cells, r1, r2); } setParameters(); background(bgcolor); } function setParameters() { if (surface == 1) { networkMode = 0; textOn = false; drawCenter = true; drawPerimeter = true; fillCell = false; drawAngle = true; drawBackground = true; bgcolor = color(0); elementColor = color(153); centerColor = color(246); angleColor = color(127); networkColor = color(246); } else if (surface == 2) { networkMode = 0; textOn = false; drawCenter = true; drawPerimeter = true; fillCell = true; drawAngle = true; drawBackground = true; bgcolor = color(246); elementColor = color(127, 153); centerColor = color(102); angleColor = color(51); networkColor = color(0); } else if (surface == 3) { networkMode = 1; textOn = true; drawCenter = false; drawPerimeter = false; fillCell = false; drawAngle = false; drawBackground = true; bgcolor = color(0); elementColor = color(0); centerColor = color(246); textColor = color(246); grayNetworkColor = 127; } else if (surface == 4) { networkMode = 1; textOn = false; drawCenter = true; drawPerimeter = false; fillCell = false; drawAngle = false; drawBackground = true; bgcolor = color(0); elementColor = color(246); centerColor = color(127); grayNetworkColor = 246; } else if (surface == 5) { networkMode = 0; textOn = false; drawCenter = false; drawPerimeter = true; fillCell = true; drawAngle = true; drawBackground = true; bgcolor = color(153); elementColor = color(0); centerColor = color(246); textColor = color(246); networkColor = color(246); angleColor = color(127); } else if (surface == 6) { networkMode = 0; textOn = false; drawCenter = true; drawPerimeter = true; fillCell = false; drawAngle = false; drawBackground = false; bgcolor = color(0); elementColor = color(0, 51); centerColor = color(246, 102); networkColor = color(0, 51); } else if (surface == 7) { networkMode = 0; drawCenter = true; drawPerimeter = true; fillCell = false; drawAngle = false; drawBackground = false; bgcolor = color(246); elementColor = color(176, 51); centerColor = color(246, 102); networkColor = color(0, 51); textOn = false; } else if (surface == 8) { networkMode = 0; textOn = false; drawCenter = false; drawPerimeter = true; fillCell = false; drawAngle = false; drawBackground = false; bgcolor = color(246); elementColor = color(246, 51); networkColor = color(0, 51); } } function draw() { if (drawBackground) { background(bgcolor); } for (let i = 0; i < numToDisplay; i++) { cells[i].check(); } for (let i = 0; i < numToDisplay; i++) { cells[i].display(); } for (let i = 0; i < numToDisplay; i++) { cells[i].displayNetwork(); } for (let i = 0; i < numToDisplay; i++) { cells[i].drawCenter(); } if (numToDisplay < cells.length) { if (frameCount % 10 == 0) { numToDisplay++; } } } function mousePressed() { totalReset(); } function keyPressed() { if (key == "1") { surface = 1; totalReset(); } else if (key == "2") { surface = 2; totalReset(); } else if (key == "3") { surface = 3; totalReset(); } else if (key == "4") { surface = 4; totalReset(); } else if (key == "5") { surface = 5; totalReset(); } else if (key == "6") { surface = 6; totalReset(); } else if (key == "7") { surface = 7; totalReset(); } else if (key == "8") { surface = 8; totalReset(); } if (key == ' ') { totalReset(); } if (key == 'p' || key == 'P') { freeze = !freeze; if (freeze) { noLoop(); } else { loop(); } } } class Cell { constructor(xin, yin, rin, num, cells, a1, a2) { this.x = xin; this.newx = xin; this.y = yin; this.newy = yin; this.r = rin; this.id = num; this.others = cells; this.moveangle = a1; this.angle = a2; this.inc = 1.0; this.moveangle = 0; this.speed = map(canvasEdge, 400 * 400, 1920 * 1080, 0.5, 1.0); this.ds = canvasEdge / 150.0; this.friends = new Array(numCells); this.friendsAlpha = new Array(numCells); for (let i = 0; i < numCells; i++) { this.friends[i] = 0; this.friendsAlpha[i] = 0; } this.friendCount = 0; this.spinRate = globalSpin; this.cellwidth = this.r + this.r; this.cellheight = this.cellwidth; } move(ato, rto) { this.newx = this.newx + cos(ato) * rto; this.newy = this.newy + sin(ato) * rto; } check() { this.friendCount = 0; this.newx += cos(this.angle); this.newy += sin(this.angle); if (this.newx < this.r + frame) { this.newx = this.r + frame; } if (this.newx > width - this.r - frame) { this.newx = width - this.r - frame; } if (this.newy < this.r + frame) { this.newy = this.r + frame; } if (this.newy > height - this.r - frame) { this.newy = height - this.r - frame; } this.x += (this.newx - this.x) / 10.0; this.y += (this.newy - this.y) / 10.0; for (let i = this.id + 1; i < numToDisplay; i++) { let dx = this.others[i].newx - this.newx; let dy = this.others[i].newy - this.newy; let distance = dist(this.x, this.y, this.others[i].x, this.others[i].y); if (distance < this.cellwidth / 2 + this.others[i].cellwidth / 2 - 1) { this.friends[this.friendCount] = i; this.friendCount++; let rA = atan2(dy, dx); this.others[i].move(rA, this.inc); this.others[i].angle += this.spinRate; this.move(rA + PI, this.inc); this.angle += this.spinRate; } } } drawCenter() { if (textOn) { noStroke(); fill(textColor); textSize(canvasEdge / 100); text(this.id, this.x, this.y); } else if (drawCenter) { noStroke(); fill(centerColor); ellipse(this.x, this.y, this.ds / 2, this.ds / 2); } } drawAngle() { strokeWeight(lineThickness); let ax = this.x + cos(this.angle) * (this.r - this.ds / 2); let ay = this.y + sin(this.angle) * (this.r - this.ds / 2); noStroke(); fill(angleColor); ellipse(ax, ay, this.ds / 2, this.ds / 2); } drawPerimeter() { if (fillCell == true) { noStroke(); fill(elementColor); ellipse(this.x, this.y, this.cellwidth, this.cellheight); } else { strokeWeight(lineThickness); noFill(); stroke(elementColor); ellipse(this.x, this.y, this.cellwidth, this.cellheight); } } display() { if (drawPerimeter) { this.drawPerimeter(); } if (drawAngle) { this.drawAngle(); } } displayNetwork() { strokeWeight(lineThickness); for (let i = 0; i < this.friendCount; i++) { if (networkMode == 0) { beginShape(LINES); stroke(networkColor); vertex(this.x, this.y); vertex(this.others[this.friends[i]].x, this.others[this.friends[i]].y); endShape(); } else { this.friendsAlpha[this.friends[i]] += 5; } } if (networkMode == 1) { for (let i = 0; i < numToDisplay; i++) { if (this.friendsAlpha[i] > 1.0) { beginShape(LINES); stroke(grayNetworkColor, this.friendsAlpha[i]); vertex(this.x, this.y); vertex(this.others[i].x, this.others[i].y); endShape(); this.friendsAlpha[i] -= 2.0; } } } } } class RND { constructor() { this.useA = false; let sfc32 = function (uint128Hex) { let a = parseInt(uint128Hex.substr(0, 8), 16); let b = parseInt(uint128Hex.substr(8, 8), 16); let c = parseInt(uint128Hex.substr(16, 8), 16); let d = parseInt(uint128Hex.substr(24, 8), 16); return function () { a |= 0; b |= 0; c |= 0; d |= 0; let t = (((a + b) | 0) + d) | 0; d = (d + 1) | 0; a = b ^ (b >>> 9); b = (c + (c << 3)) | 0; c = (c << 21) | (c >>> 11); c = (c + t) | 0; return (t >>> 0) / 4294967296; }; }; this.prngA = new sfc32(tokenData.hash.substr(2, 32)); this.prngB = new sfc32(tokenData.hash.substr(34, 32)); for (let i = 0; i < 1e6; i += 2) { this.prngA(); this.prngB(); } } random_dec() { this.useA = !this.useA; return this.useA ? this.prngA() : this.prngB(); } rb(a, b) { return a + (b - a) * this.random_dec(); } }
Ways of knowing... Ways of seeing… I can trace the origin of *Pre-Process* back to a Saturday afternoon in 2003 when I was sketching—first on paper, and then with code. I began by drawing circles, then connecting their center points, and then placing the circles in motion as coded animation. At that time, I was focused on *ideas* and not *images*—specifically, on dynamic systems and the ways a set of elements relate to each other within an imagined environment. I was working through questions about how to experience these systems and what might be an ideal (or interesting) way to engage with them. The ideas and code from this session later became the core of much of my subsequent work: including the foundation for the *Process* series of software, prints, and installations and the more recent *Process Compendium* works. *Pre-Process* pulls these origin points back into focus, develops them with what I’ve learned in the intervening years, and puts them on the blockchain to be archived. I consider the project a Rosetta Stone for my practice. It asks fundamental questions about the relationships between process and end result, including: Where is the aesthetic focus of a generative system? Is it deep within the code or within the picture the system creates? Ultimately, *Pre-Process* emphasizes experiencing the origin of the system and then transitioning with it as it seeks, but never finds, equilibrium. The system is built around Element 1, the first that I created for the *Process* series: *Element 1: Form 1 + Behavior 1 + Behavior 2 + Behavior 3 + Behavior 4 Form 1: Circle Behavior 1: Move in a straight line Behavior 2: Constrain to surface Behavior 3: Change direction while touching another Element Behavior 4: Move away from an overlapping Element* *Pre-Process* is the origin of a long journey that I’m still on. It continues to ask essential questions and to encourage me to explore possibilities. Through it, I came to realize that I was ultimately more a picture-maker than a conceptual artist, or, the way I like to think about it, I’m a “conceptual artist” with a small ‘c.’ I want the energy to be with the system (the ideas) *and* the surface (the picture) in equal measure. More directly, the work exists *between* the instructions, the performance and interpretation of the instructions, and the resulting images.
This artwork will “die” on 20 October 2052. Today I’m 50. Will I live to be 80? Will I outlive this artwork? Will this artwork outlive me? The original CENTURY project is autobiographical. Creating art and experiencing art is the core of my life, and CENTURY is my homage to 20th Century artists. It’s a synthesis of their ideas. CENTURY 2052 brings the endeavor to the 21st Century. It’s released as 50 unique artworks, one for each year since I was born. The artwork transitions from life to death at 6:44pm EST on October 20th 2052. This isn't a commercial or public release. It’s a gift to others who have shaped the world of art that I inhabit.
This artwork will “die” on 20 October 2052. Today I’m 50. Will I live to be 80? Will I outlive this artwork? Will this artwork outlive me? The original CENTURY project is autobiographical. Making art and experiencing art is my life’s work and CENTURY is my homage to the 20th Century. It’s a synthesis of ideas. CENTURY 2052 brings things to the 21st Century. It’s released as 50 unique artworks, one for each year I’m (hopefully) alive until the artwork expires at 6:44pm EST on October 20th 2052. This isn't a commercial or public release. It’s a gift to others who have shaped the world of art that I inhabit.
This artwork will “die” on 20 October 2052. Today I’m 50. Will I live to be 80? Will I outlive this artwork? Will this artwork outlive me? The original CENTURY project is autobiographical. Making art and experiencing art is my life’s work and CENTURY is my homage to the 20th Century. It’s a synthesis of ideas. CENTURY 2052 brings things to the 21st Century. It’s released as 80 unique artworks, one for each year I’m (hopefully) alive until the artwork expires at 6:44pm EST on October 20th 2052. This isn't a commercial or public release. It’s a gift to others who have shaped the world of art that I inhabit.
let seed = parseInt(tokenData.hash.slice(0, 16), 16); // ADD FOR LIVE NET let r; let maxdim; let fs = new Array(3); let bgcolor = 96; let bgdir = -1; let dead = false; let checkForDeath = true; let zombie = false; let now; let death; let numElements = 0; let strokeDim = 1; function setup() { createCanvas(windowWidth, windowHeight, WEBGL); colorMode(HSB, 360, 100, 100); pixelDensity(pixelDensity()); maxdim = max(width, height); if (maxdim >= 1440) { strokeDim = map(maxdim, 1440, 3160, 1.5, 4.0); } else { strokeDim = map(maxdim, 300, 1440, 0.2, 1.5); } numElements = 700; death = new Date(2052, 9, 20, 23, 44, 0, 0); strokeWeight(strokeDim); r = new RND(); now = Date.now(); imdead(); newFields(); if (dead) { instantDeath(); } } function draw() { if (checkForDeath && !zombie) { now = Date.now(); imdead(); } if (dead) { bgcolor -= 0.1; if (bgcolor < 10) { bgcolor = 10; } } background(0, 0, bgcolor); fs[0].display(); fs[1].display(); fs[2].display(); } function imdead() { let diff = now - death; if (diff > 0) { dead = true; } else { dead = false; } } function instantDeath() { bgcolor = 10; noLoop(); } function revive() { dead = false; zombie = true; bgcolor = 96; bgdir = -1; fs[0].revive(); fs[1].revive(); fs[2].revive(); } function keyPressed() { if (key == ' ') { bgcolor += 5 * bgdir; if (bgcolor >= 100 || bgcolor <= 0) { bgdir *= -1; } } else if (key == 'n' || key == 'N') { newFields(); } else if (key == 'd' || key == 'D') { print(now - death); } if (dead) { if (key == 'r' || key == 'R') { revive(); loop(); } } } function newFields() { let ang1 = r.rb(0, TWO_PI); let ang2 = ang1 + r.rb(-QUARTER_PI/3, QUARTER_PI/3); let ang3 = ang1 + r.rb(-QUARTER_PI/3, QUARTER_PI/3); let d1 = new FieldData(ang1); let d2 = new FieldData(ang2); let d3 = new FieldData(ang3); fs[0] = new Field(d1); fs[1] = new Field(d2); fs[2] = new Field(d3); } class FieldData { constructor(angle) { this.angle = angle; this.color1 = r.rb(0, 360); this.color2 = r.rb(0, 360); this.whichPalette = r.rb(0, 1); this.speed = r.rb(-0.0005, 0.0005); this.density = r.rb(0.1, 0.4); this.densityTest = new Array(numElements); for (let i = 0; i < this.densityTest.length; i++) { this.densityTest[i] = r.rb(0, 1); } } } class Element { constructor(_x1, _y1, _x2, _y2, _h, _s, _b, _sp) { this.x1 = _x1; this.y1 = _y1; this.x2 = _x2; this.y2 = _y2; this.off = 0.0; this.h = _h; this.s = _s; this.b = _b; this.supress = _sp; this.deadSaturation = this.s; this.startSaturation = this.s; this.jit = 1.0; if (dead) { this.jit = 0.0; this.deadSaturation = 0.0; } } revive() { this.jit = 1.0; this.deadSaturation = this.startSaturation; } jitter() { if (dead) { this.jit -= 0.001; if (this.jit <= 0) { this.jit = 0; } } this.off = r.rb(-this.jit, this.jit); } display() { if (dead) { this.deadSaturation -= 0.1; if (this.deadSaturation <= 0) { this.deadSaturation = 0; } } if (!this.supress) { if (dead) { stroke(this.h, this.deadSaturation, this.b); } else { stroke(this.h, this.s, this.b); } line(this.x1 + this.off, this.y1, this.x2 + this.off, this.y2); } } } class Field { constructor(fd) { this.num = numElements; this.angle = fd.angle; this.speed = fd.speed; this.density = fd.density; this.densityTest = fd.densityTest; this.whichPalette = fd.whichPalette; this.color1 = fd.color1; this.color2 = fd.color2; this.count = 0; this.elements = [this.num]; this.show = true; this.pnums = []; this.rndColor = 0; this.createColor(); let index = 0; for (let i = 0; i < numElements; i++) { let tx = map(i, 0, numElements - 1, -maxdim, maxdim); // ALT let h = this.pnums[index]; let s = this.pnums[index + 1]; let b = this.pnums[index + 2]; this.elements[i] = new Element( tx, -maxdim, tx, maxdim, h, s, b, this.show ); index += 3; if (this.densityTest[i] > this.density) { this.show = false; } else { this.show = true; } } } revive() { for (let i = 0; i < numElements; i++) { this.elements[i].revive(); } } display() { push(); rotate(this.angle); for (let i = 0; i < numElements; i++) { this.elements[i].jitter(); this.elements[i].display(); } if (!dead) { this.angle += this.speed; } pop(); } createColor() { if (this.whichPalette > 0.66) { this.rndColor = 1; } else { this.rndColor = 0; } this.createPalette(); } createPalette() { let index = 0; let start = this.color1; let microStart = this.color2; for (let x = 0; x < numElements; x++) { if (this.rndColor == 0) { let xx = map(x, 0, numElements, 0, 720); let h = map(x, 0, numElements, start, (start + xx) % 360); let s = map(x, 0, numElements, 30, 90); let b = 85; this.pnums[index] = h; this.pnums[index + 1] = s; this.pnums[index + 2] = b; index += 3; } else if (this.rndColor == 1) { let stop = start + map(x, 0, numElements, 0, 360); if (stop > 360) { stop = stop - 360; } this.pnums[index] = stop; this.pnums[index + 1] = map(x, 0, numElements, 30, 90); this.pnums[index + 2] = 85; index += 3; } } } } class RND { constructor() { this.useA = false; let sfc32 = function (uint128Hex) { let a = parseInt(uint128Hex.substr(0, 8), 16); let b = parseInt(uint128Hex.substr(8, 8), 16); let c = parseInt(uint128Hex.substr(16, 8), 16); let d = parseInt(uint128Hex.substr(24, 8), 16); return function () { a |= 0; b |= 0; c |= 0; d |= 0; let t = (((a + b) | 0) + d) | 0; d = (d + 1) | 0; a = b ^ (b >>> 9); b = (c + (c << 3)) | 0; c = (c << 21) | (c >>> 11); c = (c + t) | 0; return (t >>> 0) / 4294967296; }; }; this.prngA = new sfc32(tokenData.hash.substr(2, 32)); this.prngB = new sfc32(tokenData.hash.substr(34, 32)); for (let i = 0; i < 1e6; i += 2) { this.prngA(); this.prngB(); } } random_dec() { this.useA = !this.useA; return this.useA ? this.prngA() : this.prngB(); } rb(a, b) { return a + (b - a) * this.random_dec(); } }
let seed = parseInt(tokenData.hash.slice(0, 16), 16); // ADD FOR LIVE NET let r; let maxdim; let fs = new Array(3); let bgcolor = 96; let bgdir = -1; let dead = false; let checkForDeath = true; let zombie = false; let now; let death; let numElements = 0; let strokeDim = 1; function setup() { createCanvas(windowWidth, windowHeight, WEBGL); colorMode(HSB, 360, 100, 100); pixelDensity(pixelDensity()); maxdim = max(width, height); if (maxdim >= 1440) { strokeDim = map(maxdim, 1440, 3160, 1.5, 4.0); } else { strokeDim = map(maxdim, 300, 1440, 0.2, 1.5); } numElements = 700; death = new Date(2052, 9, 20, 23, 44, 0, 0); strokeWeight(strokeDim); r = new RND(); now = Date.now(); imdead(); newFields(); if (dead) { instantDeath(); } } function draw() { if (checkForDeath && !zombie) { now = Date.now(); imdead(); } if (dead) { bgcolor -= 0.1; if (bgcolor < 10) { bgcolor = 10; } } background(0, 0, bgcolor); fs[0].display(); fs[1].display(); fs[2].display(); } function imdead() { let diff = now - death; if (diff > 0) { dead = true; } else { dead = false; } } function instantDeath() { bgcolor = 10; noLoop(); } function revive() { dead = false; zombie = true; bgcolor = 96; bgdir = -1; fs[0].revive(); fs[1].revive(); fs[2].revive(); } function keyPressed() { if (key == ' ') { bgcolor += 5 * bgdir; if (bgcolor >= 100 || bgcolor <= 0) { bgdir *= -1; } } else if (key == 'n' || key == 'N') { newFields(); } else if (key == 'd' || key == 'D') { print(now - death); } if (dead) { if (key == 'r' || key == 'R') { revive(); loop(); } } } function newFields() { let ang1 = r.rb(0, TWO_PI); let ang2 = ang1 + r.rb(-QUARTER_PI/3, QUARTER_PI/3); let ang3 = ang1 + r.rb(-QUARTER_PI/3, QUARTER_PI/3); let d1 = new FieldData(ang1); let d2 = new FieldData(ang2); let d3 = new FieldData(ang3); fs[0] = new Field(d1); fs[1] = new Field(d2); fs[2] = new Field(d3); } class FieldData { constructor(angle) { this.angle = angle; this.color1 = r.rb(0, 360); this.color2 = r.rb(0, 360); this.whichPalette = r.rb(0, 1); this.speed = r.rb(-0.0005, 0.0005); this.density = r.rb(0.1, 0.4); this.densityTest = new Array(numElements); for (let i = 0; i < this.densityTest.length; i++) { this.densityTest[i] = r.rb(0, 1); } } } class Element { constructor(_x1, _y1, _x2, _y2, _h, _s, _b, _sp) { this.x1 = _x1; this.y1 = _y1; this.x2 = _x2; this.y2 = _y2; this.off = 0.0; this.h = _h; this.s = _s; this.b = _b; this.supress = _sp; this.deadSaturation = this.s; this.startSaturation = this.s; this.jit = 1.0; if (dead) { this.jit = 0.0; this.deadSaturation = 0.0; } } revive() { this.jit = 1.0; this.deadSaturation = this.startSaturation; } jitter() { if (dead) { this.jit -= 0.001; if (this.jit <= 0) { this.jit = 0; } } this.off = r.rb(-this.jit, this.jit); } display() { if (dead) { this.deadSaturation -= 0.1; if (this.deadSaturation <= 0) { this.deadSaturation = 0; } } if (!this.supress) { if (dead) { stroke(this.h, this.deadSaturation, this.b); } else { stroke(this.h, this.s, this.b); } line(this.x1 + this.off, this.y1, this.x2 + this.off, this.y2); } } } class Field { constructor(fd) { this.num = numElements; this.angle = fd.angle; this.speed = fd.speed; this.density = fd.density; this.densityTest = fd.densityTest; this.whichPalette = fd.whichPalette; this.color1 = fd.color1; this.color2 = fd.color2; this.count = 0; this.elements = [this.num]; this.show = true; this.pnums = []; this.rndColor = 0; this.createColor(); let index = 0; for (let i = 0; i < numElements; i++) { let tx = map(i, 0, numElements - 1, -maxdim, maxdim); // ALT let h = this.pnums[index]; let s = this.pnums[index + 1]; let b = this.pnums[index + 2]; this.elements[i] = new Element( tx, -maxdim, tx, maxdim, h, s, b, this.show ); index += 3; if (this.densityTest[i] > this.density) { this.show = false; } else { this.show = true; } } } revive() { for (let i = 0; i < numElements; i++) { this.elements[i].revive(); } } display() { push(); rotate(this.angle); for (let i = 0; i < numElements; i++) { this.elements[i].jitter(); this.elements[i].display(); } if (!dead) { this.angle += this.speed; } pop(); } createColor() { if (this.whichPalette > 0.66) { this.rndColor = 1; } else { this.rndColor = 0; } this.createPalette(); } createPalette() { let index = 0; let start = this.color1; let microStart = this.color2; for (let x = 0; x < numElements; x++) { if (this.rndColor == 0) { let xx = map(x, 0, numElements, 0, 720); let h = map(x, 0, numElements, start, (start + xx) % 360); let s = map(x, 0, numElements, 30, 90); let b = 85; this.pnums[index] = h; this.pnums[index + 1] = s; this.pnums[index + 2] = b; index += 3; } else if (this.rndColor == 1) { let stop = start + map(x, 0, numElements, 0, 360); if (stop > 360) { stop = stop - 360; } this.pnums[index] = stop; this.pnums[index + 1] = map(x, 0, numElements, 30, 90); this.pnums[index + 2] = 85; index += 3; } } } } class RND { constructor() { this.useA = false; let sfc32 = function (uint128Hex) { let a = parseInt(uint128Hex.substr(0, 8), 16); let b = parseInt(uint128Hex.substr(8, 8), 16); let c = parseInt(uint128Hex.substr(16, 8), 16); let d = parseInt(uint128Hex.substr(24, 8), 16); return function () { a |= 0; b |= 0; c |= 0; d |= 0; let t = (((a + b) | 0) + d) | 0; d = (d + 1) | 0; a = b ^ (b >>> 9); b = (c + (c << 3)) | 0; c = (c << 21) | (c >>> 11); c = (c + t) | 0; return (t >>> 0) / 4294967296; }; }; this.prngA = new sfc32(tokenData.hash.substr(2, 32)); this.prngB = new sfc32(tokenData.hash.substr(34, 32)); for (let i = 0; i < 1e6; i += 2) { this.prngA(); this.prngB(); } } random_dec() { this.useA = !this.useA; return this.useA ? this.prngA() : this.prngB(); } rb(a, b) { return a + (b - a) * this.random_dec(); } } // /** * Calculate features for the given token data * @param {Object} tokenData * @param {string} tokenData.tokenId - Unique identifier of the token on its contract. * @param {string} tokenData.hash - Unique hash generated upon minting the token. */ function calculateFeatures(tokenData) { const { tokenId, hash } = tokenData; let seed = parseInt(tokenData.hash.slice(0, 16), 16); //let mintNumber = parseInt(tokenData.tokenId) % 1000000; let r = new RND(tokenData); let TWO_PI = 6.2831853; let QUARTER_PI = 0.7853982; let ang1 = r.rb(0, TWO_PI); let ang2 = ang1 + r.rb(-QUARTER_PI/3, QUARTER_PI/3); let ang3 = ang1 + r.rb(-QUARTER_PI/3, QUARTER_PI/3); let radtodeg = 180.0 / Math.PI; ang1 = parseInt(ang1 * radtodeg); ang2 = parseInt(ang2 * radtodeg); ang3 = parseInt(ang3 * radtodeg); console.log("F1 Angle:" + ang1, ", F2 Angle:" + ang2, ", F3 Angle:" + ang3); const features = { "F1 Angle": ang1, "F2 Angle": ang2, "F3 Angle": ang3 }; return features; } class RND { constructor(tokenData) { this.useA = false; let sfc32 = function (uint128Hex) { let a = parseInt(uint128Hex.substr(0, 8), 16); let b = parseInt(uint128Hex.substr(8, 8), 16); let c = parseInt(uint128Hex.substr(16, 8), 16); let d = parseInt(uint128Hex.substr(24, 8), 16); return function () { a |= 0; b |= 0; c |= 0; d |= 0; let t = (((a + b) | 0) + d) | 0; d = (d + 1) | 0; a = b ^ (b >>> 9); b = (c + (c << 3)) | 0; c = (c << 21) | (c >>> 11); c = (c + t) | 0; return (t >>> 0) / 4294967296; }; }; this.prngA = new sfc32(tokenData.hash.substr(2, 32)); this.prngB = new sfc32(tokenData.hash.substr(34, 32)); for (let i = 0; i < 1e6; i += 2) { this.prngA(); this.prngB(); } } random_dec() { this.useA = !this.useA; return this.useA ? this.prngA() : this.prngB(); } rb(a, b) { return a + (b - a) * this.random_dec(); } }
This artwork will “die” on 20 October 2052. Today I’m 50. Will I live to be 80? Will I outlive this artwork? Will this artwork outlive me? The original CENTURY project is autobiographical. Making art and experiencing art is my life’s work and CENTURY is my homage to the 20th Century. It’s a synthesis of ideas. CENTURY 2052 brings things to the 21st Century. It’s released as 80 unique artworks, one for each year I’m (hopefully) alive until the artwork expires at 6:44pm EST on October 20th 2052. This isn't a commercial or public release. It’s a gift to others who have shaped the world of digital art that I inhabit.
Network C is a companion to REAS’s CENTURY. It’s a contemporary interpretation of Piet Mondrian’s Broadway Boogie Woogie, painted in New York City in 1942. Eighty years later, the most vibrant structures of the twenty-first century are dynamic data networks. If you’re viewing on an iOS device 15.4 or later, use Safari and turn off "WebGL via Metal." Setting here: Settings > Safari > Advanced > Experimental Features > WebGL via Metal
Network C is a companion to REAS’s CENTURY. It’s a contemporary interpretation of Piet Mondrian’s Broadway Boogie Woogie, painted in New York City in 1942. Eighty years later, the most vibrant structures of the twenty-first century are dynamic data networks. If you're viewing on an iOS device 15.4 or later, use Safari and turn off "WebGL via Metal." Setting here: Settings > Safari > Advanced > Experimental Features > WebGL via Metal
const headless = /HeadlessChrome/.test(window.navigator.userAgent); let nodes = []; let nodesToDraw = 1; let nodeOrder = []; // COLORS let cred = [1, 0.8, 0.76]; let cblue = [210, 0.72, 0.7]; let cyellow = [46, 0.82, 0.95]; let cwhite = [0, 0, 0.96]; let cback = [cred,cblue,cyellow,cwhite]; // CHANCE PARAMS let _cbackTop, _cbackBottom; let _rotate; let _weightFactor; let _metaWonk; let _mirrorChance; let _xydivs; let _mirror; let _rwonk; // FIXED PARAMS let maxUnits = 17; let minUnits = 9; let minWonk = 0.001; let maxWonk = 0.45; let speedScalar = 0.2; let maxDistance; let xygap; let bigdim; let sameWeight; let sameThinWeight; let newBackground = true; function setup() { createCanvas(window.innerWidth, window.innerHeight, WEBGL); pixelDensity(); colorMode(HSB, 360, 1, 1, 1); r = new RND(); defineNetwork(true); setAttributes('alpha', false); } function rollDice() { _cbackBottom = int(r.rb(0, cback.length)); _cbackTop = int(r.rb(0, cback.length)); _weightFactor = r.rb(0.066, 0.15); _metaWonk = r.rb(minWonk, maxWonk); _rotate = r.rb(0, TWO_PI); _mirrorChance = r.rb(0,1); _xydivs = int(r.rb(minUnits, maxUnits)); _rwonk = r.rb(0,1); } function draw() { if (newBackground) { defineBackground(); newBackground = false; } if (nodesToDraw < nodes.length-1 && frameCount % 10 == 0) { nodesToDraw++; } push(); rotate(_rotate); for (let i = 0; i < nodesToDraw; i++) { nodes[i].displayNetwork(); } pop(); } function keyPressed() { if (key == ' ') { defineNetwork(false); } } function windowResized() { if (!headless) { resizeCanvas(window.innerWidth, window.innerHeight); r = new RND(); defineNetwork(true); } } function defineBackground() { noStroke(); beginShape(); fill(cback[_cbackTop]) vertex(-width/2, -height/2); vertex(width/2, -height/2); fill(cback[_cbackBottom]); vertex(width/2, height/2); vertex(-width/2, height/2); endShape(); } function defineNetwork(bbb) { rollDice(); if (bbb) { newBackground = true; } nodesToDraw = 1; bigdim = max(width, height); xygap = bigdim/float(_xydivs); maxDistance = dist(0, 0, bigdim, bigdim); sameWeight = xygap * _weightFactor; sameThinWeight = map(bigdim, 1920, 3840, 1.0, 2.0); sameThinWeight = max(0.5, sameThinWeight); if (_mirrorChance > 0.5 && _weightFactor > 0.1) { _mirror = true; } else { _mirror = false; } nodes = [(_xydivs+7)*(_xydivs+7)]; nodeOrder = [nodes.length]; for (let i = 0; i < nodeOrder.length; i++) { nodeOrder[i] = i; } let nodeCount = 0; let wonk = minWonk; if (_rwonk > 0.75) { wonk = maxWonk; } else if (_rwonk > 0.10) { wonk = _metaWonk; } for (let x = -3; x <= _xydivs+3; x++) { for (let y = -3; y <= _xydivs+3; y++) { let xoff = 0; if (y % 2 == 0) { xoff = -xygap/2.0; } let xx = r.rb(-xygap*wonk, xygap*wonk); let yy = r.rb(-xygap*wonk, xygap*wonk); let nx = map(x*xygap, 0, bigdim, -bigdim/2-xygap/2, bigdim/2+xygap/2); let ny = map(y*xygap, 0, bigdim, -bigdim/2-xygap/2, bigdim/2+xygap/2); nodes[nodeCount] = new Node(nx + xoff, ny, xx, yy); nodeCount++; } } shuffle(nodes, true); buildConnections(); } function buildConnections() { for (let i = 0; i < nodes.length; i++) { nodes[i].setID(i); } for (let i = 0; i < nodes.length; i++) { nodes[i].buildNetwork(nodes); } } class Node { constructor(_x, _y, _xoff, _yoff) { this.x = _x + _xoff; this.y = _y + _yoff; this.newX = this.x; this.newY = this.y; this.centerDist = dist(0, 0, this.x, this.y); this.minimDist = dist(0, 0, xygap/2, xygap/2); this.totalConnections = 0; this.currentNet = 0; this.speed = []; this.weights = []; this.baseDist = dist(0, 0, xygap+(xygap/_xydivs), xygap+(xygap/_xydivs)); this.id = 0; this.otherNodes = []; this.connections = []; this.alphaLines = []; this.sending = []; this.c = [ cyellow, cblue, cred, cwhite ]; this.easing = 0.04; this.currentC = []; this.nextC = []; } setID(_id) { this.id = _id; } buildNetwork(_others) { let potentialConnections = [_others.length]; let count = 0; for (let i = 0; i < _others.length; i++) { if (i != this.id) { let d = dist(this.x, this.y, _others[i].x, _others[i].y); if (d < this.baseDist) { potentialConnections[count] = _others[i]; count++; this.totalConnections++; } } } this.connections = subset(potentialConnections, 0, count); this.alphaLines = [this.connections.length]; this.sending = [this.connections.length]; this.speed = [this.connections.length]; this.currentC = [this.connections.length]; this.nextC = [this.connections.length]; this.weights = [this.connections.length]; this.currentNet = int(r.rb(0, this.connections.length)); let sharedColor = this.c[int(r.rb(0, this.c.length))]; for (let i = 0; i < this.connections.length; i++) { this.alphaLines[i] = 1.0; this.sending[i] = true; let distance = dist(this.x, this.y, this.connections[i].x, this.connections[i].y); this.speed[i] = map(distance, this.baseDist, this.minimDist, 0.02, 0.05); this.currentC[i] = sharedColor; this.h = hue(this.currentC[i]); this.s = saturation(this.currentC[i]); this.b = brightness(this.currentC[i]); this.nextC[i] = this.c[int(r.rb(0, this.c.length))]; this.nh = hue(this.currentC[i]); this.ns = saturation(this.currentC[i]); this.nb = brightness(this.currentC[i]); this.weights[i] = sameWeight; } } displayNetwork() { if (this.connections.length > 0 && this.currentNet >= 0) { let i = this.currentNet; if (this.alphaLines[i] > 0.0) { this.x += (this.newX-this.x) * this.easing; this.y += (this.newY-this.y) * this.easing; let nextx = map(this.alphaLines[i], 0, 1, this.connections[i].x, this.x); let nexty = map(this.alphaLines[i], 0, 1, this.connections[i].y, this.y); let sw = map(this.alphaLines[i], 0, 1, this.weights[i], 1); if (abs(nextx-this.x) > 1.0) { if (_mirror) { push(); translate(xygap*0.25, xygap*0.25); strokeWeight(sameThinWeight); stroke(this.currentC[i][0], this.currentC[i][1], this.currentC[i][2], 0.01); line(this.x, this.y, nextx, nexty); pop(); } push(); translate(this.x, this.y); let angle = atan2(nexty-this.y, nextx-this.x); rotate(angle); let d = dist(this.x, this.y, nextx, nexty); let wide = sw * 0.5; let halfWide = wide; beginShape(); noStroke(); fill(this.currentC[i][0], this.currentC[i][1], this.currentC[i][2], 0.05); vertex(0, 0); vertex(halfWide, wide); fill(this.nextC[i][0], this.nextC[i][1], this.nextC[i][2], 0.05); vertex(d-halfWide, wide); vertex(d, 0); endShape(); pop(); } } else { this.alphaLines[i] = 1.0; this.currentC[i] = this.c[int(r.rb(0, this.c.length))]; this.nextC[i] = this.c[int(r.rb(0, this.c.length))]; this.currentNet = int(r.rb(0, this.alphaLines.length)); if (this.currentNet < 0) { this.currentNet = 0; } } this.alphaLines[i] -= this.speed[i] * speedScalar; } } } class RND { constructor() { this.useA = false; let sfc32 = function (uint128Hex) { let a = parseInt(uint128Hex.substr(0, 8), 16); let b = parseInt(uint128Hex.substr(8, 8), 16); let c = parseInt(uint128Hex.substr(16, 8), 16); let d = parseInt(uint128Hex.substr(24, 8), 16); return function () { a |= 0; b |= 0; c |= 0; d |= 0; let t = (((a + b) | 0) + d) | 0; d = (d + 1) | 0; a = b ^ (b >>> 9); b = (c + (c << 3)) | 0; c = (c << 21) | (c >>> 11); c = (c + t) | 0; return (t >>> 0) / 4294967296; }; }; this.prngA = new sfc32(tokenData.hash.substr(2, 32)); this.prngB = new sfc32(tokenData.hash.substr(34, 32)); for (let i = 0; i < 1e6; i += 2) { this.prngA(); this.prngB(); } } random_dec() { this.useA = !this.useA; return this.useA ? this.prngA() : this.prngB(); } rb(a, b) { return a + (b - a) * this.random_dec(); } }
Network C is a companion to REAS’s CENTURY. It’s a contemporary interpretation of Piet Mondrian’s Broadway Boogie Woogie, painted in New York City in 1942. Eighty years later, the most vibrant structures of the twenty-first century are dynamic data networks.
let nodes = []; let nodesToDraw = 1; let nodeOrder = []; let cred = [1, 0.8, 0.76]; let cblue = [210, 0.72, 0.7]; let cyellow = [46, 0.82, 0.95]; let cwhite = [0, 0, 0.96]; let cback = [cred,cblue,cyellow,cwhite]; let _cbackTop, _cbackBottom; let _rotate; let _weightFactor; let _metaWonk; let _mirrorChance; let _xydivs; let _mirror; let _rwonk; let maxUnits = 17; let minUnits = 9; let minWonk = 0.001; let maxWonk = 0.45; let speedScalar = 0.2; let maxDistance; let xygap; let bigdim; let sameWeight; let sameThinWeight; let newBackground = true; function setup() { createCanvas(window.innerWidth, window.innerHeight, WEBGL); pixelDensity(); colorMode(HSB, 360, 1, 1, 1); r = new RND(); defineNetwork(true); setAttributes('alpha', false); } function rollDice() { _cbackBottom = int(r.rb(0, cback.length)); _cbackTop = int(r.rb(0, cback.length)); _weightFactor = r.rb(0.066, 0.15); _metaWonk = r.rb(minWonk, maxWonk); _rotate = r.rb(0, TWO_PI); _mirrorChance = r.rb(0,1); _xydivs = int(r.rb(minUnits, maxUnits)); _rwonk = r.rb(0,1); } function draw() { if (newBackground) { defineBackground(); newBackground = false; } if (nodesToDraw < nodes.length-1 && frameCount % 10 == 0) { nodesToDraw++; } push(); rotate(_rotate); for (let i = 0; i < nodesToDraw; i++) { nodes[i].displayNetwork(); } pop(); } function keyPressed() { if (key == ' ') { defineNetwork(false); } } function windowResized() { resizeCanvas(window.innerWidth, window.innerHeight); r = new RND(); defineNetwork(true); } function defineBackground() { noStroke(); beginShape(); fill(cback[_cbackTop]) vertex(-width/2, -height/2); vertex(width/2, -height/2); fill(cback[_cbackBottom]); vertex(width/2, height/2); vertex(-width/2, height/2); endShape(); } function defineNetwork(bbb) { rollDice(); if (bbb) { newBackground = true; } nodesToDraw = 1; bigdim = max(width, height); xygap = bigdim/float(_xydivs); maxDistance = dist(0, 0, bigdim, bigdim); sameWeight = xygap * _weightFactor; sameThinWeight = map(bigdim, 1920, 3840, 1.0, 2.0); sameThinWeight = max(0.5, sameThinWeight); if (_mirrorChance > 0.5 && _weightFactor > 0.1) { _mirror = true; } else { _mirror = false; } nodes = [(_xydivs+7)*(_xydivs+7)]; nodeOrder = [nodes.length]; for (let i = 0; i < nodeOrder.length; i++) { nodeOrder[i] = i; } let nodeCount = 0; let wonk = minWonk; if (_rwonk > 0.75) { wonk = maxWonk; } else if (_rwonk > 0.10) { wonk = _metaWonk; } for (let x = -3; x <= _xydivs+3; x++) { for (let y = -3; y <= _xydivs+3; y++) { let xoff = 0; if (y % 2 == 0) { xoff = -xygap/2.0; } let xx = r.rb(-xygap*wonk, xygap*wonk); let yy = r.rb(-xygap*wonk, xygap*wonk); let nx = map(x*xygap, 0, bigdim, -bigdim/2-xygap/2, bigdim/2+xygap/2); let ny = map(y*xygap, 0, bigdim, -bigdim/2-xygap/2, bigdim/2+xygap/2); nodes[nodeCount] = new Node(nx + xoff, ny, xx, yy); nodeCount++; } } shuffle(nodes, true); buildConnections(); } function buildConnections() { for (let i = 0; i < nodes.length; i++) { nodes[i].setID(i); } for (let i = 0; i < nodes.length; i++) { nodes[i].buildNetwork(nodes); } } class Node { constructor(_x, _y, _xoff, _yoff) { this.x = _x + _xoff; this.y = _y + _yoff; this.newX = this.x; this.newY = this.y; this.centerDist = dist(0, 0, this.x, this.y); this.minimDist = dist(0, 0, xygap/2, xygap/2); this.totalConnections = 0; this.currentNet = 0; this.speed = []; this.weights = []; this.baseDist = dist(0, 0, xygap+(xygap/_xydivs), xygap+(xygap/_xydivs)); this.id = 0; this.otherNodes = []; this.connections = []; this.alphaLines = []; this.sending = []; this.c = [ cyellow, cblue, cred, cwhite ]; this.easing = 0.04; this.currentC = []; this.nextC = []; } setID(_id) { this.id = _id; } buildNetwork(_others) { let potentialConnections = [_others.length]; let count = 0; for (let i = 0; i < _others.length; i++) { if (i != this.id) { let d = dist(this.x, this.y, _others[i].x, _others[i].y); if (d < this.baseDist) { potentialConnections[count] = _others[i]; count++; this.totalConnections++; } } } this.connections = subset(potentialConnections, 0, count); this.alphaLines = [this.connections.length]; this.sending = [this.connections.length]; this.speed = [this.connections.length]; this.currentC = [this.connections.length]; this.nextC = [this.connections.length]; this.weights = [this.connections.length]; this.currentNet = int(r.rb(0, this.connections.length)); let sharedColor = this.c[int(r.rb(0, this.c.length))]; for (let i = 0; i < this.connections.length; i++) { this.alphaLines[i] = 1.0; this.sending[i] = true; let distance = dist(this.x, this.y, this.connections[i].x, this.connections[i].y); this.speed[i] = map(distance, this.baseDist, this.minimDist, 0.02, 0.05); this.currentC[i] = sharedColor; this.h = hue(this.currentC[i]); this.s = saturation(this.currentC[i]); this.b = brightness(this.currentC[i]); this.nextC[i] = this.c[int(r.rb(0, this.c.length))]; this.nh = hue(this.currentC[i]); this.ns = saturation(this.currentC[i]); this.nb = brightness(this.currentC[i]); this.weights[i] = sameWeight; } } displayNetwork() { if (this.connections.length > 0 && this.currentNet >= 0) { let i = this.currentNet; if (this.alphaLines[i] > 0.0) { this.x += (this.newX-this.x) * this.easing; this.y += (this.newY-this.y) * this.easing; let nextx = map(this.alphaLines[i], 0, 1, this.connections[i].x, this.x); let nexty = map(this.alphaLines[i], 0, 1, this.connections[i].y, this.y); let sw = map(this.alphaLines[i], 0, 1, this.weights[i], 1); if (abs(nextx-this.x) > 1.0) { if (_mirror) { push(); translate(xygap*0.25, xygap*0.25); strokeWeight(sameThinWeight); stroke(this.currentC[i][0], this.currentC[i][1], this.currentC[i][2], 0.01); line(this.x, this.y, nextx, nexty); pop(); } push(); translate(this.x, this.y); let angle = atan2(nexty-this.y, nextx-this.x); rotate(angle); let d = dist(this.x, this.y, nextx, nexty); let wide = sw * 0.5; let halfWide = wide; beginShape(); noStroke(); fill(this.currentC[i][0], this.currentC[i][1], this.currentC[i][2], 0.05); vertex(0, 0); vertex(halfWide, wide); fill(this.nextC[i][0], this.nextC[i][1], this.nextC[i][2], 0.05); vertex(d-halfWide, wide); vertex(d, 0); endShape(); pop(); } } else { this.alphaLines[i] = 1.0; this.currentC[i] = this.c[int(r.rb(0, this.c.length))]; this.nextC[i] = this.c[int(r.rb(0, this.c.length))]; this.currentNet = int(r.rb(0, this.alphaLines.length)); if (this.currentNet < 0) { this.currentNet = 0; } } this.alphaLines[i] -= this.speed[i] * speedScalar; } } } class RND { constructor() { this.useA = false; let sfc32 = function (uint128Hex) { let a = parseInt(uint128Hex.substr(0, 8), 16); let b = parseInt(uint128Hex.substr(8, 8), 16); let c = parseInt(uint128Hex.substr(16, 8), 16); let d = parseInt(uint128Hex.substr(24, 8), 16); return function () { a |= 0; b |= 0; c |= 0; d |= 0; let t = (((a + b) | 0) + d) | 0; d = (d + 1) | 0; a = b ^ (b >>> 9); b = (c + (c << 3)) | 0; c = (c << 21) | (c >>> 11); c = (c + t) | 0; return (t >>> 0) / 4294967296; }; }; this.prngA = new sfc32(tokenData.hash.substr(2, 32)); this.prngB = new sfc32(tokenData.hash.substr(34, 32)); for (let i = 0; i < 1e6; i += 2) { this.prngA(); this.prngB(); } } random_dec() { this.useA = !this.useA; return this.useA ? this.prngA() : this.prngB(); } rb(a, b) { return a + (b - a) * this.random_dec(); } }
“Phototaxis” is a simulated environment populated by simple machines. After Valentino Braitenberg’s 1984 book “Vehicles,” there are four kinds of machines with different wiring and behaviors: Explorers, Aggressors, Lovers, and Cowards. Each line charts the history of one machine’s movement. The core of this code was the foundation for my MicroImage series of works dating back to 2001. I’ve worked on it in fits and starts since then, and in 2021 it was further developed for Art Blocks. Press ‘P’ to play/pause, ‘B’ for the big bang, ‘1’–’5’ to change the magnification, and ‘L’ to reveal the lights’ locations.
“Phototaxis” is a simulated environment populated by simple machines. After Valentino Braitenberg’s 1984 book “Vehicles,” there are four kinds of machines with different wiring and behaviors: Explorers, Aggressors, Lovers, and Cowards. Each line charts the history of one machine’s movement. The core of this code was the foundation for my MicroImage series of works dating back to 2001. I’ve worked on it in fits and starts since then, and in 2021 it was further developed for Art Blocks. Press ‘P’ to play/pause, ‘B’ for the big bang, ‘1’–’5’ to change the magnification, and ‘L’ to reveal the lights’ locations. Dutch auction with 10Ξ starting price and 0.5Ξ resting price, reduced every 5 minutes as follows: 10 > 8 > 6 > 5 > 4 > 3.5 > 3 > 2.5 > 2 > 1.75 > 1.5 > 1.25 > 1 > .75 > .5
{"type":"p5js","aspectRatio":1,"animationLengthInSeconds":"0","interactive":"true","instructions":"‘P’ to play/pause|‘B’ for the big bang|‘1’–’5’ to change the magnification|‘L’ to reveal the lights’ locations","version":"1.0","curationStatus":"factory","license":"CC BY-NC 4.0"}
var seed=parseInt(tokenData.hash.slice(0,16),16);const PW=1e3,PH=1e3,PD=1414.2136,NUM_TYPES=4,MAX_LIGHTS=7,V2A=0,V2B=1,V3A=2,V3B=3;let _zoom,_num_lines,_max_speed,_num_lights,_linear_sensors,_nerves,_facade,_breadth,lights=new Array(MAX_LIGHTS),machines=[],pause=!1,bangTime=0,showLights=!1,white=[255,255,255],gray=[102,102,102],midgray=[127,127,127],black=[0,0,0],green1=[153,204,0],green2=[166,203,43],blue1=[61,168,201],blue2=[68,182,198],orange=[221,131,99],pink=[224,99,148],warmgray=[153,153,118],coolgray=[118,153,153],cs1=[white,green1,gray,green2,warmgray],cs2=[white,green1,pink,green2,gray],cs3=[white,blue1,gray,blue2,coolgray],cs4=[white,blue1,pink,blue2,gray],cs5=[white,blue1,orange,blue2,gray],cs6=[black,white,white,white,white],cs7=[midgray,white,white,white,white],csx=cs1;function setup(){createCanvas(window.innerWidth,window.innerHeight),pixelDensity(),colorMode(RGB,1),bang()}function draw(){translate(width/2,height/2);let s=max(width,height);scale(s/PW*_zoom);for(let s=0;s<machines.length;s++)machines[s].idle();for(let s=0;s<machines.length;s++)machines[s].display();if(showLights)for(let s=0;s<_num_lights;s++)lights[s].display();1e3===++bangTime&&(pause=!0,noLoop())}function bang(){r=new RND(seed),bangTime=0,pause=!1,showLights=!1,createWorld(),tuneMachines(),createFacade(),createMachines()}function createWorld(){let s=r.rb(0,1);_zoom=s>.9?.66:s>.8?2:1;for(let s=0;s<MAX_LIGHTS;s++)lights[s]=new L(r.rb(-PW/2,PW/2),r.rb(-PH/2,PH/2),10);_num_lights=2+int(r.rb(0,MAX_LIGHTS-1)),print(_num_lights);let e=r.rb(0,1);_num_lines=e>.9?50:e>.85?800:e>.75?200:400}function tuneMachines(){let s=r.rb(0,1);_breadth=s>.8?35:50;let e=r.rb(0,1);_nerves=e>.9?10:e>.8?5:0;let t=r.rb(0,1);_linear_sensors=t>.9;let i=r.rb(0,1);_max_speed=i>.8?4:i>.5?8:12}function createFacade(){let s=r.rb(0,1);csx=s>.9?cs7:s>.6?cs6:s>.5?cs5:s>.4?cs4:s>.3?cs3:s>.15?cs2:cs1,createBackground()}function createBackground(){bg=color(csx[0][0]/255,csx[0][1]/255,csx[0][2]/255),background(bg),strokeCap(SQUARE)}function createMachines(){let s=.5;_nerves<1&&(_num_lines>500?s=.25:_num_lines>300&&(s=.375)),machines=new Array(_num_lines);for(let e=0;e<machines.length;e++){let t=e%NUM_TYPES;machines[e]=new M(r.rb(-PW/2,PW/2),r.rb(-PH/2,PH/2),t,csx[t+1][0]/255,csx[t+1][1]/255,csx[t+1][2]/255,s)}}function keyTyped(){return"p"===key||"P"===key?(pause?loop():noLoop(),pause=!pause):"b"===key||"B"===key?(bang(),loop(),print("bang")):"1"===key?(bang(),loop(),_zoom=.66):"2"===key?(bang(),loop(),_zoom=1):"3"===key?(bang(),loop(),_zoom=2):"4"===key?(bang(),loop(),_zoom=4):"5"===key?(bang(),loop(),_zoom=8):"l"!=key&&"L"!=key||(showLights=!showLights,pause&&redraw()),!1}class L{constructor(s,e,t){this.x=s,this.y=e,this.r=t}display(){fill(1,.7,0),noStroke(),ellipse(this.x,this.y,this.r,this.r)}}class M{constructor(s,e,t,i,h,o,n){this.line_x=this.p_x=s,this.line_y=this.p_y=e,this.species=t,this.ocolor=new Array(3),this.dcolor=new Array(3),this.dcolorNew=new Array(3),this.ocolor[0]=this.dcolor[0]=this.dcolorNew[0]=i,this.ocolor[1]=this.dcolor[1]=this.dcolorNew[1]=h,this.ocolor[2]=this.dcolor[2]=this.dcolorNew[2]=o,this.alpha=n,this.lineRotatenew=0,this.lineRotate=0,this.fade=1,this.death=!1,this.turn_speed=8,this.speed=0,this.expanse=r.rb(0,45)+5,this.line_rotate=r.rb(0,360)}hump(s){return s=1-(s=2*(s-.5))*s}idle(){this.lineRotatenew=radians(this.line_rotate);for(let s=0;s<_num_lights;s++)this.light_x=lights[s].x,this.light_y=lights[s].y,this.lsox=cos(this.lineRotatenew+PI/5)*_breadth,this.lsoy=sin(this.lineRotatenew+PI/5)*_breadth,this.left_sensor_x=this.line_x+this.lsox,this.left_sensor_y=this.line_y+this.lsoy,this.rsox=cos(this.lineRotatenew-PI/5)*_breadth,this.rsoy=sin(this.lineRotatenew-PI/5)*_breadth,this.right_sensor_x=this.line_x+this.rsox,this.right_sensor_y=this.line_y+this.rsoy,this.ldx=this.light_x-this.left_sensor_x,this.ldy=this.light_y-this.left_sensor_y,this.ld=sqrt(this.ldx*this.ldx+this.ldy*this.ldy),this.rdx=this.light_x-this.right_sensor_x,this.rdy=this.light_y-this.right_sensor_y,this.rd=sqrt(this.rdx*this.rdx+this.rdy*this.rdy),this.norm_sensor_left=this.ld/PD,this.norm_sensor_right=this.rd/PD,0==_linear_sensors&&(this.norm_sensor_right=this.hump(this.norm_sensor_right),this.norm_sensor_left=this.hump(this.norm_sensor_left)),this.norm_sensor_average=(this.norm_sensor_left+this.norm_sensor_right)/2,this.species==V2A?(this.speed+=_max_speed-_max_speed*this.norm_sensor_average,this.speed/=2+this.expanse/25,this.line_rotate+=this.ld/this.turn_speed*(1-this.norm_sensor_left),this.line_rotate-=this.rd/this.turn_speed*(1-this.norm_sensor_right)):this.species==V2B?(this.speed+=_max_speed-_max_speed*this.norm_sensor_average,this.speed/=2+this.expanse/25,this.line_rotate+=this.rd/this.turn_speed*(1-this.norm_sensor_right),this.line_rotate-=this.ld/this.turn_speed*(1-this.norm_sensor_left)):this.species==V3A?(this.speed+=_max_speed*this.norm_sensor_average,this.speed/=2+this.expanse/25,this.line_rotate-=this.ld/this.turn_speed*(1-this.norm_sensor_left),this.line_rotate+=this.rd/this.turn_speed*(1-this.norm_sensor_right)):this.species==V3B&&(this.speed+=_max_speed*this.norm_sensor_average,this.speed/=2+this.expanse/25,this.line_rotate-=this.rd/this.turn_speed*(1-this.norm_sensor_right),this.line_rotate+=this.ld/this.turn_speed*(1-this.norm_sensor_left)),this.line_rotate+=r.rb(-_nerves,_nerves);this.dcolorNew[0]=this.ocolor[0]*this.speed*map(_max_speed,4,12,.45,.15),this.dcolorNew[1]=this.ocolor[1]*this.speed*map(_max_speed,4,12,.45,.15),this.dcolorNew[2]=this.ocolor[2]*this.speed*map(_max_speed,4,12,.45,.15),this.dcolorNew[0]=constrain(this.dcolorNew[0],0,this.ocolor[0]),this.dcolorNew[1]=constrain(this.dcolorNew[1],0,this.ocolor[1]),this.dcolorNew[2]=constrain(this.dcolorNew[2],0,this.ocolor[2]),this.speed<.4&&(this.speed=.4),this.dcolor[0]-=(this.dcolor[0]-this.dcolorNew[0])/10,this.dcolor[1]-=(this.dcolor[1]-this.dcolorNew[1])/10,this.dcolor[2]-=(this.dcolor[2]-this.dcolorNew[2])/10,this.lineRotatenew=this.line_rotate/180*PI,this.lineRotatenew<PI/2?(this.yd=sin(this.lineRotatenew)*this.speed,this.xd=cos(this.lineRotatenew)*this.speed,this.line_x+=this.xd,this.line_y+=this.yd):this.lineRotatenew<PI?(this.lineRotatenew-=PI/2,this.yd=cos(this.lineRotatenew)*this.speed,this.xd=sin(this.lineRotatenew)*this.speed,this.line_x-=this.xd,this.line_y+=this.yd):this.lineRotatenew<PI+PI/2?(this.lineRotatenew-=PI,this.yd=sin(this.lineRotatenew)*this.speed,this.xd=cos(this.lineRotatenew)*this.speed,this.line_x-=this.xd,this.line_y-=this.yd):(this.lineRotatenew-=PI+PI/2,this.yd=cos(this.lineRotatenew)*this.speed,this.xd=sin(this.lineRotatenew)*this.speed,this.line_x+=this.xd,this.line_y-=this.yd),this.death&&(this.fade-=.01,fade<0&&(this.fade=1,this.death=!1,this.rebirth()))}kill(){this.death=!0}rebirth(){this.line_x=r.rb(-PW/2,PW/2),this.line_y=r.rb(-PH/2,PH/2),this.p_x=this.line_x,this.p_y=this.line_y}display(){strokeWeight(1),stroke(this.dcolor[0],this.dcolor[1],this.dcolor[2],this.alpha*this.fade),line(this.line_x,this.line_y,this.p_x,this.p_y),this.nextPoint()}nextPoint(){this.p_x=this.line_x,this.p_y=this.line_y}}class RND{constructor(s){this.seed=s}random_dec(){return this.seed^=this.seed<<13,this.seed^=this.seed>>17,this.seed^=this.seed<<5,(this.seed<0?1+~this.seed:this.seed)%1e3/1e3}rb(s,e){return s+(e-s)*this.random_dec()}}
{"type":"p5js","aspectRatio":"1","animationLengthInSeconds":"0","interactive":"true","instructions":"‘P’ to play/pause|‘B’ for the big bang|‘1’–’5’ to change the magnification|‘L’ to reveal the lights’ locations","version":"1.0"}
“Phototaxis” is a simulated environment populated by simple machines. After Valentino Braitenberg’s 1984 book “Vehicles,” there are four kinds of machines with different wiring and behaviors: Explorers, Aggressors, Lovers, and Cowards. Each line charts the history of one machine’s movement. The core of this code was the foundation for my MicroImage series of works dating back to 2001. I’ve worked on it in fits and starts since then, and in 2021 it was further developed for Art Blocks. Press ‘P’ to play/pause, ‘B’ for the big bang, ‘1’–’5’ to change the magnification, and ‘L’ to reveal the lights’ locations.
var seed = parseInt(tokenData.hash.slice(0, 16), 16); let ellipses = false; let janky = true; let randomized = true; let moreLines = false; let maxSlices = 50; let slices = [maxSlices]; let sliceOrder = []; let numSlices = 0; let smallestSlice, largestSlice; let colorsA = ['#0771a6', '#ede8dc', '#d4cfc3', '#333d47']; let lineColorsA = ['#ede8dc', '#d4cfc3', '#eba490', '#333d47', '#0771a6', '#f78a6b']; let colorsB = ['#ad3914', '#ede8dc', '#d4cfc3', '#29333d']; let lineColorsB = ['#ede8dc', '#d4cfc3', '#eba490', '#29333d', '#ad3914', '#f78a6b']; let colorsC = ['#333333', '#555555']; let lineColorsC = ['#ececec', '#333333', '#666666', '#999999']; let colorsD = ['#2f2f30', '#DB909F', '#f0ece2']; let lineColorsD = ['#2f2f30', '#DB909F', '#f0ece2']; let colors = []; let lineColors = []; let bgcolor; let lineColorOptions = 0; let numQuads; let ells = [2]; let ellipseAlpha = 255; let quads; let dim = 0; let r; let gg; function setup() { dim = Math.min(window.innerWidth, window.innerHeight); createCanvas(dim, dim, WEBGL); pixelDensity(); r = new RND(seed); smallestSlice = dim / 50; largestSlice = dim / 4; gg = createGraphics(dim, dim); compose(); } function draw() { background(bgcolor); translate(-dim / 2, -dim / 2); updateBuffer(); sliceBuffer(); disc(); } function keyPressed() { if (key == '1') { defineSlices(); randomSequence(); } if (key == '2') { orderedSequence(); } } function disc() { fill(255); noStroke(); translate(dim / 2, dim / 2); disc4(); rotate(HALF_PI); disc4(); rotate(HALF_PI); disc4(); rotate(HALF_PI); disc4(); } function disc4() { beginShape(); vertex(-dim / 2, -dim / 2); vertex(0, -dim / 2); let bdim = -dim / 2 * 0.552284749831; bezierVertex(bdim, -dim / 2, -dim / 2, bdim, -dim / 2, 0); endShape(); } function compose() { let rc = r.rb(0, 1); if (rc > 0.99) { colors = colorsD; lineColors = lineColorsD; } else if (rc > 0.95) { colors = colorsC; lineColors = lineColorsC; } else if (rc > 0.63) { colors = colorsB; lineColors = lineColorsB; } else { colors = colorsA; lineColors = lineColorsA; } lineColorOptions = int(r.rb(2, lineColors.length + 1)); if (r.rb(0, 1) > 0.1) { ellipses = true; } else { ellipses = false; } if (r.rb(0, 1) > 0.5 && colors != colorsB && colors != colorsD) { ellipseAlpha = r.rb(204, 240); } else { ellipseAlpha = 255; } if (r.rb(0, 1) > 0.95) { moreLines = true; } else { moreLines = false; } if (r.rb(0, 1) > 0.7) { janky = true; } else { janky = false; } if (colors == colorsC) { bgcolor = '#000000'; } else { bgcolor = colors[int(r.rb(0, colors.length))]; } if (ellipses) { let edia1 = r.rb(dim * 0.5, dim * 1.75); let ta = colors.slice(); removeArrayElement(ta, bgcolor); let ec1 = ta[int(r.rb(0, ta.length))]; let ry1 = r.rb(0, dim * 0.4); if (r.rb(0, 1) > 0.5) { ry1 = dim - ry1; } ells[0] = new RE(ec1, edia1, 0.57595867, ry1); let edia2 = r.rb(dim * 0.33, dim * 1.0); let ec2 = colors[int(r.rb(0, colors.length))]; let ry2 = r.rb(0, dim * 0.4); if (r.rb(0, 1) > 0.5) { ry2 = dim - ry2; } ells[1] = new RE(ec2, edia2, -0.57595867, ry2); } numQuads = 8 + int(pow(r.rb(1, 0), 3) * 12); if (moreLines) { numQuads += 32; } quads = [numQuads]; for (let i = 0; i < numQuads; i++) { quads[i] = new RQ(); } defineSlices(); if (r.rb(0, 1) > 0.02) { randomSequence(); } else { orderedSequence(); } } function defineSlices() { numSlices = 0; let currentSlice = 0; for (let x = 0; x < dim; x += slices[currentSlice - 1].w) { let currentCut = smallestSlice + (pow(r.rb(0, 1), 3) * largestSlice); if (x + currentCut + smallestSlice > dim) { currentCut = dim - x; } slices[currentSlice] = new RS(x, currentCut); currentSlice++; numSlices++; } } function randomSequence() { randomized = true; sliceOrder = []; for (let i = 0; i < numSlices; i++) { append(sliceOrder, i); } sliceOrder = scrambleArray(sliceOrder); } function orderedSequence() { randomized = false; sliceOrder = []; for (let i = 0; i < numSlices; i++) { append(sliceOrder, i); } } function updateBuffer() { gg.clear(); if (ellipses) { for (let i = 0; i < ells.length; i++) { ells[i].display(); } } for (let i = 0; i < numQuads; i++) { quads[i].move(); quads[i].display(); } } function sliceBuffer() { let x = 0; for (let i = 0; i < numSlices; i++) { let which = sliceOrder[i]; if (i == 0 || i == numSlices - 1) { slices[which].display(x); } else { if (janky == true && randomized == true) { slices[which].display(x + slices[which].xoffset); } else { slices[which].display(x); } } x += slices[which].w; } } class RQ { constructor() { this.th = r.rb(0, 1); this.y1 = r.rb(-dim / 8, dim + dim / 8); this.quadColor = lineColors[int(r.rb(0, lineColorOptions))]; this.y2 = this.y1; this.y1off = r.rb(0, 1); this.y2off = r.rb(0, 1); this.angle = r.rb(0, TWO_PI); this.speed = r.rb(0.01, 0.01); this.scale = r.rb(dim / 100, dim / 25); this.my = 0.0; if (r.rb(0, 1) > 0.5) { this.y2 = this.y1 + (r.rb(dim / 16, dim) * -1); } else { this.y2 = this.y1 + r.rb(dim / 16, dim); } if (this.th > 0.7) { this.y1off = 2 + pow(this.y1off, 4) * dim / 50; this.y2off = 2 + pow(this.y2off, 4) * dim / 50; } else if (this.th > 0.5) { this.y1off = 2 + pow(this.y1off, 3) * dim / 70; this.y2off = 2 + pow(this.y2off, 3) * dim / 70; } else { this.y1off = 2 + pow(this.y1off, 5) * dim / 80; this.y2off = 2 + pow(this.y2off, 5) * dim / 80; } } move() { this.my = cos(this.angle) * this.scale; this.angle = this.angle + this.speed; } display() { gg.noStroke(); gg.fill(this.quadColor); gg.beginShape(); gg.vertex(0, this.y1 + this.my); gg.vertex(dim, this.y2 - this.my / 2); gg.vertex(dim, this.y2 + this.y2off - this.my / 2); gg.vertex(0, this.y1 + this.y1off + this.my); gg.endShape(); } } class RE { constructor(cin, din, ain, yin) { this.x = r.rb(0, dim); this.y = yin; this.edia = din; this.angle = ain; this.rc = cin; this.ellcolor = color(red(this.rc), green(this.rc), blue(this.rc), ellipseAlpha); } display() { gg.noStroke(); gg.push(); gg.fill(this.ellcolor); gg.translate(this.x, this.y); gg.rotate(this.angle); gg.ellipse(0, 0, this.edia, this.edia * 0.66); gg.pop(); } } class RS { constructor(xin, win) { this.tx = xin; this.w = win; this.xoffset = int(r.rb(-dim / 100, dim / 100)); } display(x) { noStroke(); beginShape(); texture(gg); vertex(x, 0, this.tx, 0); vertex(x + this.w, 0, this.tx + this.w, 0); vertex(x + this.w, dim, this.tx + this.w, dim); vertex(x, dim, this.tx, dim); endShape(); } } class RND { constructor(seed) { this.seed = seed } rd() { this.seed ^= this.seed << 13 this.seed ^= this.seed >> 17 this.seed ^= this.seed << 5 return ((this.seed < 0 ? ~this.seed + 1 : this.seed) % 1000) / 1000 } rb(a, b) { return a + (b - a) * this.rd() } } function removeArrayElement(array, elem) { var index = array.indexOf(elem); if (index > -1) { array.splice(index, 1); } } function scrambleArray(arr) { let newarr = []; let length = arr.length; for (let i = 0; i < length; i++) { let choice = floor(map(r.rb(0, 1), 0, 1, 0, arr.length)); newarr.push(arr[choice]); arr.splice(choice, 1); } return (newarr); }
CENTURY is my homage to paintings and drawings from the twentieth century and the countless hours I’ve spent looking at them. The references span the origins of concrete and non-objective art to color-field painting and minimalism. The strongest direct reference is a series of pictures created by Ellsworth Kelly in the 1950s where he cut his paintings into pieces and reassembled them in different orders. CENTURY creates a distinct picture for each unique transaction hash, and you can “cut” and “reassemble” it in different ways by pressing ‘1’ on your keyboard. Press ‘2’ to put the slices in the original order. These are landscapes; they look best large and in motion running as live code.