Skip to content

Commit

Permalink
12 hue colors
Browse files Browse the repository at this point in the history
  • Loading branch information
laurentpayot committed Apr 11, 2023
1 parent 036e455 commit 0b6a951
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 33 deletions.
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Minidenticons changelog

## 3.1.0

_2023-04-11_

### New features

- 12 hue colors instead of 18 for easier distinction and better looking but at the cost of more collisions.

### Breaking Changes

- The color for a given username has changed. But the shape inside the identicon stays the same. Not bumping version to 4 as the version 3 was only released yesterday.

### Documentation update

- Custom element closing tag notice

## 3.0.0

_2023-04-10_
Expand Down Expand Up @@ -118,4 +134,4 @@ _2022-02-10_

## 0.X.XX

Various experiments.
Various experiments
53 changes: 32 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,37 +148,48 @@ You will always get the same identicon for a given username. But it is not impos
Generated identicons are 5×5 pixels large with vertical symmetry, and can have 18 different hues for the same saturation and lightness.
This means there are 2<sup>(3×5)</sup> × 18 = 589,824 different identicons possible, but actually much less because of the modulo-based algorithm used to get more colored pixels at the center of the identicon instead of having them scattered. So duplicate identicons are inevitable when using a lot of them. It shouldn’t matter as identicons should not be used solely to identify an user, and should always be coupled to a *unique* username :wink:

The `npm test` command results below show that you have roughly a 7% chance to generate a duplicate identicon when already using 1000 of them.
The `npm test` command results below show that you have roughly a 10% chance to generate a duplicate identicon when already using 1000 of them.

```text
0 collisions out of 100 (0.00%)
0 collisions out of 200 (0.00%)
2 collisions out of 300 (0.67%)
6 collisions out of 400 (1.50%)
11 collisions out of 500 (2.20%)
21 collisions out of 600 (3.50%)
38 collisions out of 700 (5.43%)
49 collisions out of 800 (6.13%)
55 collisions out of 900 (6.11%)
66 collisions out of 1000 (6.60%)
296 collisions out of 2000 (14.80%)
589 collisions out of 3000 (19.63%)
962 collisions out of 4000 (24.05%)
1441 collisions out of 5000 (28.82%)
1965 collisions out of 6000 (32.75%)
2564 collisions out of 7000 (36.63%)
3173 collisions out of 8000 (39.66%)
3860 collisions out of 9000 (42.89%)
4570 collisions out of 10000 (45.70%)
5 collisions out of 200 (2.50%)
11 collisions out of 300 (3.67%)
19 collisions out of 400 (4.75%)
27 collisions out of 500 (5.40%)
34 collisions out of 600 (5.67%)
50 collisions out of 700 (7.14%)
59 collisions out of 800 (7.38%)
87 collisions out of 900 (9.67%)
101 collisions out of 1000 (10.10%)
378 collisions out of 2000 (18.90%)
811 collisions out of 3000 (27.03%)
1282 collisions out of 4000 (32.05%)
1896 collisions out of 5000 (37.92%)
2546 collisions out of 6000 (42.43%)
3243 collisions out of 7000 (46.33%)
3969 collisions out of 8000 (49.61%)
4750 collisions out of 9000 (52.78%)
5569 collisions out of 10000 (55.69%)
```

## Performance

Minidenticons are *fast*.

