✱presque.cool
← Back to projects
Seedmoji icon

Seedmoji

Fév 2026 App
Visit project ↗

A unique ASCII avatar for every word, every email, every username. The same text gives back the same face.


Le pitch

Seedmoji transforme n’importe quelle chaîne de caractères, un email, un pseudo, un UUID, en un petit visage composé de caractères. Taper deux fois le même texte redonne le même visage, sans compte ni stockage.

Essayer : presque.cool/seedmoji/

Durée ~1 jour
Période Fév 2026 → Oct 2026
Stack
Preact TypeScript PWA
Statut ✓ En production

Pourquoi ce projet

Il existe de nombreux générateurs d’avatars par seed — Identicon, MonsterID, Wavatars, Retro (by Gravatar), RoboHash… Facehash, de cossistant, dessine des visages en SVG à partir de n’importe quel texte. En le découvrant, j’ai eu envie de composer les miens entièrement en caractères, en poussant plus loin la variabilité : plus d’éléments, plus de combinaisons, plus d’expressivité.

Le résultat : des petits visages en glyphs qui sont souvent drôles, parfois étranges, toujours uniques.

Un jour de développement, du plaisir créatif pur.


Le dictionnaire de glyphs

Le cœur de Seedmoji, c’est son dictionnaire de caractères. J’ai écumé des sites de référence Unicode et des tables de glyphs pour constituer un catalogue trié sur le volet :

  • 109 paires d’yeux — du classique ASCII (o,o ^,^ x,x) aux formes géométriques (◉,◉ ★,☆) en passant par les kaomoji (ಠ,ಠ ꖘ,ꖘ) et les symboles monétaires (€,€ ¥,¥). Symétriques et asymétriques.
  • 41 bouches — lignes horizontales (─ ━), courbes kaomoji (ω Д ∀), formes expressives (▽ 益).
  • 15 nez — affichés uniquement avec les bouches horizontales pour éviter les chevauchements visuels.
  • 32 cadres — des crochets classiques ([ ]) aux cadres CJK (「 」 【 】) en passant par les décoratifs (╭ ╮ ╔ ╗).
  • 16 couleurs de fond — une palette vibrante récupérée sur un site d’inspiration graphique.

Le tout donne environ 34 millions de combinaisons uniques (sans compter les 3 formes de découpe). Chaque seed produit un visage différent et reproductible.


Le cœur technique : un hash déterministe

L’algorithme repose sur un hash simple, FNV-1a suivi d’un mélange MurmurHash3, le même dans tous mes projets :

seed → hash 32 bits → indices déterministes → composants du visage

Pourquoi pas SHA-256 ou MD5 ?

  1. Pas de sécurité requise — on génère des avatars, pas des tokens d’authentification
  2. Performance — FNV-1a fait quelques opérations par caractère, bien moins que SHA-256. L’avatar se recalcule à chaque frappe clavier, la différence est perceptible
  3. Synchronicité — crypto.subtle.digest() est asynchrone, ça compliquerait inutilement le code
  4. Bundle size — le hash tient en quelques lignes. Zéro dépendance, zéro polyfill

Un détail de design intéressant : le premier caractère du seed détermine la bouche. Taper a produit un avatar avec a comme bouche. Cela crée un lien visuel immédiat entre l’entrée et le résultat.

Le contraste texte/fond est calculé automatiquement via la luminance perçue (formule 0.299R + 0.587G + 0.114B) : fond clair → texte noir, fond foncé → texte blanc.


L’API d’embedding

Seedmoji inclut un endpoint /api/ qui génère du SVG brut via query params :

/seedmoji/api/?seed=tristan&shape=squircle&size=128

L’endpoint est un script PHP côté serveur. Il reprend le générateur de l’app bit à bit, et produit le même visage en SVG pur. Le SVG utilise des clipPath pour les formes (carré, squircle, rond), là où le composant React utilise borderRadius en CSS.

Pas encore utilisé en production, mais prêt pour une intégration dans d’autres projets.


Stack technique

  • Preact + TypeScript — Composants fonctionnels, typage strict
  • Vite + SWC — Build rapide
  • Tailwind CSS — Couleurs OKLch, dark mode
  • Zustand — State management, persistance localStorage
  • PWA — installable, offline, Workbox
  • i18n maison — Français/anglais, détection automatique du navigateur
  • Export SVG + PNG (512, 720, 1024px) via Canvas API
  • CSP — Content-Security-Policy avec hashes auto-générés

Évolutions

Date Version Description
Fév 2026 1.0 Version initiale — Dictionnaire, hash, export, PWA
Sep 2026 2.0 Nouveau générateur aléatoire : un même texte ne donne plus le même visage qu’avant. Contraste renforcé, l’API PHP donne exactement le même visage que l’app, réglages conservés d’une version à l’autre.
Oct 2026 2.1 Pour un démarrage plus léger, Preact remplace React : 90 Ko de JavaScript au premier chargement deviennent 32 Ko. La fenêtre des réglages et les contrôles de l’avatar s’ouvrent sans attendre.

Bilan

Durée : 1 jour (février 2026).

