chore: scaffold Kolmekivi from nih-plug-template

A stereo delay/echo plugin. Scaffolded rather than forked: the template
and the plugins built from it diverge on branding immediately, so they
share code by file copy — as codename-206 does — not by merge base. This
repo starts its own history.

Branded with tools/brand-plugin.sh. Everything derives from PLUGIN_NAME
("Kolmekivi" -> kolmekivi / Kolmekivi / KolmekiviParams), so no override
is pinned. CODENAME is set to the repo name and, by convention, stays
there even if the plugin is later renamed.

Two identity constants are now frozen and must never move, because hosts
key saved projects and presets off them:

    CLAP_ID        org.novoyuuparosk.kolmekivi
    VST3_CLASS_ID  KolmekiviDelay!!            (exactly 16 bytes)

Host categorisation is set for a delay rather than left at the template's
generic placeholders — ClapFeature::{AudioEffect,Delay,Stereo} and
Vst3SubCategory::{Fx,Delay}. These decide where the plugin appears in a
host's browser and are not covered by the branding checker, which knows
about names rather than categories.

The DSP is not written. src/lib.rs still carries the template's example
gain parameter, so the plugin builds, bundles and loads while the delay is
implemented.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WHt4DykxXaQnyaJfyS8KCn
This commit is contained in:
2026-09-04 16:09:53 +09:00
commit 728cce5e97
17 changed files with 4411 additions and 0 deletions
+177
View File
@@ -0,0 +1,177 @@
# Kolmekivi
A stereo delay/echo plugin — Rust, CLAP/VST3, egui.
Scaffolded from [`musiikki/nih-plug-template`](http://192.168.2.199:3005/musiikki/nih-plug-template);
the DSP is not written yet, the plugin currently passes audio through an example gain stage.
## Quick Start
```bash
# Clone this repo as your starting point
git clone http://192.168.2.199:3005/musiikki/nih-plug-template my-plugin
cd my-plugin
# Edit: src/lib.rs, Cargo.toml, bundler.toml — replace placeholder values
# See musiikki/codename-206 for a real-world example of how to fill these in
# Then verify the rename landed everywhere
sh check-branding.sh
```
## Renaming
Identity is duplicated across `Cargo.toml`, `bundler.toml`, `src/lib.rs`, `NOTICE`,
`Cargo.lock`, the CI workflow and the docs. Nothing makes those agree, so a half-finished
rename builds a bundle under one name while CI bundles another.
Everything for it lives in `tools/`:
```
tools/branding.conf the names, and what derives from what
tools/branding-sites.tsv where each name has to appear, and in what form
tools/brand-plugin.sh changes names
tools/check-branding.sh verifies them
```
```bash
sh tools/brand-plugin.sh # interactive; Enter keeps a value
sh tools/brand-plugin.sh --display "Fuzz Box" # or non-interactive; dry run
sh tools/brand-plugin.sh --display "Fuzz Box" --apply
sh tools/check-branding.sh # exit 0 = consistent, 1 = drift
```
**One name drives the rest.** `PLUGIN_NAME` derives the package name (`Fuzz Box` →
`fuzz_box`), the Rust types (`FuzzBox`, `FuzzBoxParams`) and the display name. Each is
overridable in `branding.conf`, because the derivation is sometimes wrong and sometimes
outright invalid — `206 Prototype` derives to `206_prototype`, which Cargo rejects since a
package name cannot start with a digit. The helper refuses those, along with Rust keywords
and built-in crate names.
**The checker does both halves.** Every canonical value is asserted *present* where it
belongs, and every retired spelling is swept for. Absence alone is not enough: renaming to
the wrong new spelling would pass a stale-sweep and still break CI.
**Two things it will not do for you.** `CLAP_ID` and `VST3_CLASS_ID` are how hosts recognise
saved projects and presets — change either and every existing session silently loses the
plugin, with no error. They need `--allow-identity-change`, and the 16-byte class ID is
*proposed* rather than derived, because that choice is yours. And `CLAP_DESCRIPTION` is
rejected if it carries a retired name or the repo codename: hosts show it to users who never
knew your development history.
**The repo name is deliberately not derived.** It is fixed when the repo is created and keeps
its development codename while the plugin gets a product name. `CODENAME` records it so it
can be kept out of user-facing text.
Adding a site the template doesn't ship is one row in `branding-sites.tsv` with owner
`custom` — no shell to edit, and it survives regeneration. Rows the helper owns are rewritten
on each rename; custom rows are carried through and value-substituted like any other file.
Both files can be hand-edited; the helper is what keeps them agreeing, so run the checker
after if you do.
## Build
```bash
# Install Rust via rustup: https://rustup.rs
# No VST3 SDK needed — NIH-plug bundles its own bindings.
# Build + bundle the CLAP (default)
cargo xtask bundle kolmekivi --release
# Add the VST3 as well — see the licensing note below before you do this
cargo xtask bundle kolmekivi --release --features vst3
```
**Output:** `target/bundled/<name>.clap` (and `<name>.vst3` with `--features vst3`), where
`<name>` is the `name` set in `bundler.toml` — **not** the crate name. Out of the box that
means `target/bundled/Kolmekivi.clap`.
On Linux the egui editor needs the GUI development headers:
```bash
sudo apt install pkg-config libgl-dev libx11-dev libxcursor-dev libxcb1-dev \
libxcb-icccm4-dev libxcb-dri2-0-dev libx11-xcb-dev libxkbcommon-dev libxkbcommon-x11-dev
```
## Deploy
### FL Studio
Build with `--features vst3` first if you want the VST3 (see the licensing note below).
FL Studio scans `C:\Program Files\Common Files\VST3` by default, **ignores directory junctions**
(so a symlinked bundle is invisible to its scanner), and caches failed scans.
1. Copy the `.vst3` bundle to a folder FL scans (e.g. `C:\Program Files\Common Files\VST3`).
2. Copy the `.clap` bundle to a folder FL scans (e.g. `C:\Program Files\Common Files\CLAP`).
3. In FL Studio: **Options → Manage plugins → tick "Rescan previously failed plugins" → Find installed plugins**, then search for your plugin name (set in `bundler.toml`).
### Linux
```bash
# CLAP
cp -r "target/bundled/Kolmekivi.clap" ~/.clap/
# VST3 (only exists if you built with --features vst3)
cp -r "target/bundled/Kolmekivi.vst3" ~/.vst3/
# Or globally:
# sudo cp -r "target/bundled/Kolmekivi.clap" /usr/lib/clap/
# sudo cp -r "target/bundled/Kolmekivi.vst3" /usr/lib/vst3/
```
## Project Structure
```
Cargo.toml # Package deps + the opt-in `vst3` feature — NIH-plug pinned to codename-206's rev
bundler.toml # Bundle name for `cargo xtask bundle`
src/lib.rs # Plugin skeleton — params, DSP, and egui editor, with one example gain param
xtask/ # Bundler xtask (cargo xtask bundle)
.cargo/config.toml # xtask alias
tools/ # Branding toolkit — see Renaming
.gitattributes # Pins *.sh to LF so Windows checkouts keep a valid shebang
.github/workflows/ # CI: branding check, both feature sets build, test, bundle
```
## CI
`.github/workflows/ci.yaml` gates pushes and PRs on the branding check, a build of both
feature sets, `cargo test`, and a bundle — enough to catch a rename that only half-landed,
a `cfg(feature = "vst3")` gate that stopped compiling, or a `bundler.toml` that no longer
matches the crate name.
It targets `runs-on: rust-audio`, an **org-scoped** runner label. A plugin cloned into a
different org will not see that runner and its jobs will queue indefinitely rather than fail
— register a runner advertising the label for that org, or change `runs-on`.
Deliberately not covered: plugin performance. Realtime cost can only be measured meaningfully
against a real audio deadline, and `Plugin::process()` cannot be called from a test at all
(`ProcessContext` requires a `Transport`, whose constructor and fields are `pub(crate)` to
nih-plug). Benchmark your DSP types directly if you need it.
## License
**GPL-3.0-or-later.** See `LICENSE` for the terms and `NOTICE` for third-party attribution.
Plugins cloned from this template inherit GPL-3.0-or-later, because the template's own code
is under it. If you need a permissive plugin, this is the wrong starting point — write the
skeleton yourself against NIH-plug directly, which is ISC.
Parts of `src/lib.rs` derive from Robbert van der Helm's NIH-plug cookiecutter template and
`gain` example, both ISC. ISC is GPL-compatible, so that notice is retained in `NOTICE`
rather than superseded.
## VST3 and Steinberg
`vst3-sys`, which `nih_export_vst3!()` needs, is GPLv3-or-later — chosen by its own authors,
who describe their port as a derivative of Steinberg's SDK that "was not made in isolation."
That obligation is what makes a distributed VST3 build GPL-licensed, and it holds regardless
of any question about Steinberg's own rights. Being GPL-3.0-or-later already, this template
satisfies it.
No Steinberg SDK source is vendored or redistributed here, so there is nothing to accept at
build time. Separately from copyright, **"VST" is a trademark of Steinberg Media Technologies
GmbH**; describing a distributed product as a VST plugin is governed by their trademark terms.
If you intend to distribute commercially under that name, that is the part worth legal advice.
CLAP carries none of this — no GPL dependency and no trademark encumbrance.