Skip to content

maucworks/threejs-glimmer

Repository files navigation

Glimmer 3D Viewer

A lightweight, interactive 3D model viewer for web applications with full TypeScript support. Drop it into any HTML element and display interactive 3D models with professional lighting and controls.

Features

Full TypeScript Support - Complete type definitions and IntelliSense
Multiple Formats - ESM and CommonJS compatibility
Professional Lighting - HDR environment maps and dynamic sun positioning
Interactive Controls - Built-in orbit controls and model framing
Edge Rendering - Conditional and threshold edge detection for technical visualization
Framework Agnostic - Works with React, Vue, Angular, or vanilla JavaScript
Mobile Optimized - Responsive design with touch controls

Installation

npm install @mauc/glimmer

Basic Implementation

1. HTML Setup

Create a container element in your HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My 3D Viewer</title>
</head>
<body>
    <div id="model-viewer"></div>
    <script type="module" src="main.js"></script>
</body>
</html>

2. TypeScript/JavaScript Implementation

import { Glimmer } from '@mauc/glimmer'

// Get your container element
const container = document.getElementById('model-viewer')!

// Create the viewer with your 3D model
const viewer = new Glimmer(container, {
  models: [{
    url: '/path/to/your-model.glb'
  }]
})

// Initialize and you're done!
await viewer.initialize()

That's it! Your website now has a fully interactive 3D viewer with complete TypeScript support.

TypeScript Integration

Complete Type Safety

import { Glimmer, type GlimmerSettings, type ModelSettings } from '@mauc/glimmer'

// Fully typed configuration
const config: GlimmerSettings = {
  environment: {
    type: 'hdr',
    url: '/studio.hdr',
    transparent: false
  },
  models: [{
    url: '/model.glb',
    color: 0xff0000,
    shadow: true,
    conditional_edges: {
      color: 0x000000,
      line_width: 2
    }
  }] satisfies ModelSettings[]
}

const viewer = new Glimmer(container, config)
await viewer.initialize()

Available Types

import type { 
  GlimmerSettings,
  ModelSettings, 
  EnvironmentSettings,
  SunSettings,
  EdgeSettings 
} from '@mauc/glimmer'

Integration Examples

React Component

import React, { useEffect, useRef } from 'react'
import { Glimmer } from '@mauc/glimmer'

interface ModelViewerProps {
  modelUrl: string
  width?: string
  height?: string
}

export function ModelViewer({ modelUrl, width = '100%', height = '400px' }: ModelViewerProps) {
  const containerRef = useRef<HTMLDivElement>(null)
  const glimmerRef = useRef<Glimmer>()

  useEffect(() => {
    if (!containerRef.current) return

    // Create viewer
    glimmerRef.current = new Glimmer(containerRef.current, {
      models: [{ url: modelUrl }],
      environment: { type: 'sky' }
    })

    glimmerRef.current.initialize()

    // Cleanup on unmount
    return () => {
      glimmerRef.current?.dispose()
    }
  }, [modelUrl])

  return (
    <div 
      ref={containerRef}
      style={{ width, height }}
      className="model-viewer"
    />
  )
}

// Usage in your React app
function ProductPage() {
  return (
    <div>
      <h1>Our Latest Product</h1>
      <ModelViewer 
        modelUrl="/products/chair.glb"
        height="500px"
      />
    </div>
  )
}

Vue Component

<template>
  <div 
    ref="container"
    class="model-viewer"
    :style="{ width, height }"
  />
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { Glimmer } from '@mauc/glimmer'

interface Props {
  modelUrl: string
  width?: string
  height?: string
}

const props = withDefaults(defineProps<Props>(), {
  width: '100%',
  height: '400px'
})

const container = ref<HTMLDivElement>()
let glimmer: Glimmer

onMounted(async () => {
  if (!container.value) return

  glimmer = new Glimmer(container.value, {
    models: [{ url: props.modelUrl }],
    environment: { type: 'hdr', url: '/lighting.hdr' }
  })

  await glimmer.initialize()
})

onUnmounted(() => {
  glimmer?.dispose()
})
</script>

<style scoped>
.model-viewer {
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
</style>

Vanilla JavaScript (ES6)

<!DOCTYPE html>
<html>
<head>
    <style>
        .viewer {
            width: 100%;
            height: 500px;
            border: 1px solid #ddd;
            border-radius: 8px;
        }
    </style>
</head>
<body>
    <div id="viewer" class="viewer"></div>
    
    <script type="module">
        import { Glimmer } from '@mauc/glimmer'
        
        const container = document.getElementById('viewer')
        
        const glimmer = new Glimmer(container, {
            environment: {
                type: 'sky',
                sun: { intensity: 1.5 }
            },
            models: [{
                url: './models/demo.glb',
                shadow: true
            }]
        })
        
        glimmer.initialize().then(() => {
            console.log('3D viewer ready!')
        })
    </script>
</body>
</html>

Multiple Models

const glimmer = new Glimmer(container, {
  environment: {
    type: 'hdr',
    url: '/studio-lighting.hdr'
  },
  models: [
    {
      url: '/models/chair.glb',
      color: 0x8B4513  // Brown chair
    },
    {
      url: '/models/table.glb',
      color: 0x654321  // Dark brown table
    }
  ]
})

await glimmer.initialize()

Dynamic Model Loading

// Start with empty viewer
const glimmer = new Glimmer(container)
await glimmer.initialize()

// Load models dynamically based on user selection
function showProduct(productId) {
    const modelUrl = `/products/${productId}.glb`
    glimmer.model_manager.clear_all()
    glimmer.model_manager.load_model(modelUrl)
}

// Example usage
document.getElementById('product-1').onclick = () => showProduct('chair')
document.getElementById('product-2').onclick = () => showProduct('table')

Configuration for Common Scenarios

E-commerce Product Display

const glimmer = new Glimmer(container, {
  environment: {
    type: 'hdr',
    url: '/assets/studio.hdr',  // Professional product lighting
    transparent: false
  },
  models: [{
    url: '/products/item.glb',
    shadow: true,
    color: 0xffffff  // Let original materials show
  }]
})

Architectural Visualization

const glimmer = new Glimmer(container, {
  environment: {
    type: 'sky',
    sun: {
      intensity: 2.0,
      position: [100, 100, 50],  // Natural daylight
      shadow: true
    }
  },
  models: [{
    url: '/buildings/house.glb',
    threshold_edges: {
      color: 0x333333,      // Architectural edge lines
      threshold_angle: 30,
      line_width: 1
    }
  }]
})

Technical Documentation

const glimmer = new Glimmer(container, {
  environment: {
    type: 'none',
    transparent: true,  // Clean background
    background_color: 0xffffff
  },
  models: [{
    url: '/technical/part.glb',
    conditional_edges: {
      color: 0x000000,      // Technical drawing style
      line_width: 2,
      threshold_angle: 1
    }
  }]
})

Styling and Layout

CSS Styling

.model-viewer {
    width: 100%;
    height: 400px;
    border-radius: 12px;
    box-shadow: 0 4px 20px rgba(0,0,0,0.15);
    overflow: hidden;
    background: #f5f5f5;
}

/* Responsive sizing */
@media (max-width: 768px) {
    .model-viewer {
        height: 300px;
    }
}

/* Full screen viewer */
.fullscreen-viewer {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    z-index: 1000;
}

Grid Layout Integration

<div class="product-grid">
    <div class="product-info">
        <h2>Product Name</h2>
        <p>Description...</p>
        <button>Add to Cart</button>
    </div>
    
    <div class="model-viewer-container">
        <div id="viewer"></div>
    </div>
</div>

<style>
.product-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2rem;
    align-items: center;
}

@media (max-width: 768px) {
    .product-grid {
        grid-template-columns: 1fr;
    }
}
</style>

User Interaction

Custom Controls

const glimmer = new Glimmer(container, {
  models: [{ url: '/model.glb' }]
})

await glimmer.initialize()

// Add custom buttons
document.getElementById('zoom-in').onclick = () => {
    // Glimmer uses OrbitControls - zoom programmatically
    glimmer.viewer.controls.dollyIn(1.2)
    glimmer.viewer.controls.update()
}

document.getElementById('reset-view').onclick = () => {
    glimmer.viewer.frame_model()  // Reset to default view
}

document.getElementById('animate').onclick = () => {
    glimmer.viewer.animate_orbit(true)  // Start rotation
}

Loading States

// Show loading indicator
const loadingDiv = document.getElementById('loading')
loadingDiv.style.display = 'block'

try {
    const glimmer = new Glimmer(container, {
        models: [{ url: '/large-model.glb' }]
    })
    
    await glimmer.initialize()
    loadingDiv.style.display = 'none'
    
} catch (error) {
    loadingDiv.innerHTML = 'Error loading 3D model'
    console.error('Failed to load model:', error)
}

Performance Tips

Optimize for Mobile

const glimmer = new Glimmer(container, {
  environment: {
    type: 'color',  // Simpler than HDR on mobile
    background_color: 0xf0f0f0
  },
  models: [{
    url: '/models/optimized.glb',  // Use lower-poly models
    shadow: window.innerWidth > 768  // Disable shadows on mobile
  }]
})

Memory Management

// Clean up when navigating away or hiding viewer
window.addEventListener('beforeunload', () => {
    glimmer.dispose()
})

// Or for Single Page Applications
function hideViewer() {
    glimmer.dispose()
    glimmer = null
}

File Preparation

Supported Formats

  • glTF 2.0 (.glb recommended) - Best performance and compatibility
  • HDR environment maps for professional lighting

Optimization Tips

  • Keep models under 10MB for web performance
  • Use glTF 2.0 binary format (.glb) for fastest loading
  • Optimize textures (1024px max recommended for web)
  • Use Draco compression when possible
  • Test on mobile devices for performance validation

Browser Support

  • Chrome 80+ ✅ Full support
  • Firefox 75+ ✅ Full support
  • Safari 13+ ✅ Full support
  • Edge 80+ ✅ Full support
  • Mobile browsers ✅ Touch controls included

Requires WebGL 2.0 support

Troubleshooting

Model Not Loading

// Check if model URL is accessible
try {
  const response = await fetch('/path/to/model.glb')
  if (!response.ok) {
    console.error('Model file not found:', response.status)
  }
} catch (error) {
  console.error('Network error:', error)
}

TypeScript Errors

Ensure you have the correct import paths:

// ✅ Correct
import { Glimmer } from '@mauc/glimmer'

// ❌ Incorrect
import { Glimmer } from '@mauc/glimmer/dist/index.js'

CORS Issues

Ensure your 3D models are served from the same domain or with proper CORS headers:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET

Performance Issues

  • Reduce model complexity and polygon count
  • Disable shadows on mobile devices
  • Use simpler lighting (type: 'color' instead of 'hdr')
  • Consider model optimization tools like gltfpack

Package Structure

@mauc/glimmer@1.0.8
├── dist/
│   ├── index.d.ts          # Main TypeScript declarations
│   ├── vite/
│   │   ├── glimmer.mjs     # ESM build
│   │   └── glimmer.umd.js  # CommonJS/UMD build
│   └── **/*.d.ts           # Complete type definitions
├── LICENSE
└── README.md

The package supports both ESM and CommonJS with complete TypeScript declarations.

Version History

v1.0.8 (Current)

  • ✅ Complete TypeScript support with full type definitions
  • ✅ Dual package format (ESM + CommonJS)
  • ✅ Comprehensive test suite (48 tests)
  • ✅ Improved build process and development workflow
  • ✅ Enhanced documentation and examples

Note: Public repository and examples will be available when the package is published to npm.

License & Legal

MIT License

This project is licensed under the MIT License - see the LICENSE file for details.

Disclaimers

Third-Party Dependencies: This software uses Three.js and other open-source libraries. Users are responsible for compliance with all dependency licenses.

Asset Rights: Users must ensure they have proper rights to any 3D models, textures, or environment maps used with this library. The example assets in this repository are for demonstration only.

Browser Compatibility: While we support modern browsers, WebGL performance and compatibility vary across devices. Test thoroughly on your target platforms.

Performance: 3D rendering performance depends on device capabilities, model complexity, and browser implementation. No performance guarantees are provided.

Production Use: This library may be used in production, but users assume all responsibility for testing and validation in their specific environments.

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

See CONTRIBUTING.md for detailed guidelines.


Ready to add 3D to your website? Start with the basic example above!

About

A 3d viewer based on THREE js.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published