3D STEP Viewer
Overview
Section titled “Overview”A client-side browser-based 3D STEP file viewer integrated into Eryxon Flow. Built with React, Three.js, and occt-import-js to parse and render CAD models entirely in the browser with no backend service required.
Key Point: This is a purely client-side implementation. STEP files are parsed in the browser using WebAssembly (occt-import-js), not on a server.
Features
Section titled “Features”✅ STEP File Support: Parse and render .step and .stp files ✅ Interactive 3D Controls: Orbit, zoom, and pan with mouse/touch ✅ Exploded View: Visualize assemblies with adjustable separation ✅ Wireframe Mode: Toggle between solid and wireframe rendering ✅ Dynamic Grid: Auto-sized grid based on model dimensions ✅ Fit to View: Automatically frame the model in the viewport ✅ File Management: Upload, view, and delete CAD files ✅ Multi-tenant: Secure tenant-isolated file storage
Technology Stack
Section titled “Technology Stack”Dependencies
Section titled “Dependencies”{ "three": "^0.180.0"}External Libraries (CDN)
Section titled “External Libraries (CDN)”- occt-import-js (v0.0.23): STEP file parser loaded from CDN
Existing Dependencies
Section titled “Existing Dependencies”@radix-ui/react-dialog: Modal dialogs@radix-ui/react-slider: Explosion factor controllucide-react: Icons@supabase/supabase-js: File storage
Database Setup
Section titled “Database Setup”1. Create Supabase Storage Bucket
Section titled “1. Create Supabase Storage Bucket”Create a storage bucket called parts-cad for storing STEP files.
Via Supabase Dashboard:
- Go to Storage > Buckets
- Click “Create bucket”
- Name:
parts-cad - Public:
false(private bucket - files accessed via signed URLs) - Click “Create bucket”
Via SQL (Alternative):
-- Create storage bucket for parts CAD filesINSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)VALUES ( 'parts-cad', 'parts-cad', false, 52428800, -- 50MB max file size ARRAY['application/step', 'application/stp', 'application/octet-stream']);2. Set Up Storage Policies
Section titled “2. Set Up Storage Policies”Add RLS (Row Level Security) policies for the parts-cad bucket:
-- Policy: Allow authenticated users to upload files to their tenant's folderCREATE POLICY "Users can upload CAD files to their tenant folder"ON storage.objectsFOR INSERTTO authenticatedWITH CHECK ( bucket_id = 'parts-cad' AND (storage.foldername(name))[1] = get_user_tenant_id()::text);
-- Policy: Allow authenticated users to read files from their tenant's folderCREATE POLICY "Users can view CAD files from their tenant"ON storage.objectsFOR SELECTTO authenticatedUSING ( bucket_id = 'parts-cad' AND (storage.foldername(name))[1] = get_user_tenant_id()::text);
-- Policy: Allow authenticated users to delete files from their tenant's folderCREATE POLICY "Users can delete CAD files from their tenant"ON storage.objectsFOR DELETETO authenticatedUSING ( bucket_id = 'parts-cad' AND (storage.foldername(name))[1] = get_user_tenant_id()::text);3. Verify Parts Table Schema
Section titled “3. Verify Parts Table Schema”The parts table should already have the file_paths column (as TEXT[]). Verify it exists:
-- Check if file_paths column existsSELECT column_name, data_type, is_nullableFROM information_schema.columnsWHERE table_name = 'parts' AND column_name = 'file_paths';
-- If it doesn't exist, add it:ALTER TABLE parts ADD COLUMN IF NOT EXISTS file_paths TEXT[];4. Create Helper Function
Section titled “4. Create Helper Function”Create a helper function to get user’s tenant ID:
-- Function to get current user's tenant IDCREATE OR REPLACE FUNCTION get_user_tenant_id()RETURNS UUIDLANGUAGE sqlSECURITY DEFINERSTABLEAS $$ SELECT tenant_id FROM profiles WHERE id = auth.uid()$$;Storage Structure
Section titled “Storage Structure”Files are stored in the following structure:
parts-cad/ └── {tenant_id}/ └── parts/ └── {part_id}/ ├── model_v1.step ├── assembly.stp └── ...Architecture
Section titled “Architecture”User opens Part Detail Modal ↓Clicks on existing STEP file OR uploads new file ↓File uploaded to Supabase storage: parts-cad/{tenant_id}/parts/{part_id}/ ↓File path saved to parts.file_paths[] ↓User clicks "View 3D" button ↓Create signed URL → Fetch as blob → Create blob URL ↓Opens STEPViewer component in Dialog ↓STEPViewer loads occt-import-js from CDN ↓Initializes Three.js scene (camera, renderer, lights, controls) ↓Fetches STEP file → Convert to ArrayBuffer → Parse with occt-import-js ↓Convert parsed meshes to Three.js geometry ↓Add to scene → Fit camera → Render loopFile Structure
Section titled “File Structure”src/├── components/│ ├── STEPViewer.tsx # 3D viewer component│ └── admin/│ └── PartDetailModal.tsx # Modified - Added CAD file section└── integrations/ └── supabase/ └── types.ts # parts table typesKey Components
Section titled “Key Components”STEPViewer Component
Section titled “STEPViewer Component”Location: /src/components/STEPViewer.tsx
Main 3D viewer component with:
- Three.js scene initialization
- STEP file parsing with occt-import-js
- Interactive controls (orbit, zoom, pan)
- Feature toggles (wireframe, grid, exploded view)
- Loading states and error handling
Props:
interface STEPViewerProps { url: string; // Blob URL to STEP file title?: string; // Display title}Features:
- 🎮 Orbit Controls: Click-drag to rotate, scroll to zoom, right-click-drag to pan
- 📦 Exploded View: Separate parts with adjustable factor (0-2x)
- 🔲 Wireframe Mode: Toggle between solid and wireframe rendering
- 📐 Dynamic Grid: Auto-sized based on model dimensions
- 🎯 Fit to View: Automatically center and frame the model
- ⚡ Optimized: Efficient rendering with requestAnimationFrame
PartDetailModal (Modified)
Section titled “PartDetailModal (Modified)”Location: /src/components/admin/PartDetailModal.tsx
Added sections:
- CAD Files Upload: Drag-and-drop file uploader for .step/.stp files
- CAD Files List: Display existing files with View/Delete actions
- 3D Viewer Dialog: Full-screen modal for STEPViewer component
For Administrators (Parts Management)
Section titled “For Administrators (Parts Management)”-
Navigate to Parts Page
- Go to Admin Dashboard > Parts
-
Open Part Detail
- Click on any part to open the detail modal
-
Upload CAD Files
- Scroll to “3D CAD Files” section
- Click “Choose STEP files” or drag-and-drop
- Select .step or .stp files
- Click “Upload”
-
View 3D Model
- Click “View 3D” button next to any file
- 3D viewer opens in full-screen modal
-
Interact with 3D Model
- Rotate: Left-click and drag
- Zoom: Scroll wheel
- Pan: Right-click and drag
- Fit View: Click “Fit View” button
- Wireframe: Toggle wireframe mode
- Explode: Toggle exploded view, adjust slider
- Grid: Toggle grid visibility
-
Delete Files
- Click trash icon next to file
- Confirm deletion
API Reference
Section titled “API Reference”STEPViewer Component
Section titled “STEPViewer Component”import { STEPViewer } from '@/components/STEPViewer';
<STEPViewer url="blob:http://localhost:5173/abc123" // Blob URL to STEP file title="Bracket Assembly" // Optional display title/>Security
Section titled “Security”Tenant Isolation
Section titled “Tenant Isolation”- Files stored in tenant-specific folders:
{tenant_id}/parts/{part_id}/ - RLS policies restrict access to user’s tenant only
- Signed URLs expire after 1 hour
File Validation
Section titled “File Validation”- Client-side: Only .step and .stp extensions allowed
- Server-side: RLS policies enforce tenant access
- MIME types:
application/step,application/stp,application/octet-stream
Storage Policies
Section titled “Storage Policies”All storage operations are protected by RLS policies that enforce tenant isolation.
Performance Considerations
Section titled “Performance Considerations”File Size Limits
Section titled “File Size Limits”- Maximum file size: 50MB per file
- Recommended: Keep files under 10MB for optimal performance
- Large assemblies: Consider splitting into sub-assemblies
Rendering Optimization
Section titled “Rendering Optimization”- Uses
requestAnimationFramefor smooth rendering - Damped controls reduce unnecessary re-renders
- Efficient geometry disposal on cleanup
- Anti-aliasing enabled for better visual quality
Memory Management
Section titled “Memory Management”- Blob URLs revoked on dialog close
- Three.js geometries and materials disposed on unmount
- Animation frame cancelled on cleanup
Troubleshooting
Section titled “Troubleshooting”Issue: “Failed to load STEP parser library”
Section titled “Issue: “Failed to load STEP parser library””Solution: Check internet connection, occt-import-js CDN may be down
Issue: “No geometry found in STEP file”
Section titled “Issue: “No geometry found in STEP file””Causes:
- Corrupt STEP file
- Unsupported STEP version (AP242, AP214, etc.)
- Empty or invalid file
Solution: Verify file is valid STEP format, try re-exporting from CAD software
Issue: Model appears off-center
Section titled “Issue: Model appears off-center”Solution: Click “Fit View” button
Issue: CORS errors
Section titled “Issue: CORS errors”Solution: We fetch signed URLs as blobs to avoid CORS issues
Issue: Memory leaks
Section titled “Issue: Memory leaks”Solution: Always revoke blob URLs when closing the viewer
Testing Checklist
Section titled “Testing Checklist”Upload & Storage
Section titled “Upload & Storage”- Upload single STEP file
- Upload multiple STEP files at once
- Reject non-STEP files (.pdf, .jpg, etc.)
- Files appear in parts-cad bucket
- File paths saved to parts.file_paths
- Tenant isolation works
3D Viewer
Section titled “3D Viewer”- STEP file loads and displays
- Model renders correctly with colors
- Camera controls work (orbit, zoom, pan)
- “Fit View” centers model
- Wireframe toggle works
- Grid toggle works
- Exploded view separates parts
- No console errors
Performance
Section titled “Performance”- Small files (<1MB) load quickly
- Medium files (1-5MB) load acceptably
- Large files (5-20MB) load without crashing
- Multiple open/close cycles don’t leak memory
- Smooth rendering at 60fps
References
Section titled “References”- Three.js Docs: https://threejs.org/docs/
- occt-import-js: https://github.com/kovacsv/occt-import-js
- Supabase Storage: https://supabase.com/docs/guides/storage