Thanks for helping DSCC. Keep changes focused, avoid broad rewrites, and do not copy implementation details from incompatible projects.
git status --short --ignored- Use
rgorrg --fileswhen searching. - Do not revert unrelated local changes.
- Do not commit private notes, raw captures, build output, MSI files, or local agent instructions.
- If you touch HID reports, telemetry packet layouts, controller assets, Sony tooling, Steam Input, or protocol constants, document the public source or original experiment in the PR.
- Use
docs/provenance-policy.mdbefore adding protocol constants, packet fields, HID offsets, Steam Input assumptions, or provider behavior. - Use
docs/game-module-template.mdfor game, parser, or profile-pack PRs.
Install Rust, Node.js 24, and the Windows GNU Rust target/toolchain used by the
project. On Linux, install libudev-dev for hidapi.
npm.cmd --prefix web ciUseful root commands:
npm.cmd run dev
npm.cmd run check
npm.cmd run check:perf
npm.cmd run check:web
npm.cmd run check:rustPowerShell note: use npm.cmd; npm.ps1 may be blocked by execution policy.
On this Windows host, plain cargo may fail because MSVC link.exe is not on
PATH. Use:
cargo +stable-x86_64-pc-windows-gnu fmt --all -- --check
cargo +stable-x86_64-pc-windows-gnu test --workspace
cargo +stable-x86_64-pc-windows-gnu clippy --workspace --all-targets -- -D warningsRun the full local app:
npm.cmd run devRun only the agent:
cargo +stable-x86_64-pc-windows-gnu run -p dscc-cli -- serve --addr 127.0.0.1:43473Run UI-only mock mode:
npm.cmd --prefix web run dev:mockMock mode is for development only. Production builds ignore mock toggles and do not include the fixture bundle.
Run without writing to real controller hardware:
$env:DSCC_DISABLE_HARDWARE_OUTPUT='1'
# or
$env:DSCC_ENABLE_HARDWARE_OUTPUT='0'Normal users enable LAN Access in the app. Direct agent launches that bind to a non-loopback address require explicit opt-in:
$env:DSCC_ENABLE_LAN_API='1'
$env:DSCC_ENABLE_LAN_FORZA='1'The tray may pass DSCC_ENABLE_LAN_API=1 so the UI can save the LAN setting,
but the saved listenOnAllInterfaces setting still controls actual exposure.
- Keep
App.svelteas the shell and state coordinator. - Put feature code in
web/src/lib/features/<feature>/when possible. - Keep API calls in
web/src/lib/api.ts. - Keep shared UI types in
web/src/lib/types.ts. - Use Svelte 5 event attributes such as
onclickandoninput. - Use
@lucide/svelteicons when adding controls. - Clean up timers, sockets, listeners, and polling.
- Keep expensive Steam or filesystem work out of render paths.
- Preserve the dense app UI style. This is an operational tool, not a landing page.
Global Profile is controller-only tuning. Do not show telemetry streams, RPM controls, adapter packet status, or game-signal routing until a supported game profile is selected.
Use direct release and support copy:
- State the fact first. Skip setup phrases.
- Name the actor when describing security, install, or hardware behavior.
- Use active voice.
- Cut filler, softeners, and broad claims.
- Prefer two precise bullets over three vague ones.
- Avoid long dash punctuation in committed docs.
- Add typed request/response structs.
- Validate input before touching state, hardware, or the filesystem.
- Keep mutating routes behind the same-origin guard.
- Persist durable changes with existing state helpers.
- Add route tests for success and failure paths.
- Add cross-origin rejection tests for security-sensitive mutations.
Do not add raw HID-byte routes. Hardware output routes must accept high-level intent and use typed output/profile paths.
DSCC has two module layers:
- Game modules identify games and profiles.
- Adapter modules read telemetry.
Use a profile pack when the game already works through an existing adapter. Add a built-in Rust adapter when new parsing, shared memory, filesystem access, or runtime behavior is needed.
Rules:
- Keep
moduleIdas the game module id andadapterIdas the telemetry adapter id. - Forza Horizon 5, Forza Horizon 6, and Forza Motorsport remain separate game
modules even when they share
forza-data-out. - Assetto Corsa Rally uses
assetto-shared-memory. - Community modules are data-only until DSCC has a sandbox/signing model.
See Game Module Contribution Guide.
Controller output has a hard boundary:
- Frame model:
crates/dscc-core - Encoding/clamping:
crates/dscc-device/src/output.rs - HID transport:
crates/dscc-device/src/hidapi_transport.rs - Runtime write path:
ControllerOutputManagerand agent output loops
Keep these promises:
- No raw report bytes in the API.
- Manual tests are time-limited.
- Stale/no-telemetry game state keeps triggers and rumble neutral.
- Supported-game detection may emit lightbar-only output.
- DualSense Edge onboard writes use guarded USB or Bluetooth HID feature-report paths and only report synced after acknowledgement plus typed readback. Unavailable hardware paths stage locally.
Steam Input writes touch user files. Preserve these guards:
- Write only guarded
controller_*.vdffiles. - Never write
controller_base*.vdf. - Keep canonical Steam root checks.
- Keep the 256 KB layout file limit.
- Honor
dryRun. - Create backups before real writes.
- Preserve
groupId, source, source mode, input id, and activator identity.
Run the button mapping guard when changing this area:
npm.cmd --prefix web run test:button-mapRun the source audit when changing API routes, diagnostics, support bundles, installer packaging, or bridge/provider copy:
npm.cmd --prefix web run test:source-auditFor docs-only changes, inspect the diff. For code changes, run the smallest validation set that covers the risk:
npm.cmd run check:web
npm.cmd run check:rust
npm.cmd run checkFor UI changes, also open the local app and verify the affected screen. Layout-affecting changes should run the mock visual smoke guard:
npm.cmd --prefix web run test:visual-smoke