搜索

PythonReactSEOPDF
GitHub Skill

starwards-station-ui

Build and modify station screens (weapons, pilot, ecr, etc.) for Starwards - two layout systems (fixed grid vs golden-layout), widget draw patterns, input wiring, color system, JSON Pointer subsystem access, and design constraints for information asymmetry

starwards☆ 39 仓库 Stars1 仓库 Forks

安装与使用

请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。

查看来源 ↗使用指南

技能说明

Skill: starwards-station-ui

Build and modify station screens (weapons, pilot, ecr, etc.) for Starwards.

Architecture

There are TWO layout systems. Don't mix them.

Fixed stations (weapons.ts, pilot.ts, ecr.ts)

Use wrapRootWidgetContainer + subContainer(VPos, HPos) grid. No golden-layout. No jQuery layout containers.

import { HPos, VPos, wrapRootWidgetContainer } from '../container';
const container = wrapRootWidgetContainer($('#wrapper'));

// Place widgets in a 3x3 grid (TOP/MIDDLE/BOTTOM × LEFT/MIDDLE/RIGHT)
drawMyWidget(container.subContainer(VPos.TOP, HPos.LEFT), shipDriver);
await drawRadar(spaceDriver, shipDriver, container); // radar fills remaining space

Grid positions are absolute-positioned divs with CSS transforms. The radar/main widget typically takes the full container; sub-widgets overlay in corners.

Customizable screens (gm.ts, ship.ts)

Use Dashboard (golden-layout v1 wrapper). Do NOT touch this for station work.

Widget patterns

Draw functions (imperative, non-React)

Most widgets are imperative functions that create Tweakpane or PixiJS elements:

// Signature pattern
export function drawMyStatus(container: WidgetContainer, shipDriver: ShipDriver): void;
// Or async if it needs awaiting:
export async function drawMyRadar(spaceDriver: SpaceDriver, shipDriver: ShipDriver, container: WidgetContainer): Promise<void>;
Widget factory functions (for golden-layout registration)

Used in gm.ts and ship.ts, NOT in fixed stations:

export function myWidget(shipDriver: ShipDriver): DashboardWidget { ... }

Fixed stations call drawXxx() directly. They do NOT use widget factory functions.

Input wiring

import { InputManager } from '../input/input-manager';
import { readWriteProp, writeProp, readWriteNumberProp } from '../property-wrappers';

const input = new InputManager();

// Momentary click (fire-once on keydown)
input.addMomentaryClickAction(writeProp(shipDriver, '/chainGun/isFiring'), 'space');

// Toggle (flip boolean on click)
input.addToggleClickAction(readWriteProp(shipDriver, '/chainGun/loadAmmo'), 'r');

// Range (continuous value, keyboard offset)
input.addRangeAction(readWriteNumberProp(shipDriver, '/smartPilot/rotation'), {
    offsetKeys: new KeysRangeConfig('e', 'q', 'e+q,q+e', 0.05),
});

// Gamepad
input.addRangeAction(readWriteNumberProp(shipDriver, '/smartPilot/rotation'), {
    axis: new GamepadAxisConfig(0, 0, [-0.1, 0.1]),
});

input.init(); // must call at end
Existing key bindings (DO NOT CONFLICT)

Weapons station: ] [ ' p o i x c v Pilot station: q e a d w s r f z + gamepad axes 0,2,3 + buttons 5,6,7,10,11,14 ECR station: 1-0 a-l (with shift variants), ` ] [ \

Color system

Import from ../colors:

  • PixiJS hex: white, red, blue, yellow, green, selectionColor
  • Radar: radar.speedLine, radar.shellTint, etc.
  • Status: status.ok, status.warn, status.error
  • HSL palette: hsl.primary.main(index) (0=light, 12=dark), hsl.secondary, hsl.error
  • CSS helpers: toCss(hexColor), withAlpha(hslColor, alpha)

Primary = cyan (#00ffff). Secondary = orange (#ff6600). Background = near-black (#0a0a0a).

ARWES (lobby only)

ARWES components (arwes-compat.tsx) are used in the lobby (index.tsx/lobby.tsx), NOT in station screens. Station screens use Tweakpane for controls and PixiJS for rendering. Don't import ARWES into station code.

Screen entry point pattern

Every station follows this structure:

// 1. Parse URL params
const shipUrlParam = urlParams.get('ship');

// 2. Connect driver, wait for ship
const driver = new Driver(window.location).connect();
const statusTracker = new ClientStatus(driver, shipUrlParam);
await driver.waitForShip(shipUrlParam);

// 3. Reload on disconnect
statusTracker.onStatusChange(({ status }) => {
    if (status !== Status.SHIP_FOUND) location.reload();
});

// 4. Get drivers
const shipDriver = await driver.getShipDriver(shipId);
const spaceDriver = await driver.getSpaceDriver();

// 5. Draw widgets into container
const container = wrapRootWidgetContainer($('#wrapper'));
// ... drawXxx calls ...

// 6. Wire input
wireInput(shipDriver);

Ship subsystem pointers

Access ship state via JSON pointer strings:

  • /chainGun/isFiring, /chainGun/loadAmmo, /chainGun/rateOfFireFactor
  • /tubes/0/isFiring, /tubes/0/loadAmmo, /tubes/0/changeProjectileCommand
  • /weaponsTarget/nextTargetCommand, /weaponsTarget/clearTargetCommand
  • /weaponsTarget/shipOnly, /weaponsTarget/enemyOnly, /weaponsTarget/shortRangeOnly
  • /smartPilot/rotation, /smartPilot/maneuvering/x, /smartPilot/maneuvering/y
  • /warp/levelUpCommand, /warp/levelDownCommand, /warp/standbyFrequency
  • /docking/toggleCommand
  • /afterBurnerCommand, /antiDrift, /breaks
  • /ecrControl
  • System power/coolant: /{systemPointer}/power, /{systemPointer}/coolantFactor

Design constraints

  1. Information asymmetry: Each station should show ONLY what that role needs. Don't duplicate data across stations.
  2. No HP bars: Show concrete system states, not abstract health numbers.
  3. Systems filter by relevance: When showing system status on a station, filter to only relevant systems:
    shipDriver.systems.filter(s => 
        s.pointer.startsWith('/tubes/') || 
        s.pointer === '/chainGun' || 
        s.pointer === '/magazine' || 
        s.pointer === '/radar'
    )
    
  4. Template selection: Fixed stations use templates/station.html (full-screen wrapper). Customizable screens use templates/sidebar.html (with golden-layout menu).

Checklist before submitting

  • No golden-layout imports in fixed station code
  • No ARWES imports in station code
  • No key binding conflicts with other stations
  • npm run build passes
  • npm run test:types passes
  • All CI jobs pass (no disabling tests or changing CI config)

使用示例

查看来源仓库中的使用示例与配置说明。

查看来源 ↗

来源历史

收录时间
2026-03-11
索引更新时间
2026-03-11
Branch
main

收录与同步日期属于本站记录。源码修改历史请查看来源仓库。

GitHub ↗

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!