Ce que j’ai appris :

  • Qu’un dictionnaire de caractères Unicode soigneusement curé peut produire des résultats étonnamment expressifs — la contrainte ASCII force la créativité
  • Qu’un hash de quelques lignes suffit quand on n’a pas besoin de sécurité cryptographique

Ce que je referais pareil :

  • Partir d’une envie simple, des visages entièrement en caractères, et livrer en un jour
  • Le premier caractère du seed comme bouche — c’est le détail qui rend l’avatar personnel

Ce que je changerais :

  • Explorer les animations SVG pour donner vie aux avatars — un clin d’œil, une bouche qui bouge
  • Intégrer l’API dans d’autres projets pour tester son utilité réelle

The pitch

Seedmoji turns any string, an email, a username, a UUID, into a small face made of characters. Typing the same text twice gives back the same face, with no account and no storage.

Try it: presque.cool/seedmoji/

Duration ~1 day
Period Feb 2026 → Oct 2026
Stack
Preact TypeScript PWA
Status ✓ In production

Why this project

There are many seed-based avatar generators — Identicon, MonsterID, Wavatars, Retro (by Gravatar), RoboHash… Facehash, by cossistant, draws SVG faces from any text. After discovering it, I wanted to compose mine entirely from characters, with more variability: more elements, more combinations, more expressiveness.

The result: little glyph faces that are often funny, sometimes weird, always unique.

One day of development, pure creative fun.


The glyph dictionary

The heart of Seedmoji is its character dictionary. I scoured Unicode reference sites and glyph tables to build a hand-picked catalogue:

  • 109 eye pairs — from classic ASCII (o,o ^,^ x,x) to geometric shapes (◉,◉ ★,☆), kaomoji (ಠ,ಠ ꖘ,ꖘ), and currency symbols (€,€ ¥,¥). Both symmetric and asymmetric.
  • 41 mouths — horizontal lines (─ ━), kaomoji curves (ω Д ∀), expressive shapes (▽ 益).
  • 15 noses — displayed only with horizontal mouths to avoid visual overlap.
  • 32 frames — from classic brackets ([ ]) to CJK frames (「 」 【 】) and decorative ones (╭ ╮ ╔ ╗).
  • 16 background colors — a vibrant palette sourced from a graphic inspiration site.

This yields roughly 34 million unique combinations (not counting the 3 clipping shapes). Each seed produces a different, reproducible face.


The technical core: a deterministic hash

The algorithm relies on a simple hash, FNV-1a followed by a MurmurHash3 mix, the same across all my projects:

seed → 32-bit hash → deterministic indices → face components

Why not SHA-256 or MD5?

  1. No security needed — we’re generating avatars, not authentication tokens
  2. Performance — FNV-1a takes a few operations per character, far fewer than SHA-256. The avatar recalculates on every keystroke, the difference is noticeable
  3. Synchronicity — crypto.subtle.digest() is async. That would needlessly complicate the code
  4. Bundle size — the hash fits in a few lines. Zero dependencies, zero polyfills

An interesting design detail: the first character of the seed determines the mouth. Typing a produces an avatar with a as its mouth. This creates an immediate visual link between input and output.

Text/background contrast is calculated automatically using perceived luminance (formula 0.299R + 0.587G + 0.114B): light background → black text, dark background → white text.


The embedding API

Seedmoji includes an /api/ endpoint that generates raw SVG via query params:

/seedmoji/api/?seed=tristan&shape=squircle&size=128

The endpoint is a server-side PHP script. It ports the app’s generator bit for bit and produces the same face as pure SVG. The SVG uses clipPath for shapes (square, squircle, round), while the React component uses CSS borderRadius.

Not yet used in production, but ready for integration into other projects.


Tech stack

  • Preact + TypeScript — Functional components, strict typing
  • Vite + SWC — Fast builds
  • Tailwind CSS — OKLch colors, dark mode
  • Zustand — State management, localStorage persistence
  • PWA — installable, offline, Workbox
  • i18n custom — French/English, automatic browser detection
  • Export SVG + PNG (512, 720, 1024px) via Canvas API
  • CSP — Content-Security-Policy with auto-generated hashes

Timeline

Date Version Description
Feb 2026 1.0 Initial version — Dictionary, hash, export, PWA
Sep 2026 2.0 New random generator: the same text no longer gives the face it gave before. Stronger contrast, the PHP API returns exactly the same face as the app, settings kept across versions.
Oct 2026 2.1 For a lighter start, Preact replaces React: 90 KB of JavaScript at first load becomes 32 KB. The settings window and the avatar controls open without waiting.

Takeaways

Duration: 1 day (February 2026).

What I learned:

  • That a carefully curated Unicode character dictionary can produce surprisingly expressive results — the ASCII constraint forces creativity
  • That a hash of a few lines is enough when you don’t need cryptographic security

What I’d do the same:

  • Start from a simple wish, faces made entirely of characters, and ship in one day
  • The first character of the seed as the mouth — it’s the detail that makes the avatar feel personal

What I’d change:

  • Explore SVG animations to bring the avatars to life — a wink, a moving mouth
  • Integrate the API into other projects to test its real-world usefulness