|
Some checks failed
Holocron Frontend CI / lint-and-test (push) Has been cancelled
Self-contained page documenting where track fusion works and where the prototype silently missed duplicates. Draggable contact pair over a to-scale cell grid, live per-gate readout, and the coverage-by-latitude comparison. Opens straight off disk, no build or server needed. |
||
|---|---|---|
| .. | ||
| .dual-graph | ||
| .storybook | ||
| config | ||
| cypress | ||
| docs | ||
| src | ||
| src-tauri | ||
| .prettierignore | ||
| .prettierrc | ||
| CLAUDE.md | ||
| cypress.config.ts | ||
| Dockerfile.dev | ||
| Dockerfile.local | ||
| eslint.config.js | ||
| index.html | ||
| package-lock.json | ||
| package.json | ||
| postcss.config.js | ||
| QUICKSTART.md | ||
| README.md | ||
| server.cjs | ||
| tailwind.config.js | ||
| tsconfig.json | ||
| tsconfig.node.json | ||
| vite.config.ts | ||
| vitest.shims.d.ts | ||
NATO Tactical Display - React Version
A real-time tactical display system built with React, Cesium, and MQTT for visualizing military assets on a 3D globe with MIL-STD-2525 symbology.
🚀 Features
- Real-time Asset Tracking: Live updates via MQTT and WebSocket
- 3D Visualization: Interactive globe using Cesium with satellite imagery and terrain
- Military Symbology: MIL-STD-2525 compliant symbols using milsymbol.js
- Map Layers: Toggle visibility by layer — UAVs, USVs, UUVs, Contacts (and other). Layer toggles control both the map and the Navigation list.
- Compact View Mode: Icon-only 3D / 2.5D / 2D buttons with tooltips to save space
- Navigation List: Asset list filtered by layer, sorted by layer then identifier, with layer badges. Click a row to select, fly to, and show details.
- Asset Selection: Click an asset on the map or in the Navigation list to select it. Selected asset is highlighted on the map and in the list.
- Asset Detail Panel: When an asset is selected, view SIDC (20-digit and human-readable breakdown: Context, Standard Identity, Symbol Set, Status, HQ/TF/Dummy, Echelon, Entity Type), Call Sign, Lat/Long/Altitude, Heading, Speed, and a Sensors section (placeholder when no sensor data).
- Range Rings: For the selected asset, optional range circles (e.g. 5 km, 10 km) on the map. Radius can be set via
description.range_ring_kmor defaults to 5 and 10 km. - Multiple View Modes: 3D, 2.5D (Columbus View), and 2D map views
- Trail Visualization: Path history for each tracked asset
- Responsive UI: Modern, tactical-themed interface with compact status (connection · asset count · last update)
📋 Prerequisites
- Node.js (v16 or higher)
- npm or yarn
- MQTT broker (e.g., Mosquitto) running on
localhost:1883 - For desktop app (Tauri): Rust toolchain
🛠️ Installation
- Install dependencies:
npm install
🏃 Running the Application
The application consists of two parts:
1. Backend Server (Node.js + WebSocket + MQTT)
Start the backend server that bridges MQTT and WebSocket:
npm run server
This will start:
- HTTP server on port
3001 - WebSocket server on port
9002 - MQTT connection to
mqtt://localhost:1883
2. Frontend (React + Vite)
In a separate terminal, start the React development server:
npm run dev
This will start the Vite dev server on port 3333.
3. Access the Application
Open your browser and navigate to:
http://localhost:3333
4. Desktop App (Tauri)
The app can run as a native desktop application using Tauri v2:
npm run tauri:dev
This starts the Vite dev server and opens a native window. The backend server must be running separately (npm run server) for full functionality.
To build a production desktop app:
npm run tauri:build
The built app will be in src-tauri/target/release/. To generate app icons for distribution, run:
npm run tauri icon path/to/your-icon.png
📁 Project Structure
nato-tactical-display/
├── src-tauri/ # Tauri desktop app backend (Rust)
│ ├── src/
│ │ ├── main.rs
│ │ └── lib.rs
│ ├── tauri.conf.json
│ └── Cargo.toml
├── src/
│ ├── components/
│ │ ├── CesiumViewer.tsx # 3D map component
│ │ ├── ControlPanel.tsx # Status and asset list
│ │ └── ControlPanel.css # Panel styling
│ ├── hooks/
│ │ ├── useWebSocket.ts # WebSocket connection hook
│ │ └── useAssetTracking.ts # Asset management hook
│ ├── utils/
│ │ ├── militarySymbol.ts # SIDC generation and breakdown
│ │ └── layers.ts # Layer keys and asset→layer mapping
│ ├── App.tsx # Main application
│ ├── App.css # Application styles
│ ├── main.tsx # React entry point
│ └── index.css # Global styles
├── server.cjs # Backend server
├── index.html # HTML template
├── vite.config.ts # Vite configuration
└── package.json # Dependencies
🔧 Configuration
Environment Variables
You can customize the configuration using environment variables:
Backend (server.cjs):
PORT: HTTP server port (default:3001). UsePORT=3002 npm run start:devwhen 3001 is in use.WS_PORT: WebSocket server port (default:9002)MQTT_BROKER: MQTT broker URL (default:mqtt://localhost:1883)MQTT_TOPIC_PREFIX: Topic prefix (default:r2d2/holocron)MQTT_CLIENT_ID: MQTT client ID (optional; auto-generated if not set)MQTT_USERNAME: MQTT broker username (optional)MQTT_PASSWORD: MQTT broker password (optional)MAPTILER_KEY: MapTiler API key (optional)
Dev proxy (Vite forwards /api and /health to the backend):
API_PORTorPORT: Backend port the proxy targets (default:3001). Set both when using a different port:PORT=3002 API_PORT=3002 npm run start:dev.
Frontend:
- WebSocket URL is loaded from
/api/config(no hardcoding in App.tsx) - Map tiles: set
MAPTILER_KEYin the server environment; the frontend loads it from/api/config(no keys in client code)
MQTT Message Format
The system expects CATL (Common Advanced Tactical Language) format messages:
{
"identifier": "ASSET-001",
"description": {
"name": "Fighter-01",
"context": "ContextEnum_REALITY",
"standard_identity": "StandardIdentityEnum_FRIEND",
"symbol_set": "SymbolSetEnum_AIR",
"status": "EntityStatusEnum_PRESENT"
},
"pose": {
"position": {
"latitude_longitude_altitude": {
"latitude": 46.72,
"longitude": 8.67,
"altitude": [{ "value": 5000 }]
}
}
},
"velocity": {
"speed_and_rate": {
"heading": 90
}
}
}
🎨 Features Breakdown
Asset Visualization
- Military Symbols: Automatically generated from CATL standard identity codes
- Fallback Display: Colored points for assets without symbology data
- Trail Rendering: 60-second path history with glow effects
- Label Display: Asset names with dynamic positioning
Control Panel
- Compact Status: Single row — status dot, connection state, asset count, last update time
- Layers: Checkboxes for UAVs, USVs, UUVs, Contacts. Off layers are hidden on the map and in the Navigation list.
- View Mode: Icon buttons (globe, globe-horizon, map) for 3D, 2.5D, 2D with tooltips
- Navigation: Asset list filtered by layers, sorted by layer then ID; layer badge per row; click to select and fly to asset
- Asset Details: When an asset is selected, SIDC breakdown, position (Lat/Long/Alt), Heading, Call Sign, optional Speed, and Sensors (or “No sensor data”)
- Range Rings: Selected asset shows configurable range circles on the map (e.g. 5 km, 10 km)
Asset Types & Colors
- 🟨 Air Assets: Yellow/Amber
- 🔵 Surface Assets: Blue/Cyan
- 🟢 Ground Assets: Green
- ⚪ Unknown: Gray/White
Identity Indicators
- 🟦 Friend: Cyan
- 🟥 Hostile: Red
- 🟩 Neutral: Green
- 🟨 Unknown: Yellow
🔨 Build for Production
To create a production build:
npm run build
The built files will be in the dist/ directory.
To preview the production build:
npm run preview
🐛 Troubleshooting
WebSocket Connection Failed
- Ensure the backend server is running on port 3001
- Check that WebSocket port 9002 is not blocked by firewall
- Verify MQTT broker is running and accessible
Assets Not Appearing
- Check MQTT broker is publishing to
assets/status/#topic - Verify message format matches CATL specification
- Check browser console for parsing errors
Cesium Not Loading
- Ensure you have internet connection for CDN resources
- Check MapTiler API key is valid
- Verify no CSP (Content Security Policy) blocks
Performance Issues
- Limit number of simultaneous assets (< 100 recommended)
- Reduce trail time in CesiumViewer.tsx
- Lower map tile resolution
Tauri Desktop App
- Port 3333 in use: Ensure no other process is using port 3333; Tauri uses
strictPortand will fail if the port is taken - Rust not found: Install Rust via rustup
- First build slow: The initial
tauri:devortauri:buildcompiles Rust dependencies; subsequent runs are faster
📝 Development
Adding New Features
- New Asset Types: Update
getAssetType()inmilitarySymbol.ts - Custom Symbols: Modify
generateSIDC()for additional SIDC codes - UI Components: Add to
src/components/ - Hooks: Add custom hooks to
src/hooks/
Code Style
- Use ES6+ features
- Follow React hooks best practices
- Use functional components
- Implement proper error handling
- Add PropTypes or TypeScript for type safety
🔐 Security Considerations
- WebSocket connections are not encrypted by default (use WSS in production)
- MQTT credentials should be secured with environment variables
- Implement authentication for production deployments
- Validate all incoming data
- Sanitize user inputs
📚 Technologies Used
- React 18: UI framework
- Vite: Build tool and dev server
- Tauri v2: Native desktop app wrapper
- Cesium: 3D globe and mapping
- WebSocket: Real-time communication
- MQTT: Message broker integration
- milsymbol.js: Military symbol rendering
- Express: Backend HTTP server
📄 License
This project is for demonstration purposes. Ensure compliance with all applicable regulations when deploying in production environments.
🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
💡 Tips
- Use
npm run devfor hot module reloading during development - Use
npm run tauri:devfor a native desktop window with hot reload - Turn layers (UAVs, USVs, UUVs, Contacts) off to focus on specific asset types; list and map stay in sync
- Click an asset on the map or in the Navigation list to select it and see details and range rings
- Use the view mode icons (globe / globe-horizon / map) to switch 3D, 2.5D, 2D
- Assets are automatically cleaned up after 5 minutes of inactivity
📞 Support
For issues or questions:
- Check the browser console for errors
- Verify MQTT messages are being received
- Check network requests in DevTools
- Review server logs for connection issues