Built-in modules
Plugins cover most ideas. Write a built-in module instead when you need to draw with egui directly, call Windows APIs inside the process, or run every frame.
The Module trait
Built-ins implement Module from crates/ui/src/module.rs:
rust
use nook_ui::module::{Module, TileCtx, TileSize};
use nook_ui::icons;
#[derive(Default)]
pub struct MyTile { clicks: u32 }
impl Module for MyTile {
fn id(&self) -> &'static str { "my_tile" }
fn name(&self) -> &str { "My tile" }
fn icon(&self) -> &'static str { icons::SPARKLE }
fn size_hint(&self) -> TileSize { TileSize::Small }
fn ui_tile(&mut self, ui: &mut egui::Ui, _ctx: &mut TileCtx<'_>) {
if ui.button(format!("{}", self.clicks)).clicked() { self.clicks += 1; }
}
}Register it in crates/modules/src/lib.rs (register_all) and open a pull request.
House rules
- Nothing in
ui_tilemay block. Do the work on a thread and drain a channel inon_tick. - Return
Nonefromnext_repaintwhen idle, so Nook stays at 0% CPU. - No
unwrap()outside tests. Every Win32 call goes through an error-checked wrapper incrates/platform. - Keep
cargo clippy --workspace --all-targets -- -D warningsclean.
Changing the plugin protocol
The plugin host lives in crates/modules/src/plugins/:
| File | What it holds |
|---|---|
manifest.rs | plugin.toml fields and plugin discovery |
protocol.rs | Every message and view component |
view.rs | How components are drawn and which events they send |
host.rs | Starting programs, pipes, poll mode, dev-mode reload |
mod.rs | The Module implementation that ties it together |
Changes must stay backward compatible: add optional fields and new types, never rename or remove existing ones. Update these docs, both SDKs and the tests in protocol.rs with any new type.