Skip to content

Instantly share code, notes, and snippets.

@mattdesl
Last active May 30, 2019 21:13
Show Gist options
  • Save mattdesl/230d151530e9e62488a14e5205f46173 to your computer and use it in GitHub Desktop.
Save mattdesl/230d151530e9e62488a14e5205f46173 to your computer and use it in GitHub Desktop.
const {
canvasSketch,
GUI,
KeyPress,
FaviconRenderer
} = require('./hooks');
const settings = {
animate: true,
scaleToView: true,
fps: 30,
duration: 4,
dimensions: [64, 64]
};
const sketch = ({ register }) => {
// Register key presses
const keyPress = register(KeyPress);
// Register GUI controls
const params = register(GUI, {
background: '#000'
});
// Render into favicon
register(FaviconRenderer);
return ({ context, width, height, playhead }) => {
// Clear background
context.clearRect(0, 0, width, height);
// Draw circle
const radius = Math.min(width, height) * 0.5;
context.fillStyle = params.background;
context.beginPath();
context.arc(width / 2, height / 2, radius, 0, Math.PI * 2);
context.fill();
// Draw letter
context.font = `${width * 0.65}px "Andale Mono"`;
context.textBaseline = 'middle';
context.textAlign = 'center';
context.fillStyle = 'white';
context.save();
context.translate(width / 2, height / 2);
context.rotate(playhead * Math.PI * 2);
context.fillText(keyPress.key || 'a', 0, 0);
context.restore();
};
};
canvasSketch(sketch, settings);
const dat = require('dat.gui');
const Color = require('canvas-sketch-util/color');
const canvasSketch = require('canvas-sketch');
module.exports.GUI = GUI;
function GUI (props, opt) {
const gui = new dat.GUI();
const output = {};
Object.keys(opt).forEach(key => {
let control = opt[key];
const parsedColor = Color.parse(control);
if (parsedColor != null) {
control = {
type: 'color',
value: parsedColor.hex
};
}
let field;
if (control && control.type) {
if (control.type === 'color') {
output[key] = control.value;
field = gui.addColor(output, key);
} else if (control.type === 'number') {
output[key] = control.value;
field = gui.add(output, key, control.min, control.max, control.step);
}
} else {
output[key] = control;
field = gui.add(output, key);
}
field.onChange(() => {
props.update();
});
});
return {
output,
unload () {
console.log('destroy')
gui.destroy();
}
};
}
GUI.Color = (value = 'black') => {
return {
type: 'color',
value
};
};
GUI.Number = (value = 0, min = -Infinity, max = Infinity, step = 0.001) => {
return {
type: 'number',
value,
min,
max,
step
};
};
module.exports.FaviconRenderer = FaviconRenderer;
function FaviconRenderer (props) {
// TODO: gotta make this cleanup on unload()
const link = document.createElement('link');
link.setAttribute('rel', 'icon');
link.setAttribute('type', 'image/ico');
document.head.appendChild(link);
update(props);
return {
postRender (props) {
update(props);
}
};
function update (props) {
link.setAttribute('href', props.canvas.toDataURL('image/png'));
}
}
module.exports.KeyPress = KeyPress;
function KeyPress (props, defaultKey) {
const output = {
key: undefined,
...defaultKey
};
window.addEventListener('keypress', keypress);
return {
output,
unload () {
window.removeEventListener('keypress', keypress);
}
};
function keypress (ev) {
output.key = ev.key;
props.update();
}
}
module.exports.MousePosition = MousePosition;
function MousePosition (props) {
const output = [ 0, 0 ];
const element = props.canvas;
element.addEventListener('mousemove', update);
return {
output,
unload () {
element.removeEventListener('mousemove', update);
}
};
function update (ev) {
const rect = props.canvas.getBoundingClientRect();
output[0] = (ev.clientX - rect.left) / props.styleWidth * props.width;
output[1] = (ev.clientY - rect.top) / props.styleHeight * props.height;
props.update();
}
}
module.exports.canvasSketch = (sketch, settings) => {
const sketchImpl = async (props) => {
const registered = [];
const register = (plugin, ...args) => {
const impl = plugin(props, ...args) || {};
registered.push(impl);
return impl.output;
};
props.register = register;
const renderer = await sketch(props);
return {
render (props) {
registered.forEach(r => r.preRender && r.preRender(props));
let ret;
if (typeof renderer === 'function') ret = renderer(props);
else if (renderer && typeof renderer.render === 'function') ret = renderer.render(props);
registered.forEach(r => r.postRender && r.postRender(props));
return ret;
},
unload (props) {
registered.forEach(r => r.unload && r.unload(props));
if (renderer && typeof renderer.unload === 'function') return renderer.unload(props);
registered.forEach(r => r.unloaded && r.unloaded(props));
}
};
};
return canvasSketch(sketchImpl, settings);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment