@teammeer.com/3dtostrip
v0.1.0
Published
Transform heavy 3D models into lightweight, hover rotatable 360° previews without WebGL. Converts any 3D model (GLB, GLTF, OBJ, FBX) into a lightweight, interactive sprite strip with 18 frames showing a smooth 360° rotation. Perfect for galleries, e-comme
Maintainers
Readme
3D to Sprite Strip
Transform heavy 3D models into lightweight, hover rotatable 360° previews without WebGL.
Problem: Full 3D rendering is great but often overkill, especially when you just need a quick preview. Traditional 3D models are heavy, slow to load, and require complex WebGL setup.
Solution: This package converts any 3D model (GLB, GLTF, OBJ, FBX) into a lightweight, interactive sprite strip with 18 frames showing a smooth 360° rotation. It is not a replacement for full 3D rendering but a perfect optimization for previews, galleries, and e-commerce where you only need a fast, realistic 3D impression without the performance cost.
npm install @teammeer.com/3dtostrip
npm install react react-dom threeQuick Start
import { useSpriteStripGenerator, SpriteStripViewer } from '@teammeer.com/3dtostrip';
function App() {
const { generateSpriteStrip, generatedData } = useSpriteStripGenerator();
return (
<>
<input
type="file"
accept=".glb,.gltf,.obj"
onChange={(e) => generateSpriteStrip(e.target.files[0])}
/>
{generatedData && (
<SpriteStripViewer
spriteStripUrl={generatedData.spriteStripUrl}
/>
)}
</>
);
}Done. Upload → Generate → Interactive 3D preview.
Features
- ✅ 18 frames of your 3D model rotating 360°
- ✅ Hover to rotate - move mouse left/right
- ✅ Works everywhere - no WebGL needed
- ✅ Tiny file size - just one image
- ✅ Custom textures - Apply textures to your models (advanced)
The Gallery Problem → Solved
| Before (3D WebGL) | After (Sprite Strips) | |----------------------|---------------------------| | Slow loading - Each model loads heavy WebGL scenes | Instant loading - Just images, no WebGL needed | | Memory bloat - Browser memory gets exhausted | Lightweight - Load 100+ models instantly | | Mobile struggles - Complex 3D rendering fails | Works everywhere - Any device, any browser | | Complex setup - WebGL, shaders, lighting setup | Zero setup - Just upload and display | | Expensive - Heavy server processing | Cheap - Static images, CDN-friendly | | Limited - Only modern browsers | Universal - Works on IE11+ |
// Gallery with 50+ models - all load instantly
{models.map(model => (
<SpriteStripViewer
key={model.id}
spriteStripUrl={model.spriteStrip}
/>
))}Auto-Save to Database
const { generateSpriteStrip } = useSpriteStripGenerator({
onSubmit: async (data) => {
await fetch('/api/save', {
method: 'POST',
body: JSON.stringify(data)
});
}
});Flow: Upload → Generate → Auto-save → Done.
Supported Formats
- GLB, GLTF (recommended)
- OBJ, FBX
- Max file size: 50MB
Next.js Example
'use client'; // Required!
import { useSpriteStripGenerator, SpriteStripViewer } from '@teammeer.com/3dtostrip';
export default function Page() {
const { generateSpriteStrip, generatedData, isGenerating, progress, error } =
useSpriteStripGenerator();
return (
<div>
<input
type="file"
accept=".glb,.gltf,.obj"
onChange={(e) => generateSpriteStrip(e.target.files[0])}
disabled={isGenerating}
/>
{isGenerating && <p>Generating... {Math.round(progress)}%</p>}
{error && <p>Error: {error.message}</p>}
{generatedData && (
<SpriteStripViewer spriteStripUrl={generatedData.spriteStripUrl} />
)}
</div>
);
}Custom Lighting Controls
You can create custom slider components to control lighting in real-time. Here's how to implement interactive lighting controls:
Basic Lighting Controls Example
import React, { useState } from 'react';
import { useSpriteStripGenerator } from '@teammeer.com/3dtostrip';
const LightingControlsExample = () => {
const [lightingConfig, setLightingConfig] = useState({
ambientLight: { intensity: 0.6 },
directionalLight: { intensity: 1.0, position: { x: 2, y: 2, z: 2 } }
});
const { generateSpriteStrip, generatedData, isGenerating } = useSpriteStripGenerator({
lighting: lightingConfig,
backgroundColor: '#f0f0f0',
ratio: '16:9'
});
return (
<div>
{/* File Upload */}
<input
type="file"
accept=".glb,.gltf,.obj,.fbx"
onChange={(e) => generateSpriteStrip(e.target.files?.[0])}
disabled={isGenerating}
/>
{/* Lighting Controls */}
<div>
<label>Ambient Light: {lightingConfig.ambientLight.intensity}</label>
<input
type="range"
min="0"
max="2"
step="0.1"
value={lightingConfig.ambientLight.intensity}
onChange={(e) => setLightingConfig(prev => ({
...prev,
ambientLight: { intensity: parseFloat(e.target.value) }
}))}
/>
</div>
<div>
<label>Directional Light: {lightingConfig.directionalLight.intensity}</label>
<input
type="range"
min="0"
max="3"
step="0.1"
value={lightingConfig.directionalLight.intensity}
onChange={(e) => setLightingConfig(prev => ({
...prev,
directionalLight: { ...prev.directionalLight, intensity: parseFloat(e.target.value) }
}))}
/>
</div>
{/* Position Controls */}
<div>
<label>X Position: {lightingConfig.directionalLight.position.x}</label>
<input
type="range"
min="-5"
max="5"
step="0.1"
value={lightingConfig.directionalLight.position.x}
onChange={(e) => setLightingConfig(prev => ({
...prev,
directionalLight: {
...prev.directionalLight,
position: { ...prev.directionalLight.position!, x: parseFloat(e.target.value) }
}
}))}
/>
</div>
{generatedData && (
<img src={generatedData.spriteStripUrl} alt="Generated Sprite Strip" />
)}
</div>
);
};Lighting Control Ranges
| Control | Range | Step | Description | |---------|-------|------|-------------| | Ambient Intensity | 0 - 2 | 0.1 | Overall scene brightness | | Directional Intensity | 0 - 3 | 0.1 | Main light strength | | X Position | -5 to 5 | 0.1 | Left/Right light position | | Y Position | -5 to 5 | 0.1 | Up/Down light position | | Z Position | -5 to 5 | 0.1 | Forward/Back light position |
API Reference
useSpriteStripGenerator(options)
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| onGenerate | (data) => void | - | Called when generation completes |
| onSubmit | (data) => Promise<void> | - | Auto-save to database |
| ratio | '16:9' \| '4:3' \| '1:1' \| '3:2' \| '5:4' \| 'auto' \| 'custom' | '16:9' | Output aspect ratio |
| customRatio | { width: number; height: number } | - | Custom dimensions (when ratio='custom') |
| backgroundColor | string | '#ffffff' | Render background color |
| backgroundOpacity | number | 1.0 | Background transparency (0-1) |
| maxTextures | number | 10 | Max texture uploads |
| acceptedFormats | string[] | ['.png', '.jpg', '.jpeg', '.webp'] | Allowed texture formats |
| resolution | ResolutionSettings | - | Resolution and quality controls |
| lighting | LightingControls | - | Advanced lighting configuration |
ResolutionSettings
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| width | number | - | Custom width (overrides ratio) |
| height | number | - | Custom height (overrides ratio) |
| quality | 'low' \| 'medium' \| 'high' \| 'ultra' | 'high' | Output quality preset |
| compression | number | 0 | File compression (0-1, higher = smaller file) |
LightingControls
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| ambientLight | { intensity?: number } | { intensity: 0.6 } | Ambient lighting intensity (0-2) |
| directionalLight | { intensity?: number; position?: { x: number; y: number; z: number } } | { intensity: 1.0, position: { x: 2, y: 2, z: 2 } } | Main directional light intensity and position |
Returns:
generateSpriteStrip(file)- Generate from 3D modelisGenerating- Loading stateprogress- Generation progress (0-100)generatedData- Result dataerror- Error stategetPresetLighting(preset)- Get lighting presetsgetPresetResolution(preset)- Get resolution presets
Helper Functions
| Function | Parameters | Returns | Description |
|----------|------------|---------|-------------|
| getPresetLighting | 'studio' \| 'outdoor' \| 'dramatic' \| 'soft' | LightingControls | Pre-configured lighting setups |
| getPresetResolution | 'mobile' \| 'desktop' \| '4k' \| 'print' | ResolutionSettings | Pre-configured resolution settings |
SpriteStripViewer
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| spriteStripUrl | string | required | Sprite strip image URL |
| hover | boolean | true | Enable hover rotation |
| ratio | '16:9' \| '4:3' \| '1:1' \| 'auto' | '16:9' | Display aspect ratio |
| className | string | '' | CSS class name |
| onFrameChange | (frame: number) => void | - | Frame change callback |
Supported File Types
3D Models: .glb, .gltf, .obj, .fbx
Textures: .png, .jpg, .jpeg, .webp
Smart Limits: 50MB per file (prevents browser crashes, ensures fast processing)
Perfect for:
- Product galleries - Show 100+ items without lag
- E-commerce - Fast product previews
- Portfolios - Interactive 3D artwork
- Real estate - Property 360° views
- Documentation - Assembly instructions
The magic: Transform heavy 3D galleries into lightning-fast image galleries with full interactivity.
🤝 Contributing
We welcome contributions! This project is open source and community-driven.
How to Contribute
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development Setup
git clone https://github.com/teammeer/3dtostrip.git
cd 3dtostrip
npm install
npm run buildIdeas & Feedback
- 💡 Have an idea? Open an issue with the
enhancementlabel - 🐛 Found a bug? Open an issue with the
buglabel - 💬 Questions? Start a discussion
- ⭐ Like this project? Give it a star!
📝 License
This project is licensed under the MIT License - see the LICENSE file for details.
👥 Authors
- Meer Tahmid - @tahmidly
- Meer Estiyak - @mmestiyak
- teammeer - @teammeer
🙏 Acknowledgments
Made with ❤️ by the teammeer
