DEV Community

Cover image for Building a Generative Jewelry Configurator with Vanilla JS, SVG, and Numerology
Camille Guerineau
Camille Guerineau

Posted on Edited on

Building a Generative Jewelry Configurator with Vanilla JS, SVG, and Numerology

Note from the workshop-lab. The algorithmic tools, configurators and articles presented here explore lithotherapy exclusively through the lens of semiotics, cultural anthropology and generative design. This work belongs to an artistic and symbolic practice rooted in fine craftsmanship. It does not, in any way, constitute medical advice, a diagnosis, or an alternative to conventional, evidence-based therapies.

A few months ago we set out to build something that doesn't fit neatly into the usual "product configurator" template: a tool that turns your name and birth date into a personalized gemstone bracelet, lets you fine-tune every single bead by hand, and ends with a real artisan crafting the physical piece.

Loch Ness: Algorithmic System for Archetypal Determination and Variable-Geometry Mineral Synergies | Zenodo

Concept Summary (Abstract) The Loch Ness project redefines the interaction between individual psychology and lithotherapy through a proprietary digital interface. Unlike standardized, fixed-output approaches, this concept rests on two innovative pillars: an original archetypal taxonomy and a variable-geometry mineral sequencing algorithm. 1. The Ontology of the "Noble Monster" The system uses a taxonomy of original archetypes created to reflect the complexity of the human psyche, including its shadow aspects and raw power. The user is not classified according to conventional sociological or demographic criteria, but according to their "wild nature" and their capacity to channel a singular inner force. This classification produces, for each profile, a multidimensional intensity vector rather than a single label. 2. The Variable-Geometry Calculation Algorithm The application processes user data to generate a mineral response whose structure is unique to each profile: Dynamic Sequencing — the number of stones (from 3 to 8 units) is not fixed; it is determined by the algorithm based on the calculated "density" of the archetypal profile. Compensation Synergy — each stone is selected to fulfill a specific functional role (Anchor, Heart, Mind, Shield, Momentum), creating a bespoke vibrational armor rather than an arbitrary assembly. This role-to-stone indirection allows the role nomenclature and the mineral catalog to evolve independently, without recalibrating the entire system with each addition. 3. Algorithmic Pipeline Processing relies on a strictly decoupled three-stage functional pipeline, each stage independently testable: Identity Normalization — identity data (first name(s), last name, date of birth) is transformed into a multidimensional profile vector (intensity, shadow aspect, momentum, stability), with no dependency on rendering or the interface. Density Calculation and Slot Count Resolution — a density function aggregates the profile vector into a scalar score, which is then projected onto the integer interval [3, 8] to dynamically determine the length of the mineral sequence. Role Resolution, then Mineral Selection — for each slot, a functional role is resolved first (Anchor, Heart, Mind, Shield, Momentum), and a stone is then selected from the catalog to fulfill that role in light of the profile vector. 4. Software Architecture The system is implemented as a static single-page web application (SPA), with no dependency on a JavaScript framework, and features the following technical characteristics: Stack — PHP, HTML5, CSS3 (custom properties), vanilla native JavaScript; no dependency on any rendering framework. Generative Rendering Engine — each mineral in the catalog is rendered as a dynamically relying on a static image bank. Dynamic Geometric Layout — the position of each stone on the support (bracelet) is calculated trigonometrically based on its index and the total number of slots resolved by the algorithm (a variable N, not a constant), with automatic bead-size scaling according to the sequence's density. State Management — the composition state is represented as an ordered array of beads, with undo/redo history stacks and targeted re-rendering (rather than a full re-render) on each mutation, to preserve smoothness on mobile. Progressive Web App — an installation manifest (icons, theme color, standalone mode) and a Service Worker providing static resource caching and partial offline resilience. Structured Data — Schema.org markup (SoftwareApplication, FAQPage) for enriched indexing, in addition to visible HTML content. Full architecture documentation (flow diagrams, justified technical choices) along with simplified code examples for educational purposes are published separately. The actual normalization tables, the density function, the role-resolution thresholds, and the complete mineral catalog are not published and constitute the proprietary core of the system. Purpose of This Filing This document records the intellectual property of the algorithmic logic, the archetype nomenclature, and the mineral selection methodology associated with the Loch Ness brand. It protects the invention of a personalization system in which technology becomes the bridge between an individual's deep identity and the talismanic object. Live application: healing crystal bracelets configurator with lithotherapy score  

