Skip to content

Instantly share code, notes, and snippets.

@blixt
Last active December 29, 2020 14:32
Show Gist options
  • Save blixt/371fb0668178c06fbb9a to your computer and use it in GitHub Desktop.
Save blixt/371fb0668178c06fbb9a to your computer and use it in GitHub Desktop.
Procedural avatars using procedural.
var avatar = procedural('avatar')
.takes('username')
// Size, in blocks.
.takes('size', function validate(avatar, blocks) {
return typeof blocks == 'number' && blocks > 0;
})
// The pixel size of a single (square) block.
.takes('blockSize', function validate(avatar, px) {
return typeof px == 'number' && px > 0;
})
// Calculate the colors that make up the avatar.
.provides('hueAngle', function (avatar) {
// Use a named number generator to get our own set of random values.
return avatar.getRandGen('color').nextInt(360);
})
.provides('background', function (avatar) {
return 'hsl(' + avatar.hueAngle + ', 100%, 50%)';
})
.provides('foreground', function (avatar) {
var hueAngle = (avatar.hueAngle + 180) % 360;
return 'hsl(' + hueAngle + ', 100%, 50%)';
})
// 75% of avatars have a mirrored effect, others don't.
.provides('isMirrored', function (avatar) {
return avatar.getRandGen('mirror').nextFloat() > .25;
})
// A particular avatar has a unique set of blocks.
.generates('block')
// The validator will run independently for both parameters.
.takes('x', 'y', function validate(block, xy) {
// We can refer to the parent instance (the avatar).
return typeof xy == 'number' && xy >= 0 && xy < block.avatar.size;
})
// The color of this block.
.provides('color', function (block) {
// No need for a named RNG because we only use it here within "block".
if (block.getRandGen().nextFloat() > .5) {
return block.avatar.foreground;
} else {
return block.avatar.background;
}
})
// Go back to defining the parent (avatar).
.done()
// Renders to a canvas and returns a URL for <img>.
.provides('url', function (avatar) {
var canvas = document.createElement('canvas'),
context = canvas.getContext('2d');
canvas.width = avatar.size * avatar.blockSize;
canvas.height = avatar.size * avatar.blockSize;
context.fillStyle = avatar.background;
context.fillRect(0, 0, avatar.size, avatar.size);
var finalX = avatar.isMirrored ? Math.floor(avatar.size / 2) : avatar.size,
blockSize = avatar.blockSize;
for (var y = 0; y < avatar.size; y++) {
for (var x = 0; x < finalX; x++) {
var realX = x * blockSize, realY = y * blockSize;
var block = avatar.block(x, y);
context.fillStyle = block.color;
context.fillRect(realX, realY, blockSize, blockSize);
if (avatar.isMirrored) {
var mirroredX = avatar.size * blockSize - realX - blockSize;
context.fillRect(mirroredX, realY, blockSize, blockSize);
}
}
}
return canvas.toDataURL();
});
var img = document.createElement('img');
img.src = avatar('bob', 16, 4).url;
document.body.appendChild(img);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment