Last Updated: November 1, 2026
This guide is maintained with AI-assistance. Please refer to our AI policy.
Read through this guide to learn how C++ code is styled for Huntr Software projects, and how docs, changelogs, and other project writing should read. Each project's CONTRIBUTING.md holds its own conventions (type prefixes, namespaces, export macros, the copyright header), while this guide covers what they share.
New code follows this guide. Older code that doesn't conform should be updated one file at a time, in a commit of its own, never mixed with a behavior change. Until a file is converted, edits inside it should match the surrounding code.
bool expanded{ false }.&&, ||, +, ==, ...) ends with the operator, rather than the next line starting with it.* and & bind to the type: LLayer* layer, const LString& path.LLayer* find_or_create(LLayer* parent, const LString& name)
{
if (LLayer* existing = parent->find_layer(name))
return existing;
return lMake<LLayer>(parent, name);
}
LEngine::LEngine() : pimpl{ new Impl() } {}
LEngine::~LEngine() { delete pimpl; }
LEngine).version_token, not kVersionToken).m_ prefix (m_tokens), so they never clash with a parameter of the same name. Public struct fields don't.b for booleans. Name a boolean so it reads as yes or no: expanded, is_open, has_file.enum class values are PascalCase.new_, old_, v2, or plan and slice numbers.#pragma once: #ifndef LENGINE_H closing with #endif // LENGINE_H..cpp, its own header first, then the standard library, then project headers.static functions in the .cpp.Documentation lives in headers, and a .cpp stays clean.
Document public API with a /** */ block directly above the declaration. Each line starts with *, and text sits two spaces after the star. Editors show these blocks on hover, and Docuriser strips the stars and renders the rest as Markdown: backticks for identifiers, cpp code blocks for examples, ### headings to section a long class doc.
/**
* Finds a layer by its path.
*
* Returns `nullptr` when no layer matches.
*/
LLayer* find_layer(const LString& path);
Open with one sentence. A function starts with a verb ("Finds a layer by its path."), a type with what it is ("Runtime engine that loads .lyr files..."). Then add what a caller needs: return values, failure behavior, ordering requirements.
Doc comments follow the Writing rules below, like any other project writing.
Small members (enum values, struct fields) take a trailing // comment when it fits on the line within about 90 columns. Anything longer gets a /** */ block above the member instead.
In comments and docs, acronyms keep their capitals (URL, JSON, HTML), while identifiers stay snake_case (url).
In a .cpp, comment only what the code can't say for itself, and say why rather than what:
// States are child attributes, so the recursive walk covers them too.
for (LAttribute* attr : pimpl->root->find_children<LAttribute>(true))
No walls of text. A comment that needs several paragraphs belongs in the header docs or a guide.
Comments describe the code as it is now: no "used to", "was changed to", "no longer", references to removed code, or associated plan steps. History belongs in commit messages and CHANGELOG.md.
test-cycles, test-lexer), never for the plan or change that produced it.nullptr, never NULL or 0.auto only where the type is obvious or verbose (iterators, range-for elements); spell it out otherwise.const&, and mark methods that don't mutate const.enum class over plain enum.For JavaScript, CMake, shell, and the rest, match the style of the surrounding code. The comment rules above apply everywhere.
These rules cover all project writing: doc comments, guides, READMEs, changelogs, and site text.
CHANGELOG.md entry in the same commit as the change, under ## [?] - Unreleased at the top until the release's version is set.### Added, ### Changed, ### Fixed, and ### Removed. Add ### Migration when users must act, or ### Recommended when the old way still works but a new one is preferred.