원클릭으로
code-style
Use when someone asks to apply code style rules, check code style, clean up code style, or follow project code conventions.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when someone asks to apply code style rules, check code style, clean up code style, or follow project code conventions.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when working on the klangscript module, implementing klangscript language features, working on the parser or interpreter, or needing klangscript architecture knowledge.
Autonomous tutorial generator — brainstorms a tutorial idea, implements it, self-reviews, and links it into the registry. Designed for /loop.
Use when working with Kraft UI framework, io.peekandpoke.kraft, Kraft components, VDom, Kraft routing, Kraft forms, Kraft modals, Kraft toasts, Kraft popups, or any io.peekandpoke.kraft.* package.
Use when working with ultra libs, io.peekandpoke.ultra, ultra.html events, ultra streams, ultra common utilities, or any io.peekandpoke.ultra.* package.
Use when working on the sprudel / sprudel-ksp module, implementing sprudel DSL functions, writing sprudel tests, or needing sprudel architecture knowledge.
Use when working on the klangblocks module, implementing block editor features, working on AST-to-blocks conversion, code generation, or round-trip testing for the visual block editor.
| name | code-style |
| description | Use when someone asks to apply code style rules, check code style, clean up code style, or follow project code conventions. |
Loads the code style and coding convention rules for the Klang project. Apply these rules whenever writing or editing code.
All if, else, for, while, and when branch bodies must use { }, even for one-liners.
Wrong:
if (condition) doSomething()
if (condition) doSomething() else doOther()
Correct:
if (condition) {
doSomething()
}
if (condition) {
doSomething()
} else {
doOther()
}
lower_case.kt.
In folders that also contain class files, use a _ prefix (e.g., _staff_pos_helpers.kt) to
group utility files at the top of the file tree. In folders with only utility files, skip the
prefix — when every file starts with _, it adds noise instead of value._utils.kt make it
impossible to tell what's inside without opening the file.Wrong: ClippingFunctions.kt (class inside is ClippingFuncs — name mismatch)
Wrong: _utils.kt (not unique, not descriptive)
Correct: ClippingFuncs.kt (matches class)
Correct: _staff_pos_helpers.kt (utility file alongside class files — _ groups it at top)
Correct: math.kt, chain_rendering.kt (utility-only folder — no _ prefix needed)
Shared DSP utilities (flushDenormal, shape resolution, etc.) must live in exactly one place
and be imported. Never copy a utility function into another file as a private copy.
Canonical location: DspUtil.kt in the module root package.
If two files need the same data class (e.g., ResolvedShape) or lookup logic (e.g., distortion
shape resolution), extract it to a shared file. Both callers import from the same source.
This is a real-time audio engine — every CPU cycle counts, in DSP code and the UI layer. Several Kotlin types are boxed (heap-allocated wrapper objects) when compiled to JavaScript. Never use them anywhere in the project.
| Type | JS representation | Problem |
|---|---|---|
Long | Emulated kotlin.Long class (pair of 32-bit ints) | Always boxed, allocation on every operation |
ULong | Wraps Long | Same boxing as Long |
Byte | JS number + range checks | Coercion/masking overhead on every operation |
Short | JS number + range checks | Coercion/masking overhead on every operation |
UByte | Inline class wrapping Byte | Same overhead as Byte |
UShort | Inline class wrapping Short | Same overhead as Short |
Char | Boxed kotlin.Char wrapper | Heap allocation |
| Instead of | Use |
|---|---|
Long / ULong | Int for counts/indices, Double for time values |
Byte / UByte | Int (mask with and 0xFF if needed) |
Short / UShort | Int (mask with and 0xFFFF if needed) |
Char | Int (char code), or String for text |
This applies project-wide — audio DSP, audio bridge, klangscript, sprudel, UI layer,
everywhere. If a Long (or other banned type) arrives from an external API, convert it to
Int or Double at the boundary immediately.
Wrong:
var absPos = ctx.blockStart - startFrame // Long arithmetic
for (i in 0 until ctx.length) {
doWork(absPos) // Long in hot loop
absPos++
}
val midi: Byte = 60 // Byte with range-check overhead
val char: Char = 'A' // Boxed Char wrapper
Correct:
var absPos = ((ctx.blockStart + ctx.offset) - startFrame).toInt() // Convert at boundary
for (i in 0 until ctx.length) {
doWork(absPos) // Int in hot loop
absPos++
}
val midi: Int = 60 // Plain JS number
val char: Int = 65 // Char code as Int, or use String for text
No FloatArray(), listOf(), toList(), Pair(), String concatenation, or object creation
in per-sample or per-block audio processing code. Pre-allocate buffers at construction time.
Wrong:
override fun process(buffer: FloatArray, offset: Int, length: Int) {
val temp = FloatArray(length) // Allocation every block!
}
Correct:
private var temp: FloatArray = FloatArray(0)
override fun process(buffer: FloatArray, offset: Int, length: Int) {
if (temp.size < length) {
temp = FloatArray(length)
} // Resize only when needed
}
Never use require(), check(), or throw exceptions in audio processing code.
These allocate strings and can kill the AudioWorklet thread.
Every IIR filter (SVF, one-pole, allpass, DC blocker) must flush denormals from its
state variables after each update. Use the shared flushDenormal() from DspUtil.kt.
Why: Denormal floats can cause 10-100x CPU spikes on some platforms.
ic1eq = flushDenormal(2.0 * v1 - ic1eq)
ic2eq = flushDenormal(2.0 * v2 - ic2eq)
All oscillators with signal discontinuities (saw, square, pulse) must use PolyBLEP anti-aliasing. Triangle is exempt (aliasing at -12dB/oct from derivative discontinuity is acceptable).
LFO and oscillator phase accumulators must be wrapped to prevent unbounded growth.
Use if (phase >= TWO_PI) phase -= TWO_PI or the wrapPhase() helper.
Why: Unbounded phase loses sin() precision as the mantissa runs out of bits.
Standard DSP coefficient names (a, k, q, g, v, p) are accepted when they
match established mathematical or DSP textbook conventions.
.toFloat() / .toDouble() at Buffer Boundaries Are ExpectedAudio code computes in Double for precision and stores in FloatArray for memory/perf.
The conversions at the boundary are intentional — do not flag them as unnecessary casts.
@Suppress("NOTHING_TO_INLINE") Is Accepted on Audio Hot-Path Inline FunctionsThe Kotlin compiler warns that inlining is unnecessary for non-lambda functions. In audio code, avoiding call overhead is intentional. The suppression is accepted.
@Suppress("unused") Is Accepted on API Surface LibrariesCollections of utility functions (e.g., ClippingFuncs) may have members that aren't all
currently referenced but form a coherent API. The suppression is accepted.
== true on Boolean? Is Correct Kotlin IdiomWhen a Boolean is nullable, x == true is the correct and idiomatic null-safe check.
Do not flag this as a style issue.
Well-known algorithm tuning constants (Freeverb delay lengths, PolyBLEP thresholds, etc.) are acceptable as inline numeric literals when documented with a source comment.
// Freeverb standard comb tunings (designed for 44100 Hz)
private val combTuning = intArrayOf(1116, 1188, 1277, 1356, ...)
Every .kt source file must begin with the project license header as its very first lines,
above any @file: annotation or package declaration:
/*
* Copyright (C) 2025-2026 The Klang Audio Motör Authors (see AUTHORS.MD)
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
New files: IntelliJ inserts this automatically via the "Klang AGPL" copyright profile in
.idea/copyright/. When creating files outside the IDE, add the header manually.
Year: the end year tracks the current year — IntelliJ's "Update copyright" before-commit action keeps it current. Don't hand-edit the year per file.
Brand: always "Motör" with the ö — never "Motor".
Exempt: .kts build scripts, and any third-party / vendored file that carries its own
copyright notice (never overwrite someone else's notice with ours).
tones/ module is MIT, not AGPL. It is a Kotlin port of tonal.js (MIT) and is licensed MIT
to match upstream. Files there use a different header that also credits danigb — never apply the
AGPL header inside tones/:
/*
* Copyright (C) 2025-2026 The Klang Audio Motör Authors (see AUTHORS.MD)
* Portions derived from tonal.js — Copyright (c) 2015 danigb.
* SPDX-License-Identifier: MIT
* Full license: tones/LICENSE
*/
IntelliJ applies this automatically via the "Klang tones MIT" copyright profile scoped to tones/.