User Guide

Building visualizer projects with Tilvora

Everything you need to install Tilvora, publish a 3D floor visualizer, stock a Materials Library, and manage the quote requests that come back in — from your first GLB upload to your first quote reply.

What is Tilvora

Tilvora adds a full-screen, real-time 3D floor & wall visualizer to any WordPress site. A visitor rotates, zooms, and customizes a room — choosing tile or wallpaper designs from your own catalog — and sees every change rendered instantly in 3D. When they're happy with a design, they submit a quote request that lands in your inbox and in a dedicated Quote Inbox screen inside wp-admin.

Each Tilvora Visualizer project is independent, with its own 3D model and settings, and is embedded anywhere with a single shortcode. There's no WooCommerce dependency — Tilvora works on any WordPress site on its own.

The full-screen Tilvora visualizer showing a room with a floor tile and a wallpaper applied, and the Floor/Wall material panel open on the right.
The full-screen visualizer — a customer picks a floor tile and a wall material and sees both applied in real time.

The 3D engine (Three.js) and its Draco decoder are bundled with the plugin and served entirely from your own site. Tilvora makes no calls to any CDN or third-party service — every asset the visualizer loads comes from your own server.

Installation

  1. Upload the plugin. In wp-admin, go to Plugins → Add New → Upload Plugin and choose the Tilvora zip file, or upload the plugin folder to /wp-content/plugins/ via FTP/SFTP.
  2. Activate it. From the Plugins screen, click Activate under Tilvora — 3D Flooring Visualizer.
  3. Open Tilvora. A new Tilvora item appears in the left-hand wp-admin menu, with your visualizer projects, Materials Library, and Quote Inbox underneath it.
RequirementMinimum
WordPress6.0+
PHP7.4+
WooCommerceNot required — Tilvora is fully standalone
Visitor's browserWebGL support (all modern desktop and mobile browsers). Where WebGL isn't available, the visualizer shows a friendly error instead of a blank screen.

No other plugin is required, and activation doesn't change anything on your live pages until you actually publish a visualizer project and place its shortcode.

Your first visualizer

You can have a working visualizer live in under a minute using Tilvora's bundled sample tile model — no 3D model or catalog of your own required yet.

  1. Go to Tilvora → Add New. Give the project a title (e.g. "Living Room Floor").
  2. Leave 3D Model and Config JSON blank. Tilvora falls back to its bundled sample model and default settings automatically, so the visualizer works immediately.
  3. Click Publish. The metabox now shows a Visualizer URL you can open directly, and an Embed Shortcode like [tilvora id="42"].
  4. Paste the shortcode into any page or post. It renders a "Design Your Floor" button that opens the full-screen visualizer.

From here, the two things worth customizing per project are your own 3D model and your own Materials Library — everything else (camera, tabs, pricing, branding) is optional and lives in the Config JSON.


Projects & embedding

The project editor

Every visualizer lives on its own project (Tilvora → Add New / edit an existing one). Each project is listed under Tilvora in the wp-admin menu, alongside its publish status:

The Tilvora visualizer projects list in wp-admin, showing two published projects.
Tilvora → Visualizers — every project on the site, at a glance.

The Tilvora — Visualizer Settings metabox on a project's edit screen has three parts.

The Tilvora Visualizer Settings metabox on a project's edit screen, showing the Visualizer URL, shortcode, 3D Model picker, and Config JSON box.
The Visualizer Settings metabox on a project's edit screen.

Visualizer URL & shortcode

Appears once the project is published: a direct link to the full-screen visualizer, and the [tilvora id="X"] shortcode for embedding it on any page or post.

3D Model

Upload a .glb file for this project via the media library picker (Select GLB Model). If you don't upload one, the project uses Tilvora's bundled default model (floor.glb). Click Remove to go back to the bundled default at any time. See Preparing a GLB model for what makes a model work correctly.

Config JSON

An advanced, optional settings block for this project — starting camera angle and zoom limits, which tabs and controls appear in the side panel, UI text/branding overrides, and which mesh names map to which controls. Leave it blank to use the bundled default. The toolbar above the box gives you:

  • Load default template — click once to arm it, click again within a few seconds to overwrite the box with the bundled default JSON (a safe starting point to edit from).
  • Load from file… — read a .json file from your computer straight into the box.
  • Validate JSON — checks the box's current contents are valid JSON without saving.

