Last active
April 4, 2022 23:45
-
-
Save Colouratura/e3756e0fa4972812c236693b9cbcad78 to your computer and use it in GitHub Desktop.
A small experiment in the Canvas ImageData api
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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