@vivekcsein-logo
  • Home
  • About
  • Development

    • Web Development
    • Performance & Optimization
    • Backend & APIs
    • Authentication & Security

    Specialized

    • SEO & Ad Monetization
    • AR Experiences
    • Animation
    • Figma to Code
  • Articles
  • Projects
  • Marketplace
  • Contact
@vivekcsein-logo

A portfolio full stack developer with a passion for building scalable and high-performance web applications.

Explore

  • Home
  • About

Services

  • Web Development
  • Backend & APIs
  • Performance Optimization
  • Security & Authentication

Connect

  • Contact
  • Privacy
  • Terms
  • Home
  • About
  • Web Development
  • Backend & APIs
  • Performance Optimization
  • Security & Authentication
  • Contact
  • Privacy
  • Terms

© @vivekcsein. All rights reserved.

  • Home
  • All Articles47
  • Featured
  • Recently Added
  • Most Read
  • Bookmarks
Topics
  • Interview3
  • 3d4
    • 3D Homepage Models
    • Setting Up 3D Elements (GLB Models)
    • Creating 3D Models with Python Prompts in Blender
    • Vivek Portfolio --- Blender 3D Model Prompt Library
  • Ai Prompts2
  • Business3
  • Deployment1
  • Dev2
  • Frontend5
  • Getting Started2
  • Security2
  • Seo2
  • Workflow10
  • Backend1
  • Deployment1
  • Security1
  • Javascript1
  • Client Advisory5
  • Engineering2
Collections
  • Docs
  • Tutorials
  • Resources
  • Articles
“A better developer every single day.”
— Vivek
  1. Docs
  2. 3d
  3. Setting Up 3D Elements (GLB Models)
3d

Setting Up 3D Elements (GLB Models)

How a GLB gets onto the site: optimize it with one command, register it in model3d.config.ts, tune it live in the dev Model lab, then place it with ClientModelViewer.

Updated Sep 12, 20266 min read
On this page

On this page

  • How it fits together
  • 1. Getting the file from your designer
  • 2. Optimize
  • 3. Register and tune it
  • 4. Sizing
  • 5. Animation presets
  • 6. Effects
  • 7. Placing it on a page
  • 8. Performance and security notes
  • Troubleshooting

How to take a .glb file from Blender (or your 3D designer) and get it on the site — optimized, correctly sized, positioned, animated and themed — without writing new Three.js/R3F code each time.

How it fits together#