The box is saved automatically (via a background request) the moment you click Publish or Update — you don't need to click a separate save button for it. If what you entered isn't valid JSON, Tilvora keeps using the last good version (or the bundled default) and shows an inline error on the edit screen until it's fixed.

Most projects never need to touch the Config JSON box at all — add your tile and wallpaper products under Tilvora → Materials Library instead. Only open this box for things the Materials Library doesn't cover: the starting camera view, custom branding text, or adding a control type beyond the material grid.

Shortcode & embedding

Paste the shortcode shown on a published project into any page, post, or widget area that renders shortcodes:

[tilvora id="42"]

It renders a styled "Design Your Floor" button that links to the full-screen visualizer for that project. You can override the button's label per placement:

[tilvora id="42" label="Try Our Tile Designer"]

The shortcode outputs nothing if the id doesn't match a project, or if that project isn't published — so it's safe to leave a shortcode in a draft page without it showing a broken button.

You can place the same shortcode (same id) on as many pages as you like, and run any number of independent projects — each with its own shortcode — across the site at once.

About the Config JSON

The Config JSON is what drives the visualizer engine: what tabs appear, what each tab's controls do, which GLB mesh each control affects, the starting camera framing, and the text shown in the UI chrome. A full field-by-field breakdown is in the Config JSON reference at the end of this guide — this section covers the parts you're most likely to actually change.

Starting camera view

"camera": {
  "fov": 50,
  "distanceMultiplier": 0.268,
  "angleX": 0.028,
  "angleY": 1.714,
  "minPolarAngle": 0.2,
  "maxPolarAngle": 1.35
}

