presque.cool
Back to projects
star wars avatar icon

star wars avatar

Déc 2016 App
Visit project

Create your Star Wars character. 4 species, hundreds of elements to combine, an avatar to export and share.


Le pitch

Star Wars Avatar est un créateur d’avatar en ligne pour l’univers Star Wars. On choisit parmi 4 espèces (Humain, Twi’lek, Zabrak, Mirialan) et des centaines d’éléments de personnalisation pour créer son personnage, puis on l’exporte en PNG ou on le partage via URL.

C’est l’un des premiers créateurs d’avatars Star Wars en ligne — et il a été codé trois fois, de trois manières différentes.

Essayer : starwarsavatar.com

Durée v3 : ~2 mois
Période Déc 2016 → Déc 2025
Stack
React TypeScript Zustand PWA
Statut ✓ En production

Pourquoi ce projet

En septembre 2016, j’ai contacté Marc Murera, designer et illustrateur derrière le compte @starwarsinfographic. J’aimais son travail graphique et je lui ai proposé une collaboration : créer un générateur d’avatar Star Wars pour la sortie du film “Rogue One: A Star Wars Story” en décembre 2016.

Il a accepté. Il fournissait les assets graphiques, je m’occupais du code.

C’était mon premier projet collaboratif avec un designer.


Trois versions, trois époques

Ce qui rend ce projet particulier, c’est son histoire technique :

Version 1 — jQuery (2016) L’objectif était de sortir vite pour coïncider avec Rogue One. jQuery était le standard de l’époque, cela fonctionnait.

Version 2 — Vanilla JS (2018) Deux ans plus tard, jQuery commençait à peser. J’ai refait l’application en JavaScript pur pour éliminer cette dépendance et moderniser le code.

Version 3 — React + TypeScript (2025) Après avoir réalisé Dice Roller et Grid4, je voulais vérifier si j’étais capable de migrer une application legacy vers React. Star Wars Avatar était le candidat idéal : un projet que je connaissais par cœur, avec une complexité réelle (composition SVG, gestion de couleurs, export d’images).

Chaque version a été une réécriture complète, pas une migration progressive. Trois approches différentes pour le même problème. Mais le style visuel, lui, n’a pas changé — Marc Murera avait fourni les assets graphiques dès 2016, et ils sont restés les mêmes à travers les trois versions. Ce qui a changé, c’est tout le reste : l’architecture, la gestion d’état, la performance, le système de couleurs.


Le défi technique : composition SVG et couleurs

Un avatar est composé de dizaines d’éléments SVG superposés : tête, yeux, nez, bouche, cheveux, vêtements, accessoires… Chaque élément doit s’aligner parfaitement avec les autres.

Les problèmes rencontrés :

  • Alignement des éléments — Certains SVG ne se calaient pas correctement. Il a fallu beaucoup d’ajustements manuels, élément par élément.
  • Cohérence des couleurs — La couleur de peau doit se propager sur tous les éléments concernés (visage, cou, oreilles…). Idem pour les cheveux. J’ai créé un système de “groupes de couleurs” : chaque élément SVG porte des classes CSS (col-obj, skin-obj, hair-obj, shadow-obj, light-obj…) qui déterminent quelle couleur il reçoit. Quand l’utilisateur change la couleur de peau, un service JavaScript parcourt tous les éléments du groupe et modifie leur style.fill directement dans le DOM — avec des variantes calculées automatiquement (ombre à -5%, lumière à +5%, ombre forte à -10%, lumière forte à +10%). C’est du JavaScript pur, pas du CSS variables — parce que les SVG sont injectés dynamiquement et que les variables CSS ne se propagent pas facilement dans des SVG chargés à la volée.
  • Casques et visibilité — Quand on met un casque, certains éléments doivent disparaître (cheveux, oreilles…). Chaque casque SVG contient des classes qui déclarent ses règles de visibilité (no-hair-rear, no-ears, no-glasses…). Un service dédié lit ces classes, puis applique display: none aux éléments concernés. Certains casques utilisent aussi des clipPath pour masquer partiellement les cheveux plutôt que de les supprimer complètement.
  • Performance — Calculer les variations de couleur sur des dizaines de SVG peut bloquer l’interface. Ces calculs et la génération d’avatars aléatoires sont déportés dans un Web Worker.