- To see how long it takes for your browser to generate 100 identicons (for a big page) try out the [online benchmark](https://laurentpayot.github.io/minidenticons/benchmark/browser.html).
### Custom element benchmark

- The same benchmark is available for NodeJS. Simply run `node benchmark/node` at the root of a Minidenticons git clone.
To see how long it takes for your browser to generate 100 identicon custom elements (for a big page) try out the [online browser benchmark](https://laurentpayot.github.io/minidenticons/benchmark/browser.html).

### NodeJS benchmark

Simply run `node benchmark/node` at the root of a Minidenticons git clone.

On my machine I get the following result:

```
Time to generate 5000 identicon SVG strings for 15 characters random usernames:
7 milliseconds (10 runs average)
```

## License

Expand Down
2 changes: 1 addition & 1 deletion img/alienHead66.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions minidenticons.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// density of 4 for the lowest probability of collision
const SQUARE_DENSITY = 4
// 18 different colors only for easy distinction
const COLORS_NB = 18
// 12 different hue colors only for easy distinction
const COLORS_NB = 12
const DEFAULT_SATURATION = 50
const DEFAULT_LIGHTNESS = 50

Expand Down
2 changes: 1 addition & 1 deletion minidenticons.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion no-custom-element.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ console.time("\nTests duration")
new Array(identicon_CE, identicon_NO_CE).forEach(identicon => {

// non-integer hue normal for empty string
assert.equal(identicon(""), '<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(62.17362189473988 50% 50%)"></svg>')
assert.equal(identicon("foo"), '<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(60 50% 50%)"><rect x="1" y="1" width="1" height="1"/><rect x="2" y="0" width="1" height="1"/><rect x="2" y="1" width="1" height="1"/><rect x="2" y="2" width="1" height="1"/><rect x="2" y="3" width="1" height="1"/><rect x="2" y="4" width="1" height="1"/><rect x="3" y="1" width="1" height="1"/></svg>')
assert.equal(identicon("foo", 75), '<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(60 75% 50%)"><rect x="1" y="1" width="1" height="1"/><rect x="2" y="0" width="1" height="1"/><rect x="2" y="1" width="1" height="1"/><rect x="2" y="2" width="1" height="1"/><rect x="2" y="3" width="1" height="1"/><rect x="2" y="4" width="1" height="1"/><rect x="3" y="1" width="1" height="1"/></svg>')
assert.equal(identicon("foo", undefined, 75), '<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(60 50% 75%)"><rect x="1" y="1" width="1" height="1"/><rect x="2" y="0" width="1" height="1"/><rect x="2" y="1" width="1" height="1"/><rect x="2" y="2" width="1" height="1"/><rect x="2" y="3" width="1" height="1"/><rect x="2" y="4" width="1" height="1"/><rect x="3" y="1" width="1" height="1"/></svg>')
assert.equal(identicon("alienHead66"), '<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(0 50% 50%)"><rect x="0" y="0" width="1" height="1"/><rect x="0" y="2" width="1" height="1"/><rect x="1" y="1" width="1" height="1"/><rect x="1" y="3" width="1" height="1"/><rect x="1" y="4" width="1" height="1"/><rect x="2" y="1" width="1" height="1"/><rect x="2" y="2" width="1" height="1"/><rect x="2" y="3" width="1" height="1"/><rect x="2" y="4" width="1" height="1"/><rect x="4" y="0" width="1" height="1"/><rect x="4" y="2" width="1" height="1"/><rect x="3" y="1" width="1" height="1"/><rect x="3" y="3" width="1" height="1"/><rect x="3" y="4" width="1" height="1"/></svg>')
assert.equal(identicon(""), '<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(273.2604328421098 50% 50%)"></svg>')
assert.equal(identicon("foo"), '<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(90 50% 50%)"><rect x="1" y="1" width="1" height="1"/><rect x="2" y="0" width="1" height="1"/><rect x="2" y="1" width="1" height="1"/><rect x="2" y="2" width="1" height="1"/><rect x="2" y="3" width="1" height="1"/><rect x="2" y="4" width="1" height="1"/><rect x="3" y="1" width="1" height="1"/></svg>')
assert.equal(identicon("foo", 75), '<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(90 75% 50%)"><rect x="1" y="1" width="1" height="1"/><rect x="2" y="0" width="1" height="1"/><rect x="2" y="1" width="1" height="1"/><rect x="2" y="2" width="1" height="1"/><rect x="2" y="3" width="1" height="1"/><rect x="2" y="4" width="1" height="1"/><rect x="3" y="1" width="1" height="1"/></svg>')
assert.equal(identicon("foo", undefined, 75), '<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(90 50% 75%)"><rect x="1" y="1" width="1" height="1"/><rect x="2" y="0" width="1" height="1"/><rect x="2" y="1" width="1" height="1"/><rect x="2" y="2" width="1" height="1"/><rect x="2" y="3" width="1" height="1"/><rect x="2" y="4" width="1" height="1"/><rect x="3" y="1" width="1" height="1"/></svg>')
assert.equal(identicon("alienHead66"), '<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(180 50% 50%)"><rect x="0" y="0" width="1" height="1"/><rect x="0" y="2" width="1" height="1"/><rect x="1" y="1" width="1" height="1"/><rect x="1" y="3" width="1" height="1"/><rect x="1" y="4" width="1" height="1"/><rect x="2" y="1" width="1" height="1"/><rect x="2" y="2" width="1" height="1"/><rect x="2" y="3" width="1" height="1"/><rect x="2" y="4" width="1" height="1"/><rect x="4" y="0" width="1" height="1"/><rect x="4" y="2" width="1" height="1"/><rect x="3" y="1" width="1" height="1"/><rect x="3" y="3" width="1" height="1"/><rect x="3" y="4" width="1" height="1"/></svg>')

for (let saturation = 0; saturation < 100; saturation += 5) {
for (let lightness = 0; lightness < COLLISION_TESTS_NUMBER; lightness += 5) {
assert.equal(
identicon("foo", saturation, lightness),
`<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(60 ${saturation}% ${lightness}%)"><rect x="1" y="1" width="1" height="1"/><rect x="2" y="0" width="1" height="1"/><rect x="2" y="1" width="1" height="1"/><rect x="2" y="2" width="1" height="1"/><rect x="2" y="3" width="1" height="1"/><rect x="2" y="4" width="1" height="1"/><rect x="3" y="1" width="1" height="1"/></svg>`
`<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(90 ${saturation}% ${lightness}%)"><rect x="1" y="1" width="1" height="1"/><rect x="2" y="0" width="1" height="1"/><rect x="2" y="1" width="1" height="1"/><rect x="2" y="2" width="1" height="1"/><rect x="2" y="3" width="1" height="1"/><rect x="2" y="4" width="1" height="1"/><rect x="3" y="1" width="1" height="1"/></svg>`
)
}
}
Expand Down

0 comments on commit 0b6a951

Please sign in to comment.