# CLAUDE.md ## Style - Keep everything short: replies, explanations, comments, docs. - Use simple English: short sentences, common words. - Avoid em dashes (—). Do not just swap them for "-" either. Rewrite the sentence instead, for example with a comma, a colon, brackets or two sentences. ## Commits - English only. - Conventional Commits prefix: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `ci:`, `build:`, `test:`. - Subject as short as possible. Imperative, lowercase, no trailing period. - Body only when something genuinely cannot be inferred from the diff. - Never add `Co-Authored-By`, "Generated with" or any other AI attribution to commits or PR descriptions. - Do not commit or push before I have checked the changes locally and said they are fine. Then commit and push. Several attempts at the same thing make one commit, and attempts that did not work make none. Different things done in one session get a commit each. This also goes for releases and tags. ## Project - The plugin is Rust (`src/`) and talks to OpenDeck through the `openaction` crate. It runs on one thread: every event is a task of its own (tokio `LocalSet`). Never hold a `RefCell` borrow across an `.await`. Settings come from the settings pages as loose JSON ("5" for 5, null for ""). Each action reads them into its own struct with `k.settings::()` (`#[derive(Deserialize, Default)]` and `#[serde(default, rename_all = "camelCase")]`): `src/settings.rs` reads every field the way JavaScript would. Use `String`, `bool`, `f64` or `serde_json::Value` fields, nothing that can fail. - `make package` builds for x86_64 and aarch64 with an old glibc (2.28), so it runs on older distributions too. It needs zig, `cargo-zigbuild` and the Rust library for aarch64 (Arch: `rust-aarch64-gnu`). `make install` only builds for this PC. Dev tools are Rust too: `cargo xtask` lists them. - Plugin ID is `de.felitendo.obs-tools` (folder `de.felitendo.obs-tools.sdPlugin`), like the Feishin plugin. Do not change it again: OpenDeck keys profiles and settings by it. - `manifest.json`, `de.json`, `pi/lib/shared.js` and the icons in `images/` are generated. Change the actions in `src/manifest.rs` or the glyphs in `src/icons.rs`, then run `make manifest` or `make icons`. `make icons` first measures every glyph (`cargo xtask fit-glyphs`, needs ImageMagick), so all icons end up the same optical size and optically centered (halfway between the middle of the box and the center of mass, so a play triangle does not look too far left). The action order in `src/manifest.rs` is the order in OpenDeck: most used first. - The settings pages stay JavaScript (`pi/`): they run in OpenDeck's web view. What they share with the plugin (German texts, glyphs) comes from Rust through `pi/lib/shared.js`. `pi/lib/render.js` draws the same key pictures as `src/render.rs`: change both, `make check` compares them. - Settings pages come from `pi/schemas.js`. A new setting needs a default in the `defaults` of the action (its `Kind` in `src/actions/`), a field in its settings struct and a field in the schema. The test `every_setting_has_a_default` checks that each field has a default. The status line is on top. Its "Change" button opens the connection settings right below it, and they open by themselves while OBS cannot be reached. The settings of the key follow in sections (`section` in `pi/schemas.js`): what the key is about, Controls, On the key, and closed sections for the rest. Use the own `dropdown()`, `checkbox()` and number stepper in `pi/pi.js`, never native `