Station Development Rules
When working on files in js/stations/, follow these established patterns to maintain consistency across all stations.
File Organization
Each station must have its own file. Do not combine multiple stations in a single file. Create a new file following the naming convention below.
Naming Conventions
- •File name: Use lowercase, single word (e.g.,
helm.js,comms.js,navigation.js,tactical.js) - •Class name: PascalCase with "Station" suffix (e.g.,
HelmStation,CommsStation,NavigationStation) - •Export name: camelCase with "Station" suffix (e.g.,
helmStation,commsStation,navigationStation)
Required Structure
Every station class must implement the following pattern:
javascript
/**
* [Station Name] Station
* [Brief description of station purpose]
*/
import { gameState } from '../core/state.js';
import { renderer } from '../core/renderer.js'; // Only if using canvas
import { audio } from '../core/audio.js';
class [StationName]Station {
constructor() {
this.container = null;
// Add station-specific properties here
}
init(container) {
this.container = container;
this.render();
this.setupEventListeners();
}
render() {
// Generate HTML structure
this.container.innerHTML = `...`;
}
setupEventListeners() {
// Attach all event listeners
}
update(timestamp) {
// Called every frame for game loop updates
}
destroy() {
// Cleanup when station is switched away
}
}
export const [stationname]Station = new [StationName]Station();
Required Methods
- •
init(container): Initialize the station with a DOM container. Must callrender()andsetupEventListeners(). - •
render(): Generate and insert the station's HTML structure intothis.container. - •
setupEventListeners(): Attach all DOM event listeners. Called once during initialization. - •
update(timestamp): Called every frame by the simulation loop. Update displays, animations, and game state. - •
destroy(): Cleanup method called when switching stations. Remove listeners, clear intervals, etc.
Layout Structure
All stations should use the station-layout class with a station-specific layout class:
html
<div class="station-layout [stationname]-layout">
<!-- Station content -->
</div>
Examples: helm-layout, comms-layout, tactical-layout, etc.
Registration
After creating a new station file, register it in js/main.js:
- •Add import:
import { [stationname]Station } from './stations/[stationname].js'; - •Add to stations registry:
[stationname]: [stationname]Station, - •Add corresponding tab in
index.htmlif needed
Common Patterns
- •Canvas usage: If the station uses a canvas, store it as
this.canvasand initialize withrenderer.init(this.canvas) - •State listeners: Use
gameState.on('eventName', callback)for reactive updates - •Audio feedback: Use
audio.playClick(),audio.playBeep(),audio.playError(), etc. for user interactions - •Update frequency: In
update(), use timestamp-based checks to avoid excessive updates (e.g.,if (Math.floor(timestamp / 500) % 2 === 0))
Best Practices
- •Keep station logic self-contained within the class
- •Use descriptive method names that indicate purpose
- •Handle edge cases (null checks, disabled states, etc.)
- •Follow the existing visual style and UI patterns
- •Ensure proper cleanup in
destroy()to prevent memory leaks