diff --git a/src/comp/postcard.svelte b/src/comp/postcard.svelte
index c882b20..7d19158 100644
--- a/src/comp/postcard.svelte
+++ b/src/comp/postcard.svelte
@@ -103,7 +103,7 @@
diff --git a/src/comp/useritem.svelte b/src/comp/useritem.svelte
index 3267bfa..e479e3d 100644
--- a/src/comp/useritem.svelte
+++ b/src/comp/useritem.svelte
@@ -17,5 +17,5 @@
-
+
diff --git a/src/lib/client/color.js b/src/lib/client/color.js
new file mode 100644
index 0000000..8e538da
--- /dev/null
+++ b/src/lib/client/color.js
@@ -0,0 +1,68 @@
+import seedrandom from "seedrandom";
+
+/**
+ * @typedef {{r: number, g: number, b: number}} rgb
+ */
+
+/**
+ * @param {seedrandom.PRNG} random
+ * @returns {rgb}
+ */
+function createColor(random) {
+ const r = random.quick();
+ const g = random.quick();
+ const b = random.quick();
+ const normal = Math.pow(r, 2) + Math.pow(g, 2) + Math.pow(b, 2);
+ return {
+ r: Math.round(r / normal * 255),
+ g: Math.round(g / normal * 255),
+ b: Math.round(b / normal * 255)
+ };
+}
+
+/**
+ *
+ * @param {rgb} a
+ * @param {rgb} b
+ * @returns {rgb}
+ */
+function mixColors(a, b) {
+ return {
+ r: Math.round(a.r * b.r / 255),
+ g: Math.round(a.g * b.g / 255),
+ b: Math.round(a.b * b.b / 255),
+ }
+}
+
+/**
+ * @param {string} seed
+ * @returns {{
+ * c1: rgb,
+ * c2: rgb,
+ * c3: rgb,
+ * c4: rgb,
+ * c13: rgb,
+ * c14: rgb,
+ * c23: rgb,
+ * c24: rgb
+ * }}
+ */
+export function generateQuadColors(seed) {
+ const r = seedrandom(seed);
+
+ const c1 = createColor(r);
+ const c2 = createColor(r);
+ const c3 = createColor(r);
+ const c4 = createColor(r);
+
+ return {
+ c1: c1,
+ c2: c2,
+ c3: c3,
+ c4: c4,
+ c13: mixColors(c1, c3),
+ c14: mixColors(c1, c4),
+ c23: mixColors(c2, c3),
+ c24: mixColors(c2, c4),
+ };
+}
diff --git a/src/lib/client/hash.js b/src/lib/client/hash.js
new file mode 100644
index 0000000..a890d7e
--- /dev/null
+++ b/src/lib/client/hash.js
@@ -0,0 +1,22 @@
+/**
+ * https://stackoverflow.com/a/8076436
+ * @param {string} string
+ * @returns {number}
+ */
+export function hashCode(string) {
+ var hash = 0;
+ for (var i = 0; i < string.length; i++) {
+ var code = string.charCodeAt(i);
+ hash = ((hash<<5)-hash)+code;
+ hash = hash & hash; // Convert to 32bit integer
+ }
+ return hash;
+}
+
+/**
+ * @param {any} any
+ * @returns {number}
+ */
+export function hashOf(any) {
+ return hashCode(String(any));
+}
diff --git a/static/avatar.svg b/static/avatar.svg
index c4a7a29..894522e 100644
--- a/static/avatar.svg
+++ b/static/avatar.svg
@@ -7,99 +7,57 @@
viewBox="0 0 100 100"
version="1.1"
id="svg1"
- inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
- sodipodi:docname="avatar.svg"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
-
-
-
-
+ id="defs1" />
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+