Aaditya

3D Asset Viewer

AI chats

About

An orbit viewer for generated 3D assets on a small hand written WebGL 2 renderer. Matcap and wireframe shading, drag to orbit, throw and zoom, keyboard controls and a turntable export to video.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds 3D Asset Viewer to your project and fits it to your theme.

Code

How 3D Asset Viewer is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client"

import * as React from "react"
import { AssetMesh, AssetViewer, normalizeMesh } from "@/components/ui/3d-asset-viewer"

/* -------------------------------------------------------------------------------------------------
 * Procedural assets
 * -----------------------------------------------------------------------------------------------*/

/**
 * Spins a profile (`[radius, height]` pairs from bottom to top) around the vertical axis: vases,
 * bottles, lamps, mushrooms. Caps the bottom when it starts away from the axis.
 */
function latheMesh(
  profile: readonly (readonly [number, number])[],
  segments = 48,
): AssetMesh {
  const rows = profile.length
  const pos: number[] = []
  const idx: number[] = []
  for (let r = 0; r < rows; r++) {
    const [radius, y] = profile[r] as readonly [number, number]
    for (let s = 0; s <= segments; s++) {
      const a = (s / segments) * Math.PI * 2
      pos.push(Math.cos(a) * radius, y, Math.sin(a) * radius)
    }
  }
  const w = segments + 1
  for (let r = 0; r < rows - 1; r++) {
    for (let s = 0; s < segments; s++) {
      const a = r * w + s
      const b = a + w
      idx.push(a, b, a + 1, a + 1, b, b + 1)
    }
  }
  const [r0, y0] = profile[0] as readonly [number, number]
  if (r0 > 0) {
    const center = pos.length / 3
    pos.push(0, y0, 0)
    for (let s = 0; s < segments; s++) idx.push(center, s + 1, s)
  }
  const mesh = { positions: new Float32Array(pos), indices: new Uint32Array(idx) }
  return normalizeMesh(mesh)
}

/** A short table vase. */
const VASE_PROFILE: readonly (readonly [number, number])[] = [
  [0.0, 0],
  [0.3, 0],
  [0.34, 0.03],
  [0.42, 0.2],
  [0.45, 0.38],
  [0.38, 0.58],
  [0.24, 0.76],
  [0.2, 0.88],
  [0.24, 0.98],
  [0.26, 1],
  [0.22, 1],
  [0.18, 0.9],
]

/** A generated ceramic vase on the turntable. Drag to orbit, switch to wireframe, export a turn. */
function AssetViewerDemo() {
  const vase = React.useMemo(() => latheMesh(VASE_PROFILE, 56), [])
  return (
    <div className="w-full max-w-xl">
      <AssetViewer
        mesh={vase}
        alt="Ceramic table vase with a rounded belly and a narrow lipped neck"
        defaultMode="both"
      />
    </div>
  )
}

/** The line under each 21st demo that points back to the kit. */
function MoreOn({ slug, children }: { slug: string; children: React.ReactNode }) {
  return (
    <p className="text-[0.75rem]/[1rem] text-(color:--chatcn-fg-faint) text-center text-balance">
      {children}{" "}
      <a
        href={`https://chatcn.dev/docs/components/${slug}`}
        target="_blank"
        rel="noopener"
        className="text-(color:--chatcn-fg-subtle) hover:text-(color:--chatcn-fg) underline underline-offset-2"
      >
        chatcn.dev
      </a>
    </p>
  )
}

export default function AssetViewerPreview() {
  return (
    <div className="flex min-h-[520px] w-full flex-col items-center justify-center gap-10 p-6">
      <AssetViewerDemo />
      <MoreOn slug="3d-asset-viewer">
        Drag to orbit, switch to wireframe, export a turntable. More on
      </MoreOn>
    </div>
  )
}

Dependencies

More by Aaditya

View all
  • Dither Orb

    Dither Orb

    7
  • Pixel Orb

    Pixel Orb

    3
  • Voice Orb

    Voice Orb

    2
  • Dither Gradient

    Dither Gradient

    1
  • Wireframe Globe

    Wireframe Globe

    1
  • Particle Text

    Particle Text

    1
  • Split Flap

    Split Flap

    1
  • Agent Lanes

    Agent Lanes

    1

More in AI chats

View all
  • AI Actions

    AI Actions

    335
  • System Message

    System Message

    71
  • Aquarium Prompt

    Aquarium Prompt

    9
  • Message With Header And Delivery Status

    Message With Header And Delivery Status

    50
  • Color Picker

    Color Picker

    154
  • ASCII Orb

    ASCII Orb

  • Attachments

    Attachments

    30
  • Cost Meter

    Cost Meter

    41

Explore more

Part of chatcn — browse the full library on 21st.dev.