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_tile may block. Do the work on a thread and drain a channel in on_tick.
  • Return None from next_repaint when idle, so Nook stays at 0% CPU.
  • No unwrap() outside tests. Every Win32 call goes through an error-checked wrapper in crates/platform.
  • Keep cargo clippy --workspace --all-targets -- -D warnings clean.

Changing the plugin protocol

The plugin host lives in crates/modules/src/plugins/:

FileWhat it holds
manifest.rsplugin.toml fields and plugin discovery
protocol.rsEvery message and view component
view.rsHow components are drawn and which events they send
host.rsStarting programs, pipes, poll mode, dev-mode reload
mod.rsThe 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.