Skip to content

Instantly share code, notes, and snippets.

@Colouratura
Last active April 4, 2022 23:45
Show Gist options
  • Save Colouratura/e3756e0fa4972812c236693b9cbcad78 to your computer and use it in GitHub Desktop.
Save Colouratura/e3756e0fa4972812c236693b9cbcad78 to your computer and use it in GitHub Desktop.
A small experiment in the Canvas ImageData api
class Frame {
constructor(width, height, pallet) {
this.width = width
this.height = height
this.pallet = pallet
this.buffer = new Uint8ClampedArray((width * height) * 4)
}
asBytes() {
return this.buffer
}
asImageData() {
const id = new ImageData(this.buffer, this.width, this.height)
return id
}
asArray() {
}
fill(colorIndex) {
const color = this.pallet.asBytes(colorIndex)
for (let i = 0; i < this.buffer.length; i += 4) {
this.buffer[i + 0] = color[0]
this.buffer[i + 1] = color[1]
this.buffer[i + 2] = color[2]
this.buffer[i + 3] = color[3]
}
}
}
class Pallet {
constructor() {
this.pallet = [
{r: 2, g: 4, b: 8, a: 255},
{r: 29, g: 43, b: 83, a: 255},
{r: 126, g: 37, b: 83, a: 255},
{r: 0, g: 135, b: 81, a: 255},
{r: 171, g: 82, b: 54, a: 255},
{r: 95, g: 87, b: 79, a: 255},
{r: 194, g: 195, b: 199, a: 255},
{r: 255, g: 241, b: 232, a: 255},
{r: 255, g: 0, b: 77, a: 255},
{r: 255, g: 163, b: 0, a: 255},
{r: 255, g: 236, b: 39, a: 255},
{r: 0, g: 228, b: 54, a: 255},
{r: 41, g: 173, b: 255, a: 255},
{r: 131, g: 118, b: 156, a: 255},
{r: 255, g: 119, b: 168, a: 255},
{r: 255, g: 204, b: 170, a: 255},
]
}
colorAt(index) {
return this.pallet[index]
}
asBytes(index) {
const color = this.colorAt(index)
const arr = new Uint8ClampedArray(4)
arr[0] = color.r
arr[1] = color.g
arr[2] = color.b
arr[3] = color.a
return arr
}
}
class Engine {
constructor($canvas, dimensions, fps) {
this.canvas = $canvas
this.width = dimensions[0]
this.height = dimensions[1]
this.fps = fps
this.pallet = new Pallet()
this.initializeCanvas()
}
initializeCanvas() {
this.canvas.width = this.width
this.canvas.height = this.height
this.ctx = this.canvas.getContext('2d')
// initialize to black
const arr = new Uint8ClampedArray((this.width * this.height) * 4)
.fill(90)
const id = new ImageData(arr, this.width, this.height)
this.ctx.putImageData(id, 0, 0)
}
render(frame) {
const id = frame.asImageData()
this.ctx.putImageData(id, 0, 0)
}
tick(f, s) {
let state = s
let uid = 0
let prevDelta = 0
function _tick(timestamp) {
uid = window.requestAnimationFrame(function() {
_tick.call(this, performance.now())
}.bind(this))
const delta = timestamp - prevDelta
if (this.fps && delta < 1000 / this.fps) {
return
}
const frame = new Frame(this.width, this.height, this.pallet)
state = f(frame, state)
this.render(frame)
prevDelta = timestamp
}
_tick.call(this, f, state)
}
}
// Entrypoint
function main() {
const $canvas = document.getElementById('canvas')
const dimensions = [640, 480]
const fps = 5
const engine = new Engine($canvas, dimensions, fps)
const state = {
color: 0,
}
engine.tick(function(frame, state) {
if (state.color === 16) {
state.color = 0
}
frame.fill(state.color)
state.color++
// required
return state
}, state)
}
// execute the main function on load
window.addEventListener('load', function() {
main()
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment