A powerful display calibration tool that helps you configure multi-display setups with 3D visualization. Available as both an Electron desktop application and a web application.
- 3D Display Visualization: View your display setup from top, left, and front perspectives
- Interactive Configuration: Drag displays to position them visually
- Preset Display Sizes: Quick setup for common display sizes (27", 32", 40", etc.)
- Real-time Calculations: See corner coordinates and projections update live
- Unified File Operations: Seamless file handling in both desktop and web environments
- Smart Change Tracking: Automatic detection and confirmation of unsaved changes
- Status Bar: Visual indicators for save status, environment, and configuration state
- Dual Environment Support: Works as both desktop and web application with identical functionality
- IG Settings Export: Write the calibrated frustum straight into a simulator's IG settings file
- Node.js (version 14 or higher)
- npm (comes with Node.js)
- Clone or download the project
- Navigate to the project directory
- Install dependencies:
npm installRun the desktop version:
npm startFeatures in Desktop Version:
- Native file dialogs for opening/saving configurations
- Full filesystem access
- Desktop integration
- Start the web server:
npm run start-web- Open your browser and navigate to:
http://localhost:3000
Features in Web Version:
- Browser-based file operations
- Automatic file downloads for saving
- Responsive design for mobile devices
- No installation required for end users
- Add Displays: Use the preset sizes or enter custom dimensions
- Position Displays:
- Enter coordinates manually, or
- Drag displays in the canvas views (right-click and drag)
- View Setup: Use the three canvas views to see your setup from different angles
- Zoom and Pan:
- Use zoom buttons or mouse wheel to zoom
- Left-click and drag to pan the view
- Double-click to reset view position
- Save Configuration: Use File > Save to store your setup
The application features a smart file operations interface that automatically adapts to the environment:
- New: Create a new configuration with unsaved changes confirmation
- Open: Native file dialog for browsing and opening .json configuration files
- Save: Save to the current file path
- Save As: Native save dialog with filename selection
- New: Create a new configuration with unsaved changes confirmation
- Open: HTML5 file picker for selecting .json files from your device
- Save: Automatic download of configuration file
- Save As: Download with timestamp-based filename
File > Export to IG Settings... (Ctrl+E, or the Export IG button in the
web version) writes this calibration into a simulator's IG settings file.
Displays are matched to the file by name: a display's name has to equal the
Name of the IG node that renders it, so name your displays after the IG nodes
before exporting — that is the one piece of setup the export needs. Matching
ignores case and extra spaces, but nothing else: near-identical node names are
not treated as the same node.
Cameras that do not render a calibrated display are never matched — mirrors, the dashboard camera banks on widget windows, and cameras that follow an incoming view (the instructor and replay cameras).
The export then:
- shows every display and the camera it will be written to, letting you pick when a name matched more than one camera, or drop a display from this export;
- asks where to save (defaulting to the file you chose);
- reports what it wrote — every field with its old and new value, the removed
FOV/Width/Height, and the displays it skipped — with a Copy button for pasting into a handover note.
The written file keeps its own indentation, line endings and comment keys, so
it diffs against the original on the cameras that changed and nothing else.
A sample input lives in samples/.
- Change Tracking: Visual indicators for unsaved changes
- Confirmation Dialogs: Prevents accidental loss of unsaved work
- Status Bar: Shows current file, save status, and environment information
- Cross-Environment Compatibility: Same file format works in both versions
Configurations are saved as JSON files with the following structure:
{
"version": "1.0",
"timestamp": "2025-07-16T...",
"displays": [
{
"width": 0.5,
"height": 0.3,
"distance": 0.7,
"yaw": 0,
"pitch": 0,
"roll": 0,
"x": 0,
"y": 0,
"z": 0.7
}
]
}- Left Click + Drag: Pan the view
- Right Click + Drag: Move selected display (if any)
- Mouse Wheel: Zoom in/out
- Double Click: Reset view position
- Zoom Buttons: Fine control over zoom level
- Click on Display: Select for editing
- Add Display: Add new display with current settings
- Update Display: Apply changes to selected display
- Delete Display: Remove selected display
nodeViewCalibrator/
├── package.json # Scripts, dependencies, electron-builder config
├── app-icon.ico # Windows app/installer icon
├── build/ # macOS icon assets (icon.icns, icon.png) for electron-builder
├── src/ # Shared browser core (ES modules, used by both apps)
│ ├── renderer-core.js # App bootstrap / wires everything together (initApp)
│ ├── display.js # Display calculation logic + presets
│ ├── mathutils.js # Rotation & projection math utilities
│ ├── sceneRenderer.js # Three.js scene, controls, FBX loading
│ ├── fileInterface.js # Environment-aware file operations (desktop vs web)
│ ├── statusBar.js # Status bar component
│ └── styles.css # Shared styles
├── desktop/ # Electron desktop app
│ ├── main.js # Electron main process
│ ├── preload.js # contextBridge -> window.electronAPI
│ ├── index.html # Desktop HTML shell (local three.js + CSP)
│ └── renderer.js # Thin entry: imports initApp from ../src
├── web/ # Web app
│ ├── server.js # Express static server (serves web/ and project root)
│ ├── index.html # Web HTML shell (CDN three.js + file inputs)
│ ├── web-renderer.js # Thin entry: imports initApp from ../src
│ └── web-styles.css # Web-specific styles
├── samples/ # Example configuration files
│ ├── display-config.json
│ └── display-config2.json
├── tools/ # Manual, developer-run diagnostic scripts
│ ├── projectionTest.js
│ └── projectionDebug.js
└── scripts/ # Convenience launchers
├── start-desktop.bat
├── start-web.bat
└── launcher.html # Standalone desktop/web chooser page
Note: The Electron entry point is
desktop/main.js(see themainfield inpackage.json).desktop/index.htmluses a strict Content-Security-Policy whosesha256hash covers the inline importmap<script>— if you edit that importmap, recompute the hash or three.js will fail to load.
To build the desktop application for distribution:
# Build for current platform
npm run build
# Package without building installer
npm run pack
# Build Windows installer
npm run dist
# Build macOS installer (.dmg, unsigned)
npm run dist:macPushing a tag matching v*.*.* (e.g. v1.1.0, matching the version in
package.json) triggers .github/workflows/release.yml,
which builds the Windows and macOS installers and publishes them as assets on
a GitHub Release for that tag. The desktop app checks that release on launch
(and via Help > Check for Updates...) and offers to download and install
whichever asset matches the running platform — see desktop/updater.js.
Neither build is code-signed, so unsigned-app warnings (Windows SmartScreen,
macOS Gatekeeper) are expected until a signing certificate is added.
The web application can be deployed to any static hosting service:
- Copy all files except
node_modulesanddist - Ensure the server serves the
web/index.htmlfile - Configure the server to handle SPA routing
For production deployment, consider:
- Using a proper web server (nginx, Apache)
- Enabling HTTPS
- Configuring appropriate caching headers
- Minifying JavaScript and CSS files
The web version supports:
- Chrome/Edge 80+
- Firefox 75+
- Safari 13+
- Modern mobile browsers
ISC License - feel free to use and modify as needed.
- Fork the repository
- Create a feature branch
- Make your changes
- Test both Electron and web versions
- Submit a pull request
Desktop app won't start:
- Ensure Node.js is installed
- Run
npm installto install dependencies - Check for any error messages in the console
Web app shows blank page:
- Check browser console for JavaScript errors
- Ensure the server is running on the correct port
- Try refreshing the page
File operations not working:
- Desktop: Check file permissions
- Web: Ensure browser allows file downloads
Canvas not responsive:
- Try refreshing the page
- Check if browser supports HTML5 Canvas
- Ensure JavaScript is enabled