Architecture (v3)

La version React suit une séparation claire :

Services (métier pur) :

  • svgCompositionService — Injection dynamique des SVG, cache, application des couleurs multi-couches
  • helmetVisibilityService — Gestion de la visibilité des éléments sous les casques
  • Pool de canvas réutilisables pour l’export PNG

Web Worker :

  • Calculs de variations de couleur déportés pour ne pas bloquer le thread principal

State (Zustand) :

  • Sélection des éléments par catégorie
  • Couleurs actives (peau, cheveux, yeux…)
  • Persistance localStorage

UI :

  • Sélecteurs par catégorie avec scroll horizontal (CSS Scroll Snap, plus léger que Swiper)
  • Preview en temps réel
  • Actions : Randomize, Reset, Download PNG, Share URL

Stack technique

  • React + TypeScript
  • Vite comme bundler (avec SWC)
  • Zustand pour le state management
  • Tailwind CSS en mode CSS-first
  • Web Workers pour les calculs de couleur
  • SVG + Canvas API pour la composition et l'export
  • PWA — installable, offline
  • i18n maison (français/anglais)
  • Persistance localStorage pour les avatars sauvegardés
  • Compression — Brotli + Gzip sur les assets
  • CSP — Content-Security-Policy avec hashes auto-générés

Évolutions

DateVersionDescription
Déc 20253.0Refonte React — Migration complète vers React/TypeScript, Tailwind CSS, PWA
Juil 20182.0Refonte Vanilla JS — Suppression de jQuery, modernisation du code
Déc 20161.0Version initiale — Lancement en jQuery pour la sortie de Rogue One

Bilan

Durée v3 : environ 2 mois (novembre — décembre 2025).

Ce que j’ai appris :

  • Ce que la collaboration avec Marc m’a surtout appris : quand les assets graphiques sont donnés, le code n’est plus l’enjeu principal. L’enjeu, c’est de ne pas les trahir. Aligner 300 SVG sans casser l’intention visuelle de l’illustrateur — c’est un contrat tacite qui cadre toutes les décisions techniques.
  • Migrer une application legacy vers React est faisable, mais demande de repenser l’architecture plutôt que de traduire ligne par ligne
  • La composition SVG dynamique avec gestion des couleurs est plus complexe qu’il n’y paraît

Ce que je referais pareil :

  • Réécrire plutôt que migrer progressivement — chaque version a bénéficié d’un regard neuf
  • Séparer clairement les services métier de l’UI

Ce que je changerais :

  • Difficile à dire. J’ai littéralement codé cette application trois fois de trois manières différentes. Je ne suis pas sûr de vouloir la refaire une quatrième fois.
  • J’aimerais ajouter d’autres espèces aliens — Togruta, Rodien, Chiss… mais cela demanderait de nouveaux assets graphiques.

The pitch

Star Wars Avatar is an online avatar creator for the Star Wars universe. Choose from 4 species (Human, Twi’lek, Zabrak, Mirialan) and hundreds of customization elements to create your character, then export it as PNG or share it via URL.

It’s one of the first Star Wars avatar creators online — and it has been coded three times, in three different ways.

Try it : starwarsavatar.com

Duration v3: ~2 months
Period Dec 2016 → Dec 2025
Stack
React TypeScript Zustand PWA
Status ✓ In production

Why this project

In September 2016, I contacted Marc Murera, the designer and illustrator behind @starwarsinfographic. I loved his graphic work and proposed a collaboration: create a Star Wars avatar generator for the release of “Rogue One: A Star Wars Story” in December 2016.

He accepted. He provided the graphic assets, I handled the code.

It was my first collaborative project with a designer.


Three versions, three eras

What makes this project special is its technical history:

Version 1 — jQuery (2016) The goal was to ship fast to coincide with Rogue One. jQuery was the standard at the time, it worked.

Version 2 — Vanilla JS (2018) Two years later, jQuery was becoming a burden. I rebuilt the application in pure JavaScript to eliminate this dependency and modernize the code.

