This commit is contained in:
Lani Aung
2025-06-05 07:31:05 -07:00
parent ef5b289ff0
commit 8d1b7bfd4d
9 changed files with 113 additions and 226 deletions
+29 -20
View File
@@ -2,7 +2,6 @@ import SandPainter from "./sand-painter"
import State from "./state"
export default class Crack {
private static padding = .66
private x: number = 0
private y: number = 0
private angle: number = 0
@@ -10,29 +9,17 @@ export default class Crack {
private state: State
constructor(state: State) {
this.painter = new SandPainter(state)
this.painter = new SandPainter(state.getRandomColor())
this.state = state
this.init()
}
init() {
let x = 0, y = 0, found = false, tries = 0
while (!found && tries++ < 1000) {
x = Math.random() * this.state.width
y = Math.random() * this.state.height
found = this.state.crackGrid[y * this.state.height + x] < 10000
}
if (!found) {
console.warn("Unable to start crack due to timeout")
return
}
const negative = Math.random() < 0.5
let value = this.state.crackGrid[y * this.state.height + x]
if (negative) value -= 90 + Math.floor(Math.random() * 4.1 - 2)
else value += 90 + Math.floor(Math.random() * 4.1 - 2)
const index = Math.floor(Math.random() * this.state.seeds.length)
const {x, y} = this.state.seeds.splice(index, 1)[0]
const flip = Math.random() < 0.5
let angle = this.state.grid[x][y]
this.start(x, y, angle + (90 + Math.floor(Math.random() * 4.1 - 2)) * (flip ? -1 : 1))
}
start(x: number, y: number, angle: number) {
@@ -41,8 +28,30 @@ export default class Crack {
this.angle = angle
}
continue() {
draw() {
this.x += .42 * Math.cos(this.angle * Math.PI / 180)
this.y += .42 * Math.sin(this.angle * Math.PI / 180)
const context = this.state.canvas.getContext("2d")
context.fillStyle = "#000"
context.fillRect(this.x, this.y, 1, 1)
const x = Math.floor(this.x)
const y = Math.floor(this.y)
const height = this.state.canvas.height
const width = this.state.canvas.width
if (x >= 0 && x < width && y >= 0 && y < height) {
const seed = this.state.grid[x][y]
if (seed > 10000 || Math.abs(seed - this.angle) < 5) {
this.state.grid[x][y] = Math.floor(this.angle)
this.state.seeds.push({x, y})
} else if (Math.abs(seed - this.angle) > 2) {
this.init()
this.state.addCrack()
}
} else {
this.init()
this.state.addCrack()
}
}
}
+8 -2
View File
@@ -1,10 +1,16 @@
import Substrate from "./substrate"
import Weather from "./weather"
const background = new Substrate("substrate-canvas", 20)
const ready = (func: () => void) => document.readyState !== "loading" ? func() : document.addEventListener("DOMContentLoaded", func)
ready(() => {
new Substrate(20)
})
/*
let weather: Weather
navigator.geolocation.getCurrentPosition(position => {
weather = new Weather(position.coords.latitude, position.coords.longitude)
}, () => {
weather = new Weather()
})
})
*/
+6 -2
View File
@@ -4,8 +4,12 @@ export default class SandPainter {
private color: number
private gain: number
constructor(state: State) {
this.color = state.getRandomColor()
constructor(color: number) {
this.color = color
this.gain = Math.random() / 10
}
render() {
}
}
+37 -12
View File
@@ -1,26 +1,51 @@
export default class State {
colors: number[]
maxCracks: number
crackGrid: number[]
height: number
width: number
import Crack from "./crack"
constructor(colors: number[], maxCracks: number, height: number, width: number) {
export default class State {
readonly canvas: HTMLCanvasElement
readonly colors: number[]
readonly maxCracks: number
readonly grid: number[][]
seeds: {x: number, y: number}[]
cracks: Crack[]
constructor(colors: number[], maxCracks: number, canvas: HTMLCanvasElement) {
this.canvas = canvas
this.colors = colors
this.maxCracks = maxCracks
this.height = height
this.width = width
this.crackGrid = []
this.grid = []
this.cracks = []
this.init()
}
init() {
this.seeds = []
const height = this.canvas.height
const width = this.canvas.width
const context = this.canvas.getContext("2d")
context.fillStyle = "rgb(255 255 255 / 95%)"
context.fillRect(0, 0, width, height)
for (let x = 0; x < width; x++) {
if (!this.grid[x]) this.grid[x] = []
for (let y = 0; y < height; y++) {
this.crackGrid[y * width + x] = 10000
this.grid[x][y] = 10001
}
}
for (let i = 0; i < 16; i++) {
this.crackGrid[Math.floor(Math.random() * (height * width))] = Math.ceil(Math.random() * 360)
const x = Math.floor(Math.random() * width)
const y = Math.floor(Math.random() * height)
this.grid[x][y] = Math.floor(Math.random() * 360)
this.seeds.push({x, y})
}
this.cracks = [new Crack(this), new Crack(this), new Crack(this)]
}
addCrack() {
if (this.cracks.length < this.maxCracks) this.cracks.push(new Crack(this))
}
getRandomColor(): number {
-7
View File
@@ -4,11 +4,4 @@ body {
margin: 0;
overflow: hidden;
padding: 0;
}
body {
canvas {
height: 100%;
width: 100%;
}
}
+20 -13
View File
@@ -2,27 +2,34 @@
import State from "./state"
export default class Substrate {
private readonly canvas: HTMLCanvasElement
private readonly state: State
constructor(id: string, maxCracks: number, colors?: number[]) {
constructor(maxCracks: number, colors?: number[]) {
if (!colors?.length) colors = [ 0x3a1e3e, 0x7c2d3b, 0xb94f3c, 0xf4a462, 0xf9c54e ] // https://colormagic.app/palette/671eeb6c42273fc4c1bb1ac7
let canvas = document.getElementById(id) as HTMLCanvasElement
if (!canvas) {
canvas = document.createElement("canvas")
document.body.appendChild(canvas)
}
this.canvas = canvas
this.state = new State(colors, maxCracks, canvas.clientHeight, canvas.clientWidth)
const canvas = document.createElement("canvas")
canvas.width = document.body.clientWidth
canvas.height = document.body.clientHeight
document.body.appendChild(canvas)
this.state = new State(colors, maxCracks, canvas)
this.init()
}
init() {
const context = this.canvas.getContext("2d")
context.fillStyle = "#fff"
context.fillRect(0, 0, this.canvas.width, this.canvas.height)
const me = this
let request: number
const draw = () => {
for (const crack of me.state.cracks) crack.draw()
request = requestAnimationFrame(draw)
}
setInterval(() => {
cancelAnimationFrame(request)
me.state.init()
request = requestAnimationFrame(draw)
}, 60 * 1000)
request = requestAnimationFrame(draw)
}
}
-1
View File
@@ -6,7 +6,6 @@
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<canvas id="substrate-canvas"></canvas>
<div id="weather-panel"></div>
<script src="main.js"></script>
</body>
+13 -165
View File
File diff suppressed because one or more lines are too long
-4
View File
@@ -5,7 +5,3 @@ body {
overflow: hidden;
padding: 0;
}
body canvas {
height: 100%;
width: 100%;
}