A shadcn/ui styled 3D model viewer component for React with annotation, search and highlight support.
- 3D Model Viewing: Load GLB/GLTF models with orbit controls
- Annotation System: Add, edit, delete annotations on 3D models
- Structure Search: Search and highlight anatomy structures
- Demo Model: Built-in skull anatomy demo model
- Comments: Add comments to annotations
- Responsive Design: Works with shadcn/ui styling
npm install react-3d-model-viewernpm install react react-dom three @react-three/fiber @react-three/dreiimport { CompleteModelViewer } from 'react-3d-model-viewer'
export default function App() {
return (
<div className="h-[600px]">
<CompleteModelViewer
modelUrl="/models/skull.glb"
structuresList={['Cranium', 'Frontal Bone', 'Temporal Bone']}
showSearchBar={true}
/>
</div>
)
}import { CompleteModelViewer } from 'react-3d-model-viewer'
function App() {
return <CompleteModelViewer />
}import { CompleteModelViewer } from 'react-3d-model-viewer'
function App() {
return (
<CompleteModelViewer
modelUrl="/models/anatomy.glb"
showSearchBar={true}
structuresList={['Skull', 'Mandible', 'Spine']}
/>
)
}import { CompleteModelViewer, type Annotation } from 'react-3d-model-viewer'
const initialAnnotations: Annotation[] = [
{
id: '1',
structureName: 'Cranium',
position: { x: 0, y: 0.8, z: 0 },
label: 'Skull',
color: '#ff6b6b',
},
]
function App() {
return (
<CompleteModelViewer
modelUrl="/models/skull.glb"
initialAnnotations={initialAnnotations}
onSaveAnnotation={(data) => console.log('Save:', data)}
onDeleteAnnotation={(ann) => console.log('Delete:', ann)}
/>
)
}import { ModelViewer } from 'react-3d-model-viewer/ModelViewer'
function App() {
return (
<ModelViewer
modelUrl="/models/skull.glb"
annotations={[]}
highlightedStructures={[]}
onAnnotationClick={(ann) => console.log(ann)}
onModelPartClick={(mesh, point) => console.log(mesh, point)}
/>
)
}| Prop | Type | Default | Description |
|---|---|---|---|
modelUrl |
string |
- | GLB model URL (empty shows demo) |
initialAnnotations |
Annotation[] |
[] |
Initial annotation list |
showSearchBar |
boolean |
true |
Show/hide search bar |
structuresList |
string[] |
[] |
Structure names for search |
currentUserId |
string |
- | Current user ID for comments |
onSaveAnnotation |
function |
- | Callback when annotation saved |
onDeleteAnnotation |
function |
- | Callback when annotation deleted |
onAddComment |
function |
- | Callback when comment added |
onModelPartClick |
function |
- | Callback when model part clicked |
onHighlightChange |
function |
- | Callback when highlight changes |
| Prop | Type | Default | Description |
|---|---|---|---|
modelUrl |
string |
- | GLB model URL |
annotations |
Annotation[] |
[] |
Annotation list |
highlightedStructures |
HighlightedStructure[] |
[] |
Structures to highlight |
selectedAnnotationId |
string |
- | Currently selected annotation |
showGrid |
boolean |
true |
Show/hide grid |
backgroundColor |
string |
#1a1a2e |
Canvas background |
| Prop | Type | Default | Description |
|---|---|---|---|
annotation |
Annotation |
- | Current annotation |
isCreating |
boolean |
- | Creating new annotation mode |
newPosition |
Position3D |
- | New annotation position |
onSave |
function |
- | Save callback |
onDelete |
function |
- | Delete callback |
onAddComment |
function |
- | Add comment callback |
| Prop | Type | Default | Description |
|---|---|---|---|
structuresList |
string[] |
- | Structure names |
onSearchResults |
function |
- | Search results callback |
isSearching |
boolean |
- | Loading state |
placeholder |
string |
- | Placeholder text |
interface Annotation {
id: string
structureName: string
position: Position3D
label?: string | null
description?: string | null
color: string
meshName?: string | null
comments?: Comment[]
}
interface Position3D {
x: number
y: number
z: number
}
interface HighlightedStructure {
meshName?: string
structureName: string
color?: string
}This component uses Tailwind CSS classes. Make sure your project has Tailwind configured:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -pAdd the content paths to your tailwind.config.js:
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
// ... rest of config
}MIT