-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
67 additions
and
30 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,77 @@ | ||
'use strict'; | ||
//setup and initialization | ||
const canvas = document.getElementById('c'), | ||
ctx = canvas.getContext('2d', {alpha: false, desynchronized: true}), | ||
w = canvas.width = document.body.offsetWidth, | ||
h = canvas.height = document.body.offsetHeight, | ||
space = 24, //pixel spacing between chars | ||
const canv = document.getElementById('c'), | ||
ctx = canv.getContext('2d', {alpha: false, desynchronized: true}), | ||
//primary and secondary colors | ||
colors = ['f00', 'ff0', '0f0', '0ff', '00f', 'f0f'], | ||
charset = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', | ||
columns = new Uint32Array(Math.ceil(w / space)), | ||
FPS_to_ms = f => 1000 / f, | ||
randRange = (min, max) => Math.random() * (max - min) + +min | ||
//I'm not using `Intl.Segmenter` because grapheme clusters can be rendered with ANY size | ||
//supporting code-points instead of code-units is easier and less buggy | ||
charset = [...'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'], | ||
Hz_to_ms = f => 1000 / f, | ||
randRange = (min, max) => Math.random() * (max - min) + +min, //[min, max) | ||
clamp = (x, min, max) => x > max ? max : x < min ? min : x //[min, max] | ||
|
||
let color_i = 0, start | ||
const baseFrame = () => { | ||
ctx.fillStyle = '#' + colors[color_i++]; ctx.font = space + 'px monospace' | ||
let debounceDelay = 1500,//ms | ||
space = 24, //px between chars, kinda works like "zoom" | ||
speed = 30, //Hz of new chars drawn | ||
dimDepth = 1 / 3, | ||
minCol = 7, maxCol = 14, | ||
w = canv.width = document.body.offsetWidth, | ||
h = canv.height = document.body.offsetHeight, | ||
color_i = 0, t | ||
|
||
const columns = Array(Math.ceil(w / space)).fill(0) | ||
|
||
const drawChars = () => { | ||
ctx.fillStyle = '#' + colors[color_i++] | ||
ctx.font = space + 'px monospace' | ||
color_i %= colors.length | ||
for (let i = 0, x = 0; i < columns.length; i++, x += space) { | ||
const y = columns[i] | ||
//draw a char | ||
//render a codepoint | ||
ctx.fillText(charset[randRange(0, charset.length) | 0], x, y) | ||
//since the range is arbitrary, we have freedom to use powers of 2 for performance | ||
columns[i] = y > (randRange(1 << 7, 1 << 14) >>> 0) ? 0 : y + space | ||
columns[i] = y > (randRange(1 << minCol, 1 << maxCol) >>> 0) ? 0 : y + space | ||
//if the canvas shrinks immediately before this, | ||
//then this will cause a non-critical memory leak, and a "CPU leak" | ||
//it's easily fixed by resizing again, or reloading | ||
} | ||
} | ||
const nextFrame = now => { | ||
if (now - start > FPS_to_ms(30)) { | ||
//global dimming, make the trail disappear gradually | ||
ctx.fillStyle = '#0001'; ctx.fillRect(0, 0, w, h) | ||
color_i %= colors.length | ||
baseFrame() | ||
start = now | ||
} | ||
requestAnimationFrame(nextFrame) | ||
//makes the trails disappear gradually | ||
const doGlobalDimming = now => { | ||
const delta = now - t, dim = Math.round(clamp(delta + dimDepth, 0, 0xff)) | ||
ctx.fillStyle = '#000000' + dim.toString(16).padStart(2, '0') | ||
ctx.fillRect(0, 0, w, h) | ||
t = now | ||
requestAnimationFrame(doGlobalDimming) | ||
} | ||
|
||
//draw 1st frame | ||
requestAnimationFrame(now => { | ||
//set BG to pure black | ||
ctx.fillStyle = '#000'; ctx.fillRect(0, 0, w, h) | ||
baseFrame() | ||
start = now | ||
drawChars() | ||
t = now | ||
}) | ||
requestAnimationFrame(nextFrame) | ||
//draw chars independent of FPS | ||
let IntID = setInterval(drawChars, Hz_to_ms(speed)), | ||
RAFID = requestAnimationFrame(doGlobalDimming), | ||
timeoutID = false | ||
|
||
const pause = () => { | ||
clearInterval(IntID) | ||
cancelAnimationFrame(RAFID) | ||
} | ||
|
||
const resize = () => { | ||
w = canv.width = document.body.offsetWidth | ||
h = canv.height = document.body.offsetHeight | ||
const colCount = Math.ceil(w / space) | ||
if (colCount > columns.length) | ||
do {columns.push(0)} while (columns.length < colCount) | ||
else columns.length = colCount | ||
} | ||
|
||
addEventListener('resize', () => { | ||
clearTimeout(timeoutID) | ||
timeoutID = setTimeout(resize, debounceDelay) | ||
}) |
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
e84d7cc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixes #2
e84d7cc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixes #26 (mostly)
e84d7cc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit is also a preparation to implement #5, so I guess this is a big update. I would call it "the dynamic/adaptive update"