favicon zenodo.org

The result is Loch Ness™, the engine behind Loch Ness Paris' crystal bracelet configurator. This post walks through the architecture, the technical trade-offs, and a few of the more interesting problems we had to solve — without giving away the proprietary parts (the numerology algorithm and the full gem-rendering engine stay closed source, but the shape of the system is worth sharing).
If you want to dig deeper, the architecture documentation and a few simplified code examples are public on GitHub: application-configurateur-de-bracelets-en-pierres-fines.
The brief, in one sentence

Turn an identity (first name, last name, birth date) into 8 symbolic gemstones, let the user build a real bracelet around them bead by bead, and hand the final design off to a craftsperson.
No accounts, no backend database of users, no checkout — just a fast, installable web app that ends in a personalized request sent to a human artisan.
Why no framework?
This was a deliberate choice. The whole app — numerology engine, SVG bead renderer, drag-to-build canvas, smart suggestions, cart — is built in php, vanilla JavaScript, plain CSS, and a single HTML file.
Three reasons drove that decision:
Load time matters more than developer convenience here. A big chunk of traffic comes from organic/mobile search for terms like "bracelet chemin de vie." Every extra hundred kilobytes of framework runtime is a few more bounces.
The DOM tree is genuinely simple. Four tabs, one SVG canvas, a handful of lists. State management doesn't need a library when the state is "an ordered array of beads plus some UI flags."
PWA installability and offline behavior are easier to reason about when you fully control the bootstrapping sequence instead of going through a framework's hydration lifecycle.
That said — vanilla JS at this scale means you have to be disciplined about state, which brings us to the next point.
State management without a framework
The entire bracelet is represented as an ordered array of bead objects. Every mutation (add, remove, reorder, change size) goes through a small set of functions that:
update the array,
push the previous state onto an undo stack,
re-render only the parts of the SVG that changed.
That last point matters a lot for performance: with up to ~19 beads rendered as gradient-filled SVG circles, a naive full re-render on every drag event is noticeable on mid-range phones. Re-rendering only the affected bead (and recalculating positions trigonometrically around the guide circle) keeps things smooth.

// Simplified illustration of bead positioning on the guide circle
function getBeadPosition(index, total, radius, center) {
  const angle = (index / total) * 2 * Math.PI - Math.PI / 2;
  return {
    x: center.x + radius * Math.cos(angle),
    y: center.y + radius * Math.sin(angle),
  };
}
Enter fullscreen mode Exit fullscreen mode

Undo/redo is just two stacks of array snapshots — simple, but it's the kind of "boring technology" that makes a configurator feel trustworthy. Users mis-click constantly; cheap undo is a UX feature, not a nice-to-have.
Generating gemstones instead of photographing them
This is the part I find most interesting. With 70+ stone types in the catalog, maintaining a photo library (multiple angles, lighting consistency, file size, retina variants…) would have been a maintenance nightmare.
Instead, every bead is a procedurally generated SVG. Each stone type has a "preset" describing its visual family (translucent crystal, opaque mineral, banded stone, metallic finish…), and each individual bead instance gets a random seed that introduces small variations — hue jitter, gradient stop shifts — so that no two beads of the same stone type look perfectly identical, the same way no two real gemstones do.
A heavily simplified version of the idea:

function renderBead({ id, baseHue, seed }) {
  const rng = seededRandom(seed);
  const hue = baseHue + (rng() - 0.5) * 12; // small natural variation

  return `
    <radialGradient id="grad-${id}" cx="40%" cy="35%" r="65%">
      <stop offset="0%"  stop-color="hsla(${hue}, 45%, 75%, 1)" />
      <stop offset="60%" stop-color="hsla(${hue}, 45%, 55%, 1)" />
      <stop offset="100%" stop-color="hsla(${hue}, 45%, 35%, 1)" />
    </radialGradient>
    <circle cx="50" cy="50" r="48" fill="url(#grad-${id})" />
  `;
}
Enter fullscreen mode Exit fullscreen mode

The production renderer is considerably more involved — it layers multiple gradients, clip paths, and noise patterns per mineral family to approximate veining (think lapis lazuli or labradorite) and translucency — but the core trick is the same: vector + seed beats a static image library when you need infinite, lightweight variation.
The numerology layer
The app's signature feature is the "Life Path Bracelet": you type in a first name and a birth date, and the engine computes 8 symbolic stones — Foundation, Summit, Life Path, Calling, Personality, Expression, Final Touch, and Wish — each tied to a different facet of numerology.
I won't detail the letter-to-number mapping or reduction rules here since that's the proprietary core of the product, but structurally it's a pure function:

identity (name + date) → numeric reduction → archetype (1–9) → stone(s)
Enter fullscreen mode Exit fullscreen mode

Keeping it as a pure, side-effect-free transformation made it trivial to unit test and to keep completely decoupled from the rendering and cart logic. The numerology module has no idea an SVG even exists.
Smart suggestions and the "litho score"
Beyond manual bead-picking, there's a "Smart" tab with:
Harmonious palettes — pre-grouped stones by color coherence,
Predefined themes — ready-made compositions for intents like "protection" or "calm,"
A coherence score that evaluates how energetically consistent a user's manual selection is.
These are all derived/precomputed layers sitting on top of the same stone catalog — no real-time AI inference, just well-structured data and some scoring heuristics. It's a good reminder that "smart suggestions" don't always need a model; sometimes a well-curated lookup table does the job at a fraction of the latency and cost.
PWA bits that actually mattered
A few small, unglamorous details ended up making a real difference on mobile:
touch-action: manipulation on all interactive elements to kill the old 300ms tap delay.
Loading the webfont with media="print" then switching to all on load, so it never blocks first paint.
A Service Worker caching static assets for offline resilience and faster repeat visits.
A manifest.json so the app can be installed straight from the browser, no app store round-trip.
None of this is novel, but it's the kind of checklist that's easy to skip under deadline pressure — and it's exactly the stuff that determines whether a configurator feels like an app or like a website pretending to be one.
From pixels to a physical object
The configurator deliberately doesn't end in a checkout button. Once a composition is validated, the user lands on a recap + contact form, and the actual fulfillment is handled by a human artisan partner who crafts the bracelet by hand using the validated design as a spec sheet.
That constraint shaped a lot of UI decisions — for instance, the cart view always shows an estimated price range rather than a fixed price, since the final quote depends on material choices (precious metal findings, natural pearls, etc.) confirmed with the artisan.
What's public, what isn't
We open-sourced the documentation and architecture of this project, along with a few deliberately simplified code examples, in a public GitHub repo. What you'll find there:
a full architecture breakdown (diagrams included),
a feature-by-feature functional spec,
simplified illustrative examples of the numerology pattern and the SVG bead rendering pattern (not the production algorithms),
a roadmap and contribution guidelines.
What stays closed: the actual numerology letter/reduction tables, the full multi-preset rendering engine, the complete stone catalog, and the litho-score algorithm — those remain Loch Ness®'s IP.
Try it
The live configurator is here: lochness-paris.com/configurateur-de-bracelet.html
The project is also archived and citable via Zenodo: zenodo.org/records/19836838
If you're into vanilla-JS architecture, generative SVG, or PWA details, I'd genuinely love feedback — open an issue on the repo or drop a comment below.

Top comments (0)