distanceMultiplier controls how far back the camera starts (relative to the model's size); angleX/angleY nudge the starting position sideways/upward; minPolarAngle/maxPolarAngle (in radians) limit how far a visitor can orbit up or down, so they can't flip the camera under the floor or too far overhead.

Branding & UI text

"uiText": {
  "brand": "Tilvora",
  "subtitle": "3D Tile Visualizer",
  "resetView": "Reset View",
  "exportPng": "Save Image",
  "addToCart": "Get a Quote",
  "resetAll": "Reset",
  "totalPriceLabel": "Total"
}

Every value here is optional and falls back to the built-in English label if omitted — override just the ones you want to change.

Tabs & controls

The uiTabs array defines the side panel, tab by tab. Each project's default JSON already includes a Floor and a Wall tab, each with one material-grid control pulling from your Materials Library. See Control types for every control type available if you want to add color pickers, finish swatches, scene lighting toggles, or a text-personalization field.


Materials Library

Adding a material

The Materials Library (Tilvora → Materials Library) is a shared catalog of tile, wallpaper, or other surface products. Add a material once and it's available to every visualizer project on the site — no Three.js, UV mapping, or JSON editing needed. You fill in the specs already printed on the manufacturer's own data sheet, and Tilvora works out the correct real-world texture scale automatically.

  1. Tilvora → Materials Library → Add New. Give it a title — this is the name customers see.
  2. Upload a Product Image. One photo is enough — see Tile & wallpaper images for what makes a good one.
  3. Fill in the Product Specification fields (below) and Publish.
The Materials Library list in wp-admin, showing a grid of published tile products with their thumbnail, category, target, and price columns.
Tilvora → Materials Library — every product available to every project, in one shared catalog.
The edit screen for a single material, showing the Product Specification fields (SKU, Category, Finish, Price, Width, Height, etc.) and the Product Image panel.
A single material's edit screen — the specs come straight off the manufacturer's data sheet.
FieldWhat it's for
SKUYour own product code, for reference only.
CategoryFree text, e.g. "Marble", "Ceramic Tile", "Wallpaper" — shown in the admin list, not to customers.
FinishFree text, e.g. "Polished", "Matte" — reference only.
Price / Price UnitAdded to the visualizer's live price total when this material is selected. Unit is display-only text, e.g. .
Width (cm) / Height (cm)For a tile: the tile's own physical width/height. For wallpaper: the roll width and the pattern repeat length. This is what the renderer uses to compute correct tiling — not the image file's pixel size.
Thickness (mm)Reference only; not used for rendering.
Roll Length (cm) / Roll Coverage (m²)Wallpaper only. Not used for rendering — only for your own roll-quantity estimates.
Applies To (mesh target)Which control this material shows up under — must match a meshTargets key in the project's config (typically floor or wall). See Preparing a GLB model.
Mapping ModeRepeat (tile/wallpaper — the standard mode) or Fit (reserved for a future non-repeating product type; currently just skips tiling).

Only published materials are served to the visualizer. Save one as a draft to keep working on it without it appearing to customers yet.

Tile & wallpaper images

The Product Image is uploaded through the standard WordPress media library, so any format WordPress accepts works: JPG, PNG, or WebP. What matters far more than the file format is what's in the photo, because of how the renderer uses it.

The visualizer doesn't scale the image based on its pixel dimensions. It repeats the image across the mesh using the physical Width (cm) / Height (cm) you enter on the material — so the photo itself needs to be a clean, tileable, square-on crop of the material for the repeat to look seamless.

  • Seamless / tileable. Use a straight-on, evenly cropped photo (or a proper seamless texture) of the repeating pattern. A photo with visible grout lines only on some edges, a shadow, or a vignette will show a visible seam every time it repeats.
  • Square, or matching the material's own aspect ratio. A tile that's square in real life should be photographed square; a rectangular tile or wallpaper repeat should keep that same width:height ratio in the crop.
  • Evenly, neutrally lit. Materials render unlit — the customer sees the photo's true printed color, unaffected by the 3D scene's lighting. A photo with strong directional shadows or a color-cast light source will carry that straight into the render.
  • High resolution. A reasonably large square image (around 1024×1024 up to 2048×2048 px) stays sharp when a customer zooms in. There's no hard minimum, but low-res photos will look blurry up close.
  • Accurate dimensions. Double-check the Width/Height (cm) fields match the real product. Getting these wrong is the most common cause of a tile that looks stretched, too large, or too small once applied.

Duplicating a material

To add a new colorway or size of a product you've already entered, don't start from scratch. From the Materials Library list, hover a row and click Duplicate (or use the Duplicate button on the material's own edit screen). This creates a new draft with every field and the product image copied over — just change the title, image, and whichever spec differs, then Publish.


The 3D model

Preparing a GLB model

Tilvora accepts .glb (glTF binary) models exported from Blender or any similar 3D tool — it's not hardcoded to one mesh or product. Draco-compressed geometry is supported (the decoder is bundled with the plugin).

Mesh names must match your meshTargets

The Config JSON's meshTargets object maps a logical key (used by controls, e.g. "floor") to the exact name of a mesh node inside your GLB:

"meshTargets": {
  "floor": "Floor",
  "wall": "Wall"
}

This is an exact, case-sensitive match against the mesh's name as exported — not a partial or fuzzy match. If a name doesn't match anything in the loaded model, that target's controls simply won't have anything to apply to (check your browser console for a warning naming the missing mesh). In Blender, rename the relevant mesh objects (not just the containing collection) to exactly what your meshTargets values expect before exporting.

Model scale & UV unwrap

Tilvora computes each material's tiling automatically from two things: the mesh's own real-world bounding-box size, and the material's physical Width/Height (cm) from the Materials Library. For that to come out correct:

  • Export the model at true real-world scale (1 Blender unit = 1 meter is the glTF convention) — a floor mesh that's actually 4m × 5m should measure 4 × 5 in your 3D tool before export, not an arbitrary scale fixed up later.
  • Give the floor/wall mesh a clean, non-overlapping UV unwrap so the repeated texture tiles evenly across it rather than distorting at seams.

Testing a model live

Open any visualizer's full-screen URL and drag a .glb or .gltf file from your computer straight onto the page. It loads immediately as a live, local preview — nothing is uploaded or saved anywhere. Use this to check your mesh names and materials line up correctly before uploading the model properly through the project's 3D Model field. Refresh the page (or navigate away) to discard the test model and go back to whatever's actually configured for that project.


Customer experience

The visualizer screen

The full-screen visualizer is a standalone page (it doesn't use your theme's header/footer) with:

Top bar

Brand name (links back to your site), the current project's title, Reset View, a light/dark theme toggle (remembered per visitor), and Export PNG.

Side panel

One tab per entry in uiTabs — Floor and Wall by default, each showing a grid of your published Materials Library products for that target.

Price bar

Live running total with a line-item breakdown of anything carrying a price, and the Get a Quote button.

Reset All

In the panel footer — clears every selection back to the project's defaults.

On phones and small screens, the side panel becomes a draggable bottom sheet the visitor can collapse, expand halfway, or expand fully.

A visitor's selections are remembered in their browser between visits to the same project, so they can leave and come back without starting over. Reset All clears this saved state.

Requesting a quote

Clicking Get a Quote captures a snapshot of the customer's current 3D view and opens a form:

  • Full Name and Email (required)
  • Phone and Postcode (optional)
  • Notes (optional) — free text for installation dates, special requirements, etc.

Above the form, the customer sees a chip for each of their current selections (e.g. their chosen floor tile and wall material) with its thumbnail. On submit, the request — including the design snapshot and the live price total — is saved to the Quote Inbox and two emails go out: one to your site's admin address, and a confirmation to the customer.

The Request a Quote modal, showing selection chips for the chosen floor and wall materials above a form with Full Name, Email, Phone, Postcode, and Notes fields filled in.
The quote form — the customer's current selection is shown above it, pulled live from the visualizer.
The quote modal's success state, showing a checkmark, 'Quote Request Sent!', and a summary of the selected materials.
Confirmation shown immediately after a successful submission.

Quote Inbox

Managing quotes

Tilvora → Quote Inbox lists every submitted quote with the customer's contact details, their selection, and the price total. It supports:

  • Status tabs — All / New / Replied / Completed, with a live count next to each.
  • Search — matches against customer name or email.
  • Sorting — by customer, status, or date received.
  • Bulk actions — mark as Replied, mark as Completed, or Delete across multiple selected quotes at once.
The Quote Inbox list showing a customer row with their name, email, phone, a design thumbnail, their floor and wall material selection, project, status badge with inline status-change links, and received date.
Tilvora → Quote Inbox — every submitted quote, with its design snapshot and status controls inline.

Open a quote to see its full detail card: the customer's contact info, their design snapshot (downloadable), their full selection, price, and any notes. Status can be changed inline from the list or the detail view — this updates instantly via AJAX, with a plain link fallback if JavaScript is unavailable. The badge next to the Quote Inbox menu item shows how many quotes are currently New.

A single quote's detail view, showing the status bar with Mark New/Replied/Completed links, the customer's contact card, and their design snapshot.
A quote's detail view — everything needed to follow up, in one place.

A new pending count only appears once a quote has actually been submitted — the count doesn't include drafts or anything not yet sent.

Email notifications

Every submitted quote triggers two emails, sent via your site's own wp_mail() configuration (no third-party email service is involved):

  • To your site's admin email — the customer's contact details, their full selection, room/price info if provided, and their notes. Its Reply-To header is set to the customer, so replying goes straight to them.
  • To the customer — a confirmation summarizing their request, with Reply-To set to your admin address.

These are sent a moment after the quote is saved (via WP-Cron) rather than while the customer waits, so a slow outgoing-mail connection never delays their "Quote Request Sent!" confirmation on screen. If emails aren't arriving, see Troubleshooting.


Reference

Control types

Every control in a tab's controls array has a type, an id, a label, and a cfgPath (the dot-notation path where its current value is stored, e.g. "floor.materialId"). Beyond that, each type takes its own fields:

TypePurposeKey fields
material-gridThumbnail grid of Materials Library products. What the default Floor/Wall tabs use.target (matches a meshTargets key)
color-swatchesRow of solid-color swatches applied straight to the mesh's material color.target, swatches: [{value, label, priceModifier?, roughness?, metalness?}]
finishCard grid for finish presets combining color + roughness/metalness (e.g. matte vs. gloss).target, options: [{value, label, color?, roughness?, metalness?, priceModifier?}]
material-presetNamed presets defined once under the config's top-level materialPresets and referenced by key.target, options: [{value, label}]
env-gridScene background/environment picker (defined under top-level environments).options: [{value, label, cssClass}]
switchOn/off toggle wired to a viewer effect.effect (see below)
sliderNumeric range wired to a viewer effect.effect, min, max, scale?, displayUnit?
text-inputFree-text field (e.g. an engraving/personalization line). Never affects the 3D model; only appears in the quote's field list and optionally adds its own price.priceModifier?

switch and slider controls take an effect key from a fixed set: environment, ground, shadows, autoRotate, ambientLight, keyLight, exposure, environmentIntensity. Any control can add a priceModifier (a number added to the running total when that value is selected) except material-grid, which prices itself from the selected Materials Library product, and env-grid/switch/slider, which don't carry a price.

By default, a customer's material-grid, color-swatches, finish, material-preset, and non-empty text-input selections are included in their quote request; env-grid, switch, and slider (scene/viewer settings, not part of what they're ordering) are excluded. Set "includeInOrder": true or false on any control to override this.

Config JSON reference

Top-level fields a project's Config JSON can set. Anything omitted falls back to the bundled default.

FieldDescription
idSet automatically to the project's post ID — used as the storage key for a visitor's saved selections.
productNameSet automatically to the project's title.
currencySymbol prefixed to every price shown, e.g. "$".
basePriceStarting price total before any selection is added.
modelPathPath/URL to the GLB model. Overridden automatically if a model is uploaded via the project's media picker.
camerafov, distanceMultiplier, angleX, angleY, minPolarAngle, maxPolarAngle — see About the Config JSON.
meshTargetsMaps each logical target key to the exact mesh name in the GLB. See Preparing a GLB model.
defaultsThe starting value of every cfgPath, applied before any saved visitor state.
materialPresetsNamed {color, roughness, metalness} presets referenced by a material-preset control.
environmentsNamed scene backgrounds ({color, fog?}) referenced by an env-grid control.
uiTabsThe side-panel tabs and their controls — see Control types.
uiTextUI label overrides — see About the Config JSON.

Tab icons (the small SVG shown per tab) accept a limited set of SVG shape tags — svg, path, rect, circle, line, polyline, polygon, g — with their common presentation attributes. Anything outside that allowlist is stripped when the project is saved.

Frequently asked questions

Does this require WooCommerce?

No. Tilvora is fully standalone and works on any WordPress site.

What image format should my tile/wallpaper photos be?

JPG, PNG, or WebP all work — Tilvora uses the standard WordPress media library. What matters more is that the photo is a seamless, square-on crop of the material at the physical size you enter in Width (cm)/Height (cm). See Tile & wallpaper images.

Does this load anything from a CDN?

No. Three.js and the Draco decoder are bundled locally with the plugin and served from your own site.

Can I run multiple different visualizers on one site?

Yes — each project under Tilvora → Add New is independent, with its own model, Config JSON, and shortcode.

How do customers request a quote?

They click Get a Quote in the visualizer, fill in their name and email (phone/postcode/notes are optional), and submit. The request is emailed to your admin address, a confirmation goes to the customer, and it's saved in Tilvora → Quote Inbox.

What happens on a browser without WebGL?

The loader shows a friendly error message instead of a blank screen.

Where do materials come from — do I add them per project?

No — the Materials Library is shared site-wide. Add a material once under Tilvora → Materials Library and it becomes available to every project whose meshTargets includes a matching target.

Troubleshooting

The shortcode shows nothing on the page

The shortcode only renders once its project is published (not a draft) and the id in the shortcode matches an existing project. Check Tilvora → All Visualizers for the correct ID and status.

A material doesn't appear in its tab

Confirm the material is published, and that its Applies To (mesh target) field matches one of the project's meshTargets keys exactly (e.g. floor). A material set to a target the project's config doesn't define won't show up on that project.

A material shows in the panel but doesn't appear on the model

This almost always means the mesh name in meshTargets doesn't exactly match a mesh node name inside the uploaded GLB. Check your browser's developer console for a warning naming the mesh Tilvora couldn't find, and confirm the name (case included) against what your 3D tool exported. See Preparing a GLB model.

The tile texture looks stretched or has a visible seam

Usually one of: the material's Width (cm)/Height (cm) don't match the real product, the source photo isn't seamlessly tileable, or the GLB's floor/wall mesh wasn't exported at true real-world scale. See Preparing a GLB model and Tile & wallpaper images.

Config JSON won't save

Click Validate JSON in the metabox to see the exact parse error. Tilvora refuses to save invalid JSON and keeps the previous working version (or the bundled default) active until it's fixed, so a typo here never takes the live visualizer down.

Quote request emails aren't arriving

Quotes are saved to the Quote Inbox immediately regardless of email delivery, so check there first to confirm the submission itself worked. Email delivery goes through your site's normal wp_mail() setup (the same path as password-reset emails, etc.) and is scheduled via WP-Cron a moment after saving — if your site's WP-Cron isn't running reliably (common on very low-traffic sites, since default WP-Cron only fires on page loads), or your host's outgoing mail isn't configured, emails can be delayed or dropped. An SMTP plugin is the usual fix if your host's default mail sending is unreliable.