Version 3 — React + TypeScript (2025) After completing Dice Roller and Grid4, I wanted to verify if I could migrate a legacy application to React. Star Wars Avatar was the ideal candidate: a project I knew inside out, with real complexity (SVG composition, color management, image export).

Each version was a complete rewrite, not a progressive migration. Three different approaches to the same problem. But the visual style didn’t change — Marc Murera had provided the graphic assets back in 2016, and they remained the same across all three versions. What changed was everything else: architecture, state management, performance, the color system.


The technical challenge: SVG composition and colors

An avatar is composed of dozens of layered SVG elements: head, eyes, nose, mouth, hair, clothes, accessories… Each element must align perfectly with the others.

Problems encountered:

  • Element alignment — Some SVGs didn’t align correctly. It required a lot of manual adjustments, element by element.
  • Color consistency — Skin color must propagate to all relevant elements (face, neck, ears…). Same for hair. I created a “color groups” system: each SVG element carries CSS classes (col-obj, skin-obj, hair-obj, shadow-obj, light-obj…) that determine which color it receives. When the user changes skin color, a JavaScript service traverses all elements of the group and modifies their style.fill directly in the DOM — with automatically calculated variants (shadow at -5%, light at +5%, strong shadow at -10%, strong light at +10%). It’s pure JavaScript, not CSS variables — because SVGs are dynamically injected and CSS variables don’t propagate easily into SVGs loaded on the fly.
  • Helmets and visibility — When wearing a helmet, some elements must disappear (hair, ears…). Each helmet SVG contains classes that declare its visibility rules (no-hair-rear, no-ears, no-glasses…). A dedicated service reads these classes, then applies display: none to the relevant elements. Some helmets also use clipPath to partially mask hair rather than removing it completely.
  • Performance — Calculating color variations on dozens of SVGs can block the interface. These calculations and random avatar generation are offloaded to a Web Worker.

Architecture (v3)

The React version follows a clear separation:

Services (pure business logic):

  • svgCompositionService — Dynamic SVG injection, caching, multi-layer color application
  • helmetVisibilityService — Visibility management for elements under helmets
  • Reusable canvas pool for PNG export

Web Worker:

  • Color variation calculations offloaded to avoid blocking the main thread

State (Zustand):

  • Element selection by category
  • Active colors (skin, hair, eyes…)
  • localStorage persistence

UI:

  • Category selectors with horizontal scroll (CSS Scroll Snap, lighter than Swiper)
  • Real-time preview
  • Actions: Randomize, Reset, Download PNG, Share URL

Tech stack

  • React + TypeScript
  • Vite as bundler (with SWC)
  • Zustand for state management
  • Tailwind CSS in CSS-first mode
  • Web Workers for color calculations
  • SVG + Canvas API for composition and export
  • PWA — installable, offline
  • i18n custom (French/English)
  • localStorage persistence for saved avatars
  • Compression — Brotli + Gzip on assets
  • CSP — Content-Security-Policy with auto-generated hashes

Timeline

DateVersionDescription
Dec 20253.0React rebuild — Complete migration to React/TypeScript, Tailwind CSS, PWA
Jul 20182.0Vanilla JS rebuild — Removed jQuery, modernized codebase
Dec 20161.0Initial version — Launched in jQuery for Rogue One release

Takeaways

Duration v3: about 2 months (November — December 2025).

What I learned:

  • What working with Marc actually taught me: when the graphic assets are given, the code isn’t the main challenge. The challenge is not betraying them. Aligning 300 SVGs without breaking the illustrator’s visual intent — it’s an unspoken contract that frames every technical decision.
  • Migrating a legacy application to React is feasible, but requires rethinking the architecture rather than translating line by line
  • Dynamic SVG composition with color management is more complex than it appears

What I’d do the same:

  • Rewrite rather than migrate progressively — each version benefited from a fresh perspective
  • Clearly separate business services from UI

What I’d change:

  • Hard to say. I’ve literally coded this application three times in three different ways. I’m not sure I want to do it a fourth time.
  • I’d love to add more alien species — Togruta, Rodian, Chiss… but that would require new graphic assets.

Settings

Language
Theme
Privacy Policy