text
models-src/*.glb                      ← raw exports from Blender (keep these)
        │  bun run models:optimize
        ▼
public/models/*.glb                   ← web-ready files the site serves
src/packages/configs/model3d.config.ts   ← one entry per model: size, position, animation, effects
src/packages/configs/models.manifest.ts  ← auto-generated list of files that exist (models:sync)
src/components/features/models/
  ClientModelViewer.tsx   ← USE THIS in pages (lazy, SSR-safe, pauses off-screen)
  ModelViewer.tsx         ← Canvas + lights + model + effects
  GlbModel.tsx            ← loads, auto-fits and animates one GLB
  PlaceholderModel.tsx    ← stand-in shown until the GLB exists
  effects/                ← underglow, orbit rings, floating tiles, sparkles, parallax

The normal workflow is: drop the raw file → bun run models:optimize → tune in the Model lab → paste the values into model3d.config.ts → place <ClientModelViewer modelKey="…" />.

Every slot already exists in model3d.config.ts with a procedural placeholder, so you can build the page and the effects before a model is exported. The moment public/models/<file> exists, the real model replaces the placeholder — no code change.

1. Getting the file from your designer#

  • Format: .glb (single file, textures embedded), not .gltf + folder.
  • Origin at the centre of the model's base, facing +Z, Y up. Apply scale and rotation in Blender before export.
  • No backdrop planes or lights baked in — the page provides those. (If one slips through, list its material in optimize.drop.)
  • Give emissive parts real emissive materials (screens, neon) — they pick up the theme's glow.
  • If there is a baked animation, note the exact clip name for clip.
  • Drop the file in models-src/ using the file name from the config (e.g. models-src/avatar.glb).

2. Optimize#

bash
bun run models:optimize                # every model that has a raw file
bun run models:optimize hero-workstation   # one model, by key or file name

Reads models-src/, writes public/models/. It drops unwanted materials, merges meshes that share a material (fewer draw calls), welds vertices, optionally simplifies, quantizes and prunes. Example (the hero desk):

BeforeAfter
File size3.25 MB1.03 MB
Triangles148,39265,201
Draw calls17928

Per-model options live in the config:

ts
optimize: { simplify: 0.4, drop: ["Backdrop_Gradient"], maxTexture: 1024 },

bun run models:sync (runs automatically before dev/build) prints which slots are still placeholders and warns when a file is over budget (1.5 MB, hero 2.5 MB).

Draco/Meshopt compression is deliberately not used: it needs a WASM decoder at runtime, which the site's CSP does not allow.

3. Register and tune it#

ts
// src/packages/configs/model3d.config.ts
{
  key: "showcase-database",          // ← you reference the model by this key
  file: "database.glb",              // ← name inside public/models
  placeholder: "database",           // ← shown until the file exists
  size: 1.7,                         // ← largest axis, in scene units
  position: [0, 0, 0],               // ← nudge after auto-centering
  rotation: [0, 0, 0],               // ← radians
  animation: "float-spin",
  clip: undefined,                   // ← baked clip name, if any
  camera: { position: [0, 1.2, 6], fov: 40 },
  effects: [{ type: "underglow" }, { type: "orbit-rings", count: 2 }],
}

Tune it live: run bun dev, open /dev → Model lab. Pick a slot, drag the sliders for size / position / rotation / camera / effects, watch the FPS counter, then press Copy values and paste them into the entry. The lab only exists in development; it is not in the production build.

4. Sizing#

You don't need to know the scale your designer exported at. On load the model is measured and uniformly scaled so its largest axis equals size, then centred. Change size to make a model bigger or smaller — never ask for a re-export.

Use caseSuggested size
Small showcase tile (grid of 4)1.4 – 1.8
Section hero (desk, avatar, globe)3 – 4
Full-bleed centerpiece4+

5. Animation presets#

PresetWhat it does
"none"Static.
"float"Gentle up/down drift with slight tilt.
"spin"Slow continuous Y rotation.
"float-spin"Both — default for showcase tiles.
"entrance"One-time GSAP "pop in" (scale 0 → 1).

A baked clip (clip: "Idle") plays independently of the preset. All motion switches off when the visitor has reduce motion enabled. Wrong clip name? In development the console lists the available names.

6. Effects#

Listed per model in effects. Every colour comes from the active theme (--primary, --accent-foreground, …) and updates when the theme changes — never hard-code a colour in a 3D component.

typeLook
"underglow"Pulsing neon glow + ring on the floor under the model.
"orbit-rings" (count)Thin glowing rings turning around the model.
"tiles" (items)Glass tiles hovering around it (React / TS / Next…).
"sparkles" (count)Faint drifting dots.
"pointer-parallax" (strength)Whole scene eases toward the cursor.

To add an effect: create a component in models/effects/, add its type to ModelEffect in the config, and map it in effects/index.tsx.

7. Placing it on a page#

Always use ClientModelViewer (the Canvas can't be server-rendered).

tsx
import { ClientModelViewer } from "@/components/features/models/ClientModelViewer";

const ShowcaseCard = () => (
  <div className="aspect-square rounded-3xl border border-border">
    <ClientModelViewer modelKey="showcase-database" />
  </div>
);
PropMeaning
modelKeyThe key from model3d.config.ts.
classNameSizing is up to the parent — give it an explicit height.
eagerMount immediately (above-the-fold hero). Default: when scrolled near.
interactiveVisitors can drag-orbit. Leave off for decorative tiles.
overridesOverride size / position / effects for one usage.

8. Performance and security notes#

  • Three.js loads in its own chunk, only when a viewer is within 300 px of the viewport, and rendering pauses while it is off-screen.
  • Pixel ratio is capped and drops automatically if the frame rate falls.
  • No WebGL (or a failed GLB) shows a CSS glow / the placeholder — never a broken page.
  • Keep the 4-up showcase light: size ≈ 1.7, no interactive, ~1 effect pair each.
  • The strict CSP blocks third-party fetches, so don't use drei's <Environment preset="…"> (it downloads an HDR). Lights use a built-in procedural environment.

Troubleshooting#

SymptomLikely cause
Slot shows the placeholderThe file isn't in public/models/ yet, or the file name doesn't match. Run bun run models:sync.
Model tiny or hugeAdjust size, not the GLB.
Model off-centreA stray empty/light far from the origin is counted in the bounds — delete it in Blender.
Parts look flat/darkMissing emissive on glowing parts, or the material was merged/dropped — check optimize.drop.
clip doesn't playName typo — the dev console lists the real clip names.
Hydration error mentioning WebGLRendererA viewer was imported directly instead of ClientModelViewer.
Works locally, not on GitHub Pages sub-pathDon't hard-code /models/…; the viewer prefixes the base path itself.
Previous3D Homepage ModelsNext Creating 3D Models with Python Prompts in Blender

Keep reading

  • 3d

    3D Homepage Models

    3D model slots, asset requirements, configuration, optimization workflow, and implementation guidance for the homepage.

    15 min read·Sep 12, 2026
  • 3d

    Vivek Portfolio --- Blender 3D Model Prompt Library

    A library of production-ready Blender prompts for the 3D assets on Vivek's portfolio, from the workspace and avatar to tech orbs, with shared rules for web-ready GLB export.

    16 min read·Sep 12, 2026
  • 3d

    Creating 3D Models with Python Prompts in Blender

    A beginner's guide to creating 3D models in Blender by turning natural-language prompts into Python scripts, with basic shapes, a coffee mug project and a 4-week plan.

    19 min read·Sep 12, 2026

On this page

  • How it fits together
  • 1. Getting the file from your designer
  • 2. Optimize
  • 3. Register and tune it
  • 4. Sizing
  • 5. Animation presets
  • 6. Effects
  • 7. Placing it on a page
  • 8. Performance and security notes
  • Troubleshooting