Directive rules for generating, reviewing and suggesting code in YUP. Apply them on every task.
C++20 graphics/audio library, ISC licensed, forked from the JUCE7 ISC modules. CMake build, Google Test, Rive + OpenGL/Metal/D3D.
Copyright line for new files: Copyright (c) 2026 - kunitoki@gmail.com.
- Never run bash commands to configure, compile or test. Say what should be tested; the user runs it and reports back.
- Code that changed without you noticing is the user's doing, not a linter's. Acknowledge it, never revert it.
- Headers and implementation files are compiled through the main module header/cpp - linter errors when parsing them in isolation are expected.
- Use C++20 and the standard library, unless the feature is unsupported on a YUP platform.
- Check existing patterns in similar modules first; reuse YUP infrastructure instead of reinventing or duplicating it.
- Never assume plain JUCE7 APIs - verify them, they may have evolved (see Differences with JUCE).
- Prefer less code. If 200 lines could be 50, rewrite it. Nothing speculative, no abstraction for single-use code.
- Composition over inheritance. Small single-responsibility classes, open-closed, no leaked internals.
- Const-correct throughout. Flat code with early exits over deep nesting.
- RAII and smart pointers, no raw ownership. Consider thread safety where it applies.
- Adapt or replace an existing implementation - never copy-and-modify and leave both behind.
- Don't pollute implementation files with obvious comments.
- Extensive Doxygen docs on public APIs and public build-system methods.
- Test-first where practical - a bug fix starts with a failing test. New code is always tested; refactors keep tests passing, API contracts intact, platform-specific layout preserved and performance in mind.
- Update
docs/with effective and user targeted documentation (no extensive internal details if not needed) and add a briefCHANGELOG.mdentry when the change warrants it. - Surgical edits: every changed line traces to the request. Don't reformat or refactor adjacent code; do clean up orphans your own change created.
- Avoid the use of em-dashes, just use
-.
Formatting is enforced by .clang-format (Allman braces, 4-space indent, no column limit, Type* ptr alignment, space before non-empty parens: foo (x), TEST_F (Fixture, name)).
PascalCasetypes;camelCasefor functions, variables, members and constants.- One main class per file, named
yup_ClassName.h/yup_ClassName.cpp. using namespaceonly in test files; elsewhere scope it to the smallest block.- Include order: own module header → other YUP modules → same-module headers → external libraries (Rive) → standard library.
- New files start with the ISC header - copy it from
modules/yup_dsp_jit/yup_dsp_jit.h, which already carries the correct2026year (many older files still say2024, and ported JUCE files carry an extra JUCE attribution block that must not be reused). Headers then open with#pragma once. - Module headers add the
BEGIN_YUP_MODULE_DECLARATIONblock right after it (ID, vendoryup, version, name, description, website, licenseISC, dependencies,searchpaths: native). Same file is the exemplar; allyup_*modules share one version number. Details indocs/build-system/module-format.md. - Module layout:
modules/yup_module_name/holdingyup_module_name.h/.cpp/.mm, one level of subdirectory for logical groups, andnative/for platform code namedyup_ClassName_<platform>.cpp-android,windows,linux,wasm,emscripten, plusmac/ios/appleas.mm. Avoid deep nesting (third-party trees excepted, we don't control them). - Modules are unity builds assembled by files in the root which should also resolve global includes, subfolder files are just included there and should not include anything on their own.
- Tests live in
tests/module_name/yup_ClassName.cpp, one per class, plusyup_ModuleIntegration.cppfor integration tests.
class YupStyleClass
{
public:
YupStyleClass();
~YupStyleClass();
void publicMethod();
private:
int memberVar;
YUP_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (YupStyleClass)
};Mirror the structure of an existing test, e.g. tests/yup_dsp/yup_KMeterState.cpp.
- Include the module header and
<gtest/gtest.h>, thenusing namespace yup;. - Test the public interface only, covering normal, edge and error cases.
- Descriptive names:
TEST_F (ClassNameTests, ReturnsNullForInvalidInput). - Group related tests in a fixture; keep them independent and deterministic.
- Keep helpers and constants inside the fixture rather than at file scope - unity builds make file-scope names clash.
- Never use C/C++ macros such as
M_PI; use the YUP alternatives.
YUP_WINDOWS, YUP_MAC, YUP_IOS, YUP_LINUX, YUP_ANDROID, YUP_WASM (any WebAssembly), YUP_EMSCRIPTEN (Emscripten only), YUP_DESKTOP, YUP_MOBILE.
- Fallible operations return
yup::Result(Result::ok()/Result::fail ("...")) oryup::ResultValue<T>(makeResultValueOk (v)/makeResultValueFail ("..."); a plainTconverts implicitly). jassertfor programming errors, paired with a graceful early return for release builds.
- American English:
centernotcentred,ColornotColour. - Check the YUP
GraphicsAPI - do not assume JUCE's. - Graphics primitives convert with the template
.to<float>(), nottoFloat(). - Fonts come from
ApplicationTheme, never instantiated inline.