Skip to content
Nitai AharoniNitai Aharoni← Index
2025-presentLive

Sappa

Lets online shoppers see furniture in 3D and in their own room before buying

24hfrom a shop's product list to a working viewer

The problem

People buy furniture with their eyes, and a static product photo cannot answer the question they actually have: what does this look like in my size, my fabric, my room. Retailers know this. What stops them is that every existing answer demands a 3D team, a long integration, and a rebuild of the product page.

What I built

Sappa is an embeddable visualisation widget for home-goods retailers, plus the self-serve tooling that gets a catalog into it. A shopper picks size, colour, material and options, and sees the product update live. The retailer sends a catalog and goes live on their existing store, typically within a day, with no developers on their side.

The 3D configurator: procedural geometry, live pricing, and per-part materials

One embed, three modes

The whole shopper-facing surface is a single Vite app deployed once at /configurator/, which boots into one of three modes chosen at runtime from partner config and URL params:

  • 3D configurator for three-dimensional goods like modular sofas. Real-time procedural Three.js.
  • 2D visualiser for a full-page photo catalog with room rendering.
  • 2D product widget, an inline strip that swaps colours and materials on real product photography, with no 3D model required at all.

All three share the catalog layer, internationalisation, analytics and the embed SDK. Only the 3D path pays for the engine assets. That decision is why a rug retailer and a sofa retailer can run the same product without either carrying the other's weight.

The 3D engine

Geometry is procedural, generated in code from a resolved BuildSpec, not authored per SKU. That is what makes dimension ranges possible: a shopper drags width from 180cm to 240cm and the mesh rebuilds, rather than snapping between pre-modelled variants.

The layering is strictly one-way:

host page -> embed/sdk.ts -> iframe -> configurator app
                                        ui/ (React)
                                        constraints/ + pricing/  (pure functions)
                                        engine/ (framework-agnostic Three.js)

engine/ knows nothing about React and consumes metres and hex colours. constraints/ is a pure resolve(config, model) returning a clamped config, disabled options and validation notes. pricing/ is additive option deltas. The host page owns cart and checkout; the iframe owns geometry, constraints and price, and emits the selection back over a small postMessage contract.

Modular furniture has geometry rules that are easy to get subtly wrong. Each module owns its own parts, so legs sit at each footprint rectangle's corners rather than on the overall bounding box, otherwise an L-shaped sofa grows a leg floating in the notch. The back stack orders rear to front (back frame, back cushion, seat cushion) with the seat starting in front of the back so they never intersect. A chaise removes the arm on its side, and cushions size to usable width so they never pierce an armrest.

The AI render pipeline

Studio 3D answers "what does it look like". It does not answer "what does it look like in a room". A separate variation pipeline takes the configured product and produces photorealistic room renders, so the site can show the same sofa as clean geometry and as a furnished living room side by side.

The marketing site, with the 3D and rendered views compared directly

Getting catalogs in

The part that decides whether this is a product or a consultancy is onboarding. A partner Studio takes a retailer's catalog in whatever format they already have, and a Cloud Run chat orchestrator drives the pipeline that turns products, variants, materials and product rules into a configured widget. Constraints matter commercially, not just visually: a shopper can only pick combinations the retailer actually sells, so every order that comes through is one they can fulfil.

Distribution is through embed plugins for Shopify, WooCommerce, Wix and Magento, so the install is a script tag rather than a project. Everything is bilingual, English and Hebrew, with full right-to-left support.

Building something in this territory? Start a conversation →