Blog ·

How we built the keychain configurator

A customer types a name, picks a font and a couple of colors, and watches a 3D keychain take shape in the browser. When the design looks right, they add it to the cart. We print it and ship it. That is the whole product, and it is also a clean test of how fast we can take an idea to something real. The configurator forces a few hard problems into the open: live 3D rendering, generating a real print file in the browser, and getting that file safely into a WooCommerce order. Solve those, and you have a working custom product running inside an actual shop, not a demo.

This is a disip build. disip is the digital label of Van Riel Online Services, a Rotterdam studio for rapid development and digital solutions. The keychain configurator is how we show what that means: a complete, working custom product, taken from idea to live shop in a short time.

Below is how it was built, what each part does, and what we want to improve next.

The configurator: designing in the browser

The editor is called Keychain Studio. It is a React app with a Three.js scene at its core. The customer interacts with a small set of controls: a name field, a font, and colors. Every change feeds straight into the 3D model, so the WebGL preview updates in real time as they type and pick. There is no “generate” button to wait on and no server round trip to see the result. What they see in the preview is the object that will be printed.

Keeping the preview honest is the point. The geometry the customer rotates on screen is the same geometry that becomes the print file, so the design step and the production step share one source of truth instead of two that can drift apart.

  • React drives the interface and state for the name, font, and color choices.
  • Three.js renders the live WebGL preview and builds the keychain geometry.
  • Real-time updates mean every keystroke and color change is reflected in the 3D view immediately.

From widget to web shop

Keychain Studio lives in its own repository, separate from the shop. That separation is deliberate. The widget can be developed, built, and reasoned about on its own terms, without dragging the WordPress stack along for every change to a control or a piece of geometry.

The build step (npm run build:embed) compiles the whole React and Three.js app into a single UMD bundle, one JavaScript file ready to drop in anywhere. On the shop side, the site runs WordPress and WooCommerce on the Twenty Twenty-Five block theme, PHP 8.4, HPOS orders, behind Cloudflare. A small custom plugin, keychain-3d, loads that bundle and registers a custom block. The block is placed on a dedicated product-page template, so the configurator mounts exactly where it belongs and nowhere else.

The result is a clean seam: the widget knows nothing about WooCommerce, and the plugin knows nothing about Three.js. They meet at one file and one block.

The ordering flow

A preview means nothing if the order does not carry the actual design. So the moment a customer adds the keychain to the cart, the widget generates a .3mf file, the 3D print format that holds the model. That file is the deliverable, and the rest of the flow exists to keep it attached to the right order.

  • On add-to-cart, the widget produces the .3mf and sends it to a REST endpoint.
  • The endpoint stores it first in a temporary folder, keyed to the cart, not yet to an order.
  • At checkout the file is moved into a per-order folder and attached to the WooCommerce order as a download.
  • This works on both the classic checkout and the newer Store-API checkout, so the design follows the order whichever path the customer takes.

The price is fixed at €4,50 and enforced on the server. The browser can ask for whatever it likes; what reaches the order is what the server decides. That keeps the price honest no matter what happens on the client.

Iterating fast

The two-repo setup pays off in the loop from idea to live. Every change runs through the same short path, and the path is boring on purpose: boring means repeatable, and repeatable means fast.

  1. Change the widget in its own repository.
  2. Run build:embed to produce the UMD bundle.
  3. Copy the bundle into the plugin.
  4. Bump the version number, which expires stale caches and re-syncs the block theme template.
  5. Push to live.
  6. Verify in the browser.

The version bump matters more than it looks. Skip it and the browser happily serves the old bundle, so a change you made never reaches anyone. Tie cache-busting and template sync to one number and that whole class of “but it works locally” confusion goes away.

Rapid development is not heroics. It is a short, repeatable loop you can run all day without breaking the live site.

What is next

The flow is live and orders carry their designs. Here is what comes next to make it sturdier.

  • Clean up temporary uploads automatically. Designs that never reach checkout leave files in the temporary folder; a scheduled cleanup keeps storage tidy on its own.
  • Move heavy geometry to a Web Worker. Long names take roughly 0.6 to 1 second to rebuild. Pushing that work off the main thread keeps the interface responsive while the model regenerates.
  • Validate against design-less orders. An extra check makes sure a keychain cannot be ordered without an actual design attached, so every order that lands is one we can print.

See it for yourself

The fastest way to understand the configurator is to use it. Design a keychain, watch the 3D preview follow along, and download the real file. If you want a working custom product like this for your own shop, disip can build it. Get in touch.