Mercurial
comparison graphics/index.js @ 173:827c6ac504cd hg-web
Merged in default here.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 19 Jan 2026 18:59:10 -0800 |
| parents | 8ceb5d3c6bdd |
| children |
comparison
equal
deleted
inserted
replaced
| 151:c033667da5f9 | 173:827c6ac504cd |
|---|---|
| 1 const SCREEN_WIDTH = 600; | 1 const SCREEN_WIDTH = 600; |
| 2 const SCREEN_HEIGHT = 600; | 2 const SCREEN_HEIGHT = 600; |
| 3 const PIXEL_SIZE = 10; | 3 const PIXEL_SIZE = 1; |
| 4 const FRAME = 60 | 4 const FRAME = 60 |
| 5 | 5 |
| 6 game.width = SCREEN_WIDTH; | 6 game.width = SCREEN_WIDTH; |
| 7 game.height = SCREEN_HEIGHT; | 7 game.height = SCREEN_HEIGHT; |
| 8 | 8 |
| 12 ctx.fillStyle = "black"; | 12 ctx.fillStyle = "black"; |
| 13 ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); | 13 ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); |
| 14 } | 14 } |
| 15 | 15 |
| 16 function drawPixel({x, y}) { | 16 function drawPixel({x, y}) { |
| 17 ctx.fillStyle = "blue"; | 17 ctx.fillStyle = "pink"; |
| 18 ctx.fillRect(x * SCREEN_WIDTH, y * SCREEN_HEIGHT, PIXEL_SIZE, PIXEL_SIZE); | 18 ctx.fillRect(x * SCREEN_WIDTH, y * SCREEN_HEIGHT, PIXEL_SIZE, PIXEL_SIZE); |
| 19 } | 19 } |
| 20 | 20 |
| 21 function normazlie({x, y}) { | 21 function normalize({x, y}) { |
| 22 return { | 22 return { |
| 23 x: ((x + 1) / 2), | 23 x: ((x + 1) / 2), |
| 24 y: (1 - ((y + 1) / 2)), | 24 y: (1 - ((y + 1) / 2)), |
| 25 } | 25 } |
| 26 } | 26 } |
| 31 y: y/z | 31 y: y/z |
| 32 } | 32 } |
| 33 } | 33 } |
| 34 | 34 |
| 35 function drawLine({x, y}, {x2, y2}) { | 35 function drawLine({x, y}, {x2, y2}) { |
| 36 console.log("Hello", x,y, x2,y2); | |
| 37 ctx.beginPath(); | 36 ctx.beginPath(); |
| 38 ctx.moveTo(x * SCREEN_WIDTH, y * SCREEN_HEIGHT); | 37 ctx.moveTo(x * SCREEN_WIDTH, y * SCREEN_HEIGHT); |
| 39 ctx.lineTo(x2 * SCREEN_WIDTH, y2* SCREEN_HEIGHT); | 38 ctx.lineTo(x2 * SCREEN_WIDTH, y2* SCREEN_HEIGHT); |
| 40 ctx.lineWidth = 3; | 39 ctx.lineWidth = 3; |
| 41 ctx.strokeStyle = "red"; | 40 ctx.strokeStyle = "red"; |
| 42 ctx.stroke(); | 41 ctx.stroke(); |
| 43 } | 42 } |
| 44 | 43 |
| 45 const test = 0; | 44 |
| 46 const points = [ | 45 // function generateHeartPoints(resolution = 0.008) { |
| 47 {x: -0.25, y: 0.25, z: 0.5 + test}, | 46 // const points = []; |
| 48 {x: -0.25, y: -0.25, z: 0.5 + test}, | 47 // // Nordstrom needs a slightly higher threshold because the |
| 49 {x: 0.25, y: -0.25, z: 0.5 + test}, | 48 // // gradient of the cubic is steeper in some areas. |
| 50 {x: 0.25, y: 0.25, z: 0.5 + test}, | 49 // const threshold = 0.0001; |
| 51 | 50 // |
| 52 {x: -0.25, y: 0.25, z: -0.5 + test}, | 51 // for (let x = -1.5; x <= 1.5; x += resolution) { |
| 53 {x: -0.25, y: -0.25, z: -0.5 + test}, | 52 // for (let y = -1.5; y <= 1.5; y += resolution) { |
| 54 {x: 0.25, y: -0.25, z: -0.5 + test}, | 53 // for (let z = -1.5; z <= 1.5; z += resolution) { |
| 55 {x: 0.25, y: 0.25, z: -0.5 + test}, | 54 // |
| 56 ] | 55 // const x2 = x * x; |
| 57 const vortexs = [ | 56 // const y2 = y * y; |
| 58 [0, 1, 2, 3], | 57 // const z2 = z * z; |
| 59 [4, 5, 6, 7], | 58 // const z3 = z2 * z; |
| 60 [0, 4], | 59 // |
| 61 [1, 5], | 60 // // Nordstrom Equation: (2x² + y² + z² - 1)³ - (1/10)x²z³ - y²z³ = 0 |
| 62 [2, 6], | 61 // const inner = (2 * x2) + y2 + z2 - 1; |
| 63 [3, 7], | 62 // const value = Math.pow(inner, 3) - (0.1 * x2 * z3) - (y2 * z3); |
| 64 ] | 63 // |
| 64 // if (Math.abs(value) < threshold) { | |
| 65 // // Keep the jitter for that organic "floating dust" look | |
| 66 // points.push({ | |
| 67 // x: x + (Math.random() - 0.5) * resolution, | |
| 68 // y: y + (Math.random() - 0.5) * resolution, | |
| 69 // z: z + (Math.random() - 0.5) * resolution | |
| 70 // }); | |
| 71 // } | |
| 72 // } | |
| 73 // } | |
| 74 // } | |
| 75 // return points; | |
| 76 // } | |
| 77 | |
| 78 function generateHeartPoints(resolution = 0.01) { | |
| 79 const points = []; | |
| 80 const threshold = 0.001; | |
| 81 | |
| 82 for (let x = -1.5; x <= 1.5; x += resolution) { | |
| 83 for (let y = -1.5; y <= 1.5; y += resolution) { | |
| 84 for (let z = -1.5; z <= 1.5; z += resolution) { | |
| 85 | |
| 86 const x2 = x * x; | |
| 87 const y2 = y * y; | |
| 88 const z2 = z * z; | |
| 89 const z3 = z2 * z; | |
| 90 | |
| 91 const inner = x2 + (9/4) * y2 + z2 - 1; | |
| 92 const value = Math.pow(inner, 3) - x2 * z3 - (9/80) * y2 * z3; | |
| 93 | |
| 94 if (Math.abs(value) < threshold) { | |
| 95 points.push({ | |
| 96 x: x + (Math.random() - 0.5) * 0.01, | |
| 97 y: y + (Math.random() - 0.5) * 0.01, | |
| 98 z: z + (Math.random() - 0.5) * 0.01 | |
| 99 }); | |
| 100 } | |
| 101 } | |
| 102 } | |
| 103 } | |
| 104 return points; | |
| 105 } | |
| 106 | |
| 107 let points = generateHeartPoints(); | |
| 108 const intial_start_z = 2; | |
| 109 points = points.map(point => ({...point, x: point.x + intial_start_z})); | |
| 110 // const points = [ | |
| 111 // {x: -0.25, y: 0.25, z: 0.25}, | |
| 112 // {x: -0.25, y: -0.25, z: 0.25}, | |
| 113 // {x: 0.25, y: -0.25, z: 0.25}, | |
| 114 // {x: 0.25, y: 0.25, z: 0.25}, | |
| 115 // | |
| 116 // {x: -0.25, y: 0.25, z: -0.25}, | |
| 117 // {x: -0.25, y: -0.25, z: -0.25}, | |
| 118 // {x: 0.25, y: -0.25, z: -0.25}, | |
| 119 // {x: 0.25, y: 0.25, z: -0.25}, | |
| 120 // ] | |
| 121 // const vortexs = [ | |
| 122 // [0, 1, 2, 3], | |
| 123 // [4, 5, 6, 7], | |
| 124 // [0, 4], | |
| 125 // [1, 5], | |
| 126 // [2, 6], | |
| 127 // [3, 7], | |
| 128 // ] | |
| 129 | |
| 130 function rotate_xy({x, y, z}, angle) { | |
| 131 return { | |
| 132 x: x * Math.cos(angle) - y * Math.sin(angle), | |
| 133 y: x * Math.sin(angle) + y * Math.cos(angle), | |
| 134 z: z | |
| 135 }; | |
| 136 } | |
| 65 | 137 |
| 66 function rotate_xz({x,y,z}, angle) { | 138 function rotate_xz({x,y,z}, angle) { |
| 67 return { | 139 return { |
| 68 x: x * Math.cos(angle) - z*Math.sin(angle), | 140 x: x * Math.cos(angle) - z*Math.sin(angle), |
| 69 y: y, | 141 y: y, |
| 70 z: x * Math.sin(angle) + z*Math.cos(angle), | 142 z: x * Math.sin(angle) + z*Math.cos(angle), |
| 71 } | 143 } |
| 72 } | 144 } |
| 73 | 145 |
| 146 function rotate_yz({x, y, z}, angle) { | |
| 147 return { | |
| 148 x: x, | |
| 149 y: y * Math.sin(angle) + z * Math.cos(angle), | |
| 150 z: y * Math.cos(angle) - z * Math.sin(angle) | |
| 151 }; | |
| 152 } | |
| 153 | |
| 74 function move_z(point, dz) { | 154 function move_z(point, dz) { |
| 75 return {...point, z: point.z + dz} | 155 return {...point, z: point.z + dz} |
| 156 } | |
| 157 | |
| 158 function move_y(point, dy) { | |
| 159 return {...point, y: point.y + dy} | |
| 76 } | 160 } |
| 77 | 161 |
| 78 let dz = 0; | 162 let dz = 0; |
| 79 let dt = 1/FRAME; | 163 let dt = 1/FRAME; |
| 80 let angle = 0; | 164 let angle = 0; |
| 165 const fontPoint = {x: SCREEN_WIDTH / 2, y: SCREEN_HEIGHT * 0.3}; | |
| 81 | 166 |
| 82 function drawAnimation() { | 167 function drawAnimation() { |
| 83 drawBackground(); | 168 drawBackground(); |
| 84 dz += 1 * dt; | 169 dz -= 1 * dt; |
| 85 // angle += 2*Math.PI*dt; | 170 angle += 2*Math.PI*dt*0.2; |
| 86 angle = 0; | 171 |
| 87 for (var vortex of vortexs) | 172 // Texts... |
| 173 ctx.font = "60px serif"; | |
| 174 ctx.textAlign = "center"; // Ensures the point is the middle of the text | |
| 175 ctx.textBaseline = "middle"; | |
| 176 ctx.fillStyle = "pink"; | |
| 177 ctx.fillText("Heart!", fontPoint.x, fontPoint.y); | |
| 178 | |
| 179 // Hearts... | |
| 180 for (var point of points) | |
| 88 { | 181 { |
| 89 for (let i = 0; i < vortex.length; i++) | 182 const newPoint = normalize( |
| 90 { | 183 threeDtotwoD( |
| 91 const newPoint = normazlie( | 184 move_z(rotate_yz(rotate_xz(rotate_xy(point, angle), angle), angle), dz) |
| 92 threeDtotwoD( | 185 // move_z(point, dz) |
| 93 move_z(rotate_xz(points[vortex[(i+1)%vortex.length]], angle), dz) | 186 ) |
| 94 ) | |
| 95 ); | |
| 96 | |
| 97 drawLine( | |
| 98 normazlie( | |
| 99 threeDtotwoD( | |
| 100 move_z(rotate_xz(points[vortex[i]], angle), dz) | |
| 101 ) | |
| 102 ), | |
| 103 {x2: newPoint.x, y2: newPoint.y} | |
| 104 ); | 187 ); |
| 105 } | 188 drawPixel(newPoint); |
| 106 } | 189 } |
| 190 | |
| 191 // for (var vortex of vortexs) | |
| 192 // { | |
| 193 // for (let i = 0; i < vortex.length; i++) | |
| 194 // { | |
| 195 // const newPoint = normalize( | |
| 196 // threeDtotwoD( | |
| 197 // move_z(rotate_xz(points[vortex[(i+1)%vortex.length]], angle), dz) | |
| 198 // ) | |
| 199 // ); | |
| 200 | |
| 201 // drawLine( | |
| 202 // normalize( | |
| 203 // threeDtotwoD( | |
| 204 // move_z(rotate_xz(points[vortex[i]], angle), dz) | |
| 205 // ) | |
| 206 // ), | |
| 207 // {x2: newPoint.x, y2: newPoint.y} | |
| 208 // ); | |
| 209 // } | |
| 210 // } | |
| 107 setTimeout(() => drawAnimation(), 1000/60) | 211 setTimeout(() => drawAnimation(), 1000/60) |
| 108 } | 212 } |
| 109 | 213 |
| 110 drawAnimation() | 214 drawAnimation() |
| 111 | 215 |