Re:Show HN: Self-hosted service for creating random avatars
by tomxor on Sunday March 13, 2022 @10:09AM
(#30661341)
No offence but this seems overcomplicated to me. I know docker and nodejs etc are all the trend, or maybe I'm missing something that makes this necessary?
If it's just a matter of generating a random sprite, this could be a simple front-end script that given a random seed outputs a deterministic avatar. That seed could be based on a user-email etc and now you have a "service" without a back-end. The images are simple enough that it should be very efficient to generate and faster than a http request (provided it's written considerately)... or if it _must_ be done in the backend, you could generate a http image response on the fly based on a seed passed in the request header, again in one simple script.
[edit]
Sorry I feel bad now, but I genuinely think there is a better approach. I'm hoping you might be open to it. Here's a proof of concept that add avatars to HN based on the username:
(Just paste it in the console on this page and scroll to the top.)
const avatar = (r=1, p=16) => {
const c = document.createElement('canvas');
const x = c.getContext('2d');
c.width = 8*p;
c.height = 8*p;
for (let i=28; i--;) {
// xorshift
r ^= r << 13;
r ^= r >>> 17;
r ^= r << 5;
// pixels
const X=i&3, Y=i>>2;
if (r>>>28 > X*X+Y) {
x.fillRect(
p*3.5 + p*X,
p*0.5 + p*Y,
p, p);
x.fillRect(
p*3.5 - p*X,
p*0.5 + p*Y,
p, p);
}
}
return c;
};
// Your HN avatar ! :)
const seed = [...me.innerText]
.map(c => c.charCodeAt(0))
.reduce((a, b) => a + b);
const sprite = avatar(seed);
document.body.prepend(sprite);
Re:Show HN: Self-hosted service for creating random avatars
by tomxor on Sunday March 13, 2022 @07:53PM
(#30666999)
I'm glad. Also, thank you, I actually had some fun hacking on this problem a bit more. Following is a script to annotate HN comments with deterministic avatars :) feel free to do with it as you please.
Fixed one silly oversight: the original example just summed the unicode points of the username, but this has trivial collisions with other names (even on this thread), ideally the string should be hashed, so i've done a very simple made up hash by adding a nonlinear operation to xorshift to combine each code point (if you really care about collisions, use a proper hash like SHA256). Also added some colour and tweaked the sprite probability distribution.
If you want a more sophisticated pattern, the part to play with is `if (r>>>29 > X**X/3+Y/2)`, the left hand side is the high 3 bits of the PRNG state (i.e random integer between 0 and 8), the right hand side is an arbitrary probability distribution, the current one just biases it towards the top center (squared on the horizontal). If you want a unit interval (a float between 0 and 1) rather than a 31bit uint for the random variable, you can get one with `(r>>>0)*2**-32`, but with a bit more computational cost.
for (const u of document.querySelectorAll('.hnuser')) {
const p=2;
// seed state
let s=u.innerText, r=1;
for (let i=s.length; i--;) {
// xorshift32
r^=r<<13, r^=r>>>17, r^=r<<5;
// seed
r+=s.charCodeAt(i);
}
// init canvas
const c=document.createElement('canvas');
c.width=p*8, c.height=p*8;
u.parentElement.prepend(c);
const x=c.getContext('2d');
x.fillStyle='#'+(r>>8&0xFFFFFF)
.toString(16).padStart(0, 6)
// draw pixels
for (let i=28; i--;) {
// xorshift32
r^=r<<13, r^=r>>>17, r^=r<<5;
// pixels
const X=i&3, Y=i>>2;
if (r>>>29 > X*X/3+Y/2)
x.fillRect(p*3.5+p*X, p*0.5+p*Y, p, p),
x.fillRect(p*3.5-p*X, p*0.5+p*Y, p, p);
}
}
If you paste above in the console of any HN page you will get annotated usernames.
Re:Show HN: Self-hosted service for creating random avatars
by tomxor on Sunday March 13, 2022 @04:00PM
(#30665130)
As I said, it can be done front or back end, you can use the same script I wrote if you want to stick to javascript, or can implement the same in any other language, and then just return the generated image. In fact the algorithm is so simple you can write the raw bytes out as a bitmap without depending on any image libraries if you wanted.
The difference is that it's stateless because it's deterministic. and therefore requires no more than a single small script.
Re:Show HN: Self-hosted service for creating random avatars
by phoboslab on Sunday March 13, 2022 @12:03PM
(#30662490)
Sorry to rain on your parade, but this looks seriously over-engineered. There are 71 files in this github repo (6914 after `npm install`) for something that requires ~100 lines of code.
Related: here's some PHP code I wrote 14 years ago that does something similar, but tries to generate aesthetically pleasing avatars:
Re:Show HN: Self-hosted service for creating random avatars
by ytjohn on Sunday March 13, 2022 @01:13PM
(#30663351)
One of these I really like that has been around forever is https://robohash.org/ You can generate different variations of robots, cats, and humans.
The source is available as well, and it's also a python module, which is great if you're writing python apps. I found it rather simple to integrate inside of just about any flask/fastapi/django application.
If it's just a matter of generating a random sprite, this could be a simple front-end script that given a random seed outputs a deterministic avatar. That seed could be based on a user-email etc and now you have a "service" without a back-end. The images are simple enough that it should be very efficient to generate and faster than a http request (provided it's written considerately)... or if it _must_ be done in the backend, you could generate a http image response on the fly based on a seed passed in the request header, again in one simple script.
[edit]
Sorry I feel bad now, but I genuinely think there is a better approach. I'm hoping you might be open to it. Here's a proof of concept that add avatars to HN based on the username:
(Just paste it in the console on this page and scroll to the top.)
Fixed one silly oversight: the original example just summed the unicode points of the username, but this has trivial collisions with other names (even on this thread), ideally the string should be hashed, so i've done a very simple made up hash by adding a nonlinear operation to xorshift to combine each code point (if you really care about collisions, use a proper hash like SHA256). Also added some colour and tweaked the sprite probability distribution.
If you want a more sophisticated pattern, the part to play with is `if (r>>>29 > X**X/3+Y/2)`, the left hand side is the high 3 bits of the PRNG state (i.e random integer between 0 and 8), the right hand side is an arbitrary probability distribution, the current one just biases it towards the top center (squared on the horizontal). If you want a unit interval (a float between 0 and 1) rather than a 31bit uint for the random variable, you can get one with `(r>>>0)*2**-32`, but with a bit more computational cost.
If you paste above in the console of any HN page you will get annotated usernames.The difference is that it's stateless because it's deterministic. and therefore requires no more than a single small script.
Related: here's some PHP code I wrote 14 years ago that does something similar, but tries to generate aesthetically pleasing avatars:
https://phoboslab.org/log/2008/12/instant-avatars
https://bruzu.com
The source is available as well, and it's also a python module, which is great if you're writing python apps. I found it rather simple to integrate inside of just about any flask/fastapi/django application.
https://github.com/e1ven/Robohash
https://apps.apple.com/us/app/id1464477788
https://play.google.com/store/apps/details?id=com.pranapps.h...
Example:
https://play-lh.googleusercontent.com/RYxCwU-dV9hdzmewDKYmlU...
https://code.sgo.to/2021/06/14/avatars.html