SMECO 2.0 is a browser-based 3D digital twin viewer built for the inspection and documentation of complex ship engine room assemblies. The platform renders a full-scale marine propulsion system in real-time WebGL, allowing engineers and technical staff to navigate component hierarchies, isolate individual parts, trigger animated exploded views per ship system, and access linked PDF documentation β all within a single-page web application requiring no plugins or native installation.
The project was designed from the ground up with a modular architecture that cleanly separates the 3D rendering core, model-specific logic, controller behaviours, and UI β making it straightforward to extend with new vessel models, additional documentation modules, or different engineering domains entirely.
- Features
- Architecture
- Tech Stack
- Project Structure
- Getting Started
- API Reference
- Ship Systems
- Design Decisions
- Roadmap
- WebGL-accelerated rendering via Three.js with ACESFilmic tone mapping and PCF soft shadows
- DRACO-compressed GLB asset loading (~14 MB model delivered efficiently via local WASM decoder)
- Adaptive pixel ratio capping at 2Γ for performance/quality balance across devices
- Transparent canvas with full light/dark theme switching β scene background and light intensities update live
The platform allows engineers to isolate individual components, inspect technical metadata, and access linked documentation directly from the 3D environment.
- Raycaster picking β click any mesh in the 3D scene to select and inspect it
- Focus / isolation mode β selected component is highlighted while the rest of the model fades; camera animates to fit the part in frame
- Hover highlighting β emissive color overlay on mouseover for instant part identification
- 3D floating labels β CSS2DObject labels anchored to component positions in world space
- Smooth camera snap β one-click camera rotation to orthographic-aligned views (front, back, left, right, top, bottom) with animated transition
The platform supports both full-model and subsystem-level exploded views, enabling engineers to better understand spatial relationships, assembly structure and component positioning.
-
Global explode β separates all 13 ship systems simultaneously using a hand-authored CAD-style displacement config with per-part offset vectors and rotations; animated with a custom smoothstep RAF loop (2.2 s duration)
-
Per-system explode β isolates and explodes a single selected system, with each subgroup configured for a specific direction and travel distance; uses GSAP when available with a RAF fallback
- Sidebar driven by a logical tree rebuilt from the raw GLB Object3D graph
- 13 top-level ship systems, each expandable to full assembly β subassembly β component depth
- Visibility toggles per node, propagating down the subtree
- Full reset: camera, visibility, explode state, focus mode β restored in a single action
- Every component links to its metadata stored in the backend: title, description, and three PDF document slots (documentation, schematics, maintenance)
- Inline edit mode β engineers can update titles and descriptions directly in the viewer
- PDF upload via multipart form β files stored server-side and linked to the component key
- Fuzzy key resolution β normalised Unicode matching handles Croatian/English diacritics, underscore/hyphen/dot separators, and case differences
- JWT-based login screen gating the entire viewer
- Token persisted in
localStorage; silently validated on page load β valid sessions skip the login screen entirely
- Emissive warning light simulation on specific mesh groups, representing active alarm states in the engine room
The application follows a strict layered architecture with no framework β intentionally, to demonstrate direct command of the underlying browser APIs and Three.js internals.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β index.html (SPA) β
β Single HTML shell β all UI inline β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β ES module entry
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β app.entry.js β
β Orchestrator: auth flow, model loading, β
β theme, camera controls, explode state machine β
ββββββββ¬ββββββββββββββββββββββββ¬βββββββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββββ ββββββββββββββββββββββββββββββββββββ
β auth.js β β viewer.core.js β
β JWT login β β Three.js runtime factory β
β VPS API β β Scene Β· Renderer Β· Camera β
βββββββββββββββ β OrbitControls Β· Lighting β
β GLTFLoader Β· DRACOLoader β
ββββββββββββββββ¬ββββββββββββββββββββ
β loadModelModule(mod)
βΌ
ββββββββββββββββββββββββββββββββββββ
β engine.model.js β
β Model Module (pluggable) β
β Loads GLB Β· Wires controllers β
ββββ¬ββββββββββββββββββββββββββββββββ
β
ββββββββββββββΌββββββββββββββββββββββββββββββ
βΌ βΌ βΌ
ββββββββββββββ ββββββββββββββββββββββββ ββββββββββββββββββ
β tree.js β β controllers/ β β ui/sidebar/ β
β Rebuilds β β picking Β· focus β β Render tree β
β logical β β hover Β· labels β β Edit/save β
β hierarchy β β explode Β· visibilityβ β components β
β from GLB β β reset Β· systemExp. β β Components β
ββββββββββββββ ββββββββββββββββββββββββ β REST API β
βββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββββ
β backend/ β
β Express API β
β components.json β
β PDF storage β
βββββββββββββββββββββ
Any new vessel model can be integrated by creating a module that satisfies this contract and registering it in MODEL_REGISTRY:
export const id = 'engine';
export const name = '3D Engine';
export const url = '/glb/FIXED_ENGINE_ROOM.glb';
export const viewPreset = { dir, distanceMul, offset, targetOffset };
export async function load(ctx) { /* receives viewer API, sets up scene */ }
export async function dispose() { /* cleanup all listeners and references */ }
export function toggleExplode() { /* returns Boolean or Promise<Boolean> */ }
export function toggleSystemExplode() { ... }The architecture currently ships with one model (engine). Adding a second requires only the new module file and a one-line registry entry.
| Layer | Technology | Version | Notes |
|---|---|---|---|
| 3D Rendering | Three.js | 0.160.0 | Scene, renderer, camera, controls, loaders |
| Build Tool | Vite | ^7.3.1 | Dev server, HMR, path aliases, bundle analyser |
| Language | Vanilla JS | ES2022 | Pure ES modules, no framework |
| Animation | GSAP | CDN (optional) | Camera transitions, explode sequences. Graceful fallback if absent |
| Compression | DRACOLoader | Three.js addon | Local WASM decoder β no CDN dependency |
| Backend | Node.js + Express | 18+ / ^5.2.1 | REST API, ESM ("type": "module") |
| File Upload | multer | ^2.1.1 | PDF documents, max 25 MB |
| Data Storage | JSON flat file | β | backend/data/components.json β zero-config, human-readable |
| Auth | JWT | β | Bearer token, localStorage persistence |
Ship_engine/
βββ index.html # SPA shell β all UI elements inline
βββ vite.config.js # Build config + path aliases (@app, @engine, @ui, @shared)
βββ package.json # Frontend dependencies
βββ start.sh # One-command setup and launch script
βββ .env # VITE_API_BASE_URL (auth backend, not committed)
β
βββ config/
β βββ api.js # Components API base URL (dev/prod auto-switch)
β
βββ viewer/
β βββ auth.js # JWT auth: login, logout, validateToken, authFetch
β βββ preloader.js # Loading overlay controller
β β
β βββ app/
β β βββ app.entry.js # Application entry β orchestrates everything
β β
β βββ engine/
β β βββ core/
β β β βββ viewer.core.js # Three.js runtime factory
β β βββ models/
β β βββ engine/
β β βββ engine.model.js # Model root β load / dispose / explode API
β β βββ tree.js # GLB β logical tree with paths and groups
β β βββ names.js # Node name formatting utilities
β β βββ utils.js # isRenderablePart() and helpers
β β βββ controllers/
β β β βββ picking.js # Raycaster click detection
β β β βββ focus.js # Component isolation + info panel + API
β β β βββ hover.js # Emissive highlight on mouseover
β β β βββ labels.js # CSS2DObject floating labels
β β β βββ visibility.js # Show / hide mesh subtrees
β β β βββ explode.js # Global explode animation (smoothstep RAF)
β β β βββ explode.config.js # Per-system displacement vectors + rotations
β β β βββ systemExplode.js # Per-system explode (GSAP / RAF)
β β β βββ system-explode.config.js # Config for all 13 systems
β β β βββ reset.js # Full scene reset
β β βββ ui/
β β βββ sidebar/
β β βββ engine.sidebar.js # Bridges tree β sidebar UI
β β
β βββ ui/
β βββ sidebar/ # Generic sidebar component (model-agnostic)
β βββ render.js # DOM rendering + API integration
β βββ state.js # Reactive sidebar state
β βββ dom.js # DOM references and helpers
β βββ panels.js # Accordion expand / collapse
β βββ events.js # All event listeners
β βββ icons.js # SVG icon factories
β βββ api.js # Sidebar API helpers
β
βββ css/
β βββ viewer-base.css # Reset, root variables, layout base
β βββ viewer-ui.css # All UI: sidebar, toolbar, info panel, login, menus
β βββ viewer-preloader.css # Preloader overlay animation
β βββ viewer-sidebar.css # Sidebar-specific overrides
β
βββ public/
β βββ glb/
β β βββ FIXED_ENGINE_ROOM.glb # Primary 3D asset (14 MB, DRACO-compressed)
β βββ docs/
β β βββ components/ # Dynamically uploaded component PDFs
β β βββ main_docs/ # Static ship system technical drawings
β β βββ help/ # Platform user guide
β βββ draco/gltf/ # DRACOLoader WASM runtime (local)
β
βββ backend/
βββ server.js # Express REST API
βββ package.json
βββ data/
βββ components.json # Component metadata store (auto-created)
- Node.js 18 or newer
- npm
Clone the repository:
git clone https://github.com/Armin-000/Ship_engine.git
cd Ship_engineCreate a .env file in the project root:
VITE_API_BASE_URL=http://your-auth-backend-urlRun the startup script β it handles everything automatically:
# macOS / Linux
chmod +x start.sh
./start.sh
# Windows (Git Bash or WSL)
./start.shThe script will:
- Verify your Node.js installation
- Install frontend dependencies (
npm install) - Install backend dependencies (
cd backend && npm install) - Create required directories (
backend/data/,public/docs/components/) - Start the backend API server on port
3001 - Start the Vite frontend server on port
5173 - Open the application in your default browser
# Terminal 1 β backend
cd backend
npm start
# Terminal 2 β frontend
npm run devnpm run buildOutput is written to dist/. To analyse the bundle:
npm run build:analyze| Service | URL |
|---|---|
| Frontend | http://localhost:5173 |
| Backend API | http://localhost:3001 |
| Health check | http://localhost:3001/api/health |
The backend exposes a REST API for component metadata and PDF document management.
Base URL: http://localhost:3001 (dev) Β· https://ship-engine.onrender.com (prod)
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/health |
Service health check |
GET |
/api/components |
Retrieve all stored component metadata |
GET |
/api/components/resolve |
Fuzzy-resolve a component by key + candidate names |
GET |
/api/components/:key |
Retrieve one component by exact key |
PUT |
/api/components/:key |
Create or update a component record |
POST |
/api/upload/document |
Upload a PDF file (multipart, max 25 MB) |
DELETE |
/api/components/:key |
Delete a component record |
GET |
/docs/components/:filename |
Serve a stored PDF file |
Every 3D mesh is identified by its path through the scene graph, built at runtime by tree.js:
path:Scene/FULL/1_Structure/11_Floor/113_Engine_Room_Base/Object_5_3
{
"path:Scene/FULL/1_Structure/11_Floor/113_Engine_Room_Base/Object_5_3": {
"title": "Transverse foundation girder",
"description": "Transverse bracing element providing lateral stiffness and structural integrity to the machinery bed.",
"documents": {
"documentation": "/docs/components/1780433957970-c32_1000_hp_specifications.pdf",
"schematics": null,
"maintenance": null
},
"updatedAt": "2026-06-03T09:02:34.043Z"
}
}The engine room model is organised into 13 independently navigable and explodable ship systems:
| # | System |
|---|---|
| 1 | Structure |
| 2 | Exhaust System |
| 3 | Plate Heat Exchanger |
| 4 | Port Generator |
| 5 | Main Engine No. 1 |
| 6 | Transmission |
| 7 | Pipes |
| 8 | Valves |
| 9 | Propeller |
| 10 | Fire System |
| 11 | Lube Oil Tank |
| 12 | Service Air Receiver |
| 13 | Duplex Oil Strainer |
Each system contains a hierarchy of assemblies, subassemblies, and individual named components. Every level of the hierarchy is separately navigable, isolatable, and documentable.
No frontend framework. The decision to use vanilla ES modules rather than React or Vue was deliberate. The application's primary complexity is 3D scene management, not component state trees β Three.js already provides the rendering abstraction, and introducing a virtual DOM layer would add overhead without solving a real problem here.
GSAP as an optional peer dependency. Rather than adding a hard npm dependency, GSAP is loaded via CDN and accessed as window.gsap || null throughout the codebase. Every animation code path has a functional RAF fallback, which means the application runs correctly β with slightly less polished easing curves β if the CDN load fails or is blocked.
Two separate API origins. Authentication (JWT login, token validation) runs against a dedicated VPS. Component metadata and PDF storage run against a separate service on Render. These concerns are intentionally decoupled: swapping or scaling the document storage service does not affect user authentication.
JSON flat file as the database. For this use case β a single-writer system where an engineer updates component metadata β a flat JSON file is operationally simpler than a database, trivially human-readable and editable, and trivially version-controllable. Migration to SQLite or PostgreSQL is a well-defined future step.
Local DRACO decoder. The DRACOLoader WASM runtime is bundled locally in public/draco/gltf/ rather than pointing to the Google CDN. This eliminates a cross-origin dependency for an asset critical to the initial load path.
- JWT middleware on the components API (currently open CRUD)
- Database migration β SQLite or PostgreSQL
- Additional vessel models β architecture is ready, requires only a new model module
- 3D annotation billboards anchored to specific mesh positions
- TypeScript migration β incremental, starting from
viewer.core.js - CI/CD pipeline with static build and automated deployment
- Mobile-optimised touch controls and responsive sidebar layout
ISC β see LICENSE for details.



