Contributing to QRKude
Thanks for helping! QRKude promises that the same style document produces the same QR code in every language. Most of the rules below exist to keep that promise.
How the repository fits together
core/ C99 reference implementation (encoder, shapes, SVG, raster)
docs/GUIDE.md concepts for users (how QR codes work, scannability)
docs/STYLES.md every style option with pictures
docs/SPEC.md normative description of the behaviour, for port authors
docs/tools/ generator for the pictures in docs/images/
spec/vectors/ conformance vectors generated from core/
spec/tools/ vector generator, decode checker
packages/* ports (web, python, rust, dart, flutter) and wrappers
(qt, arduino, esp-idf, lvgl)
Changing behaviour (new shape, new option, bug fix in the output)
- Implement it in
core/first, with unit tests incore/tests/. - Describe it in
docs/SPEC.mdprecisely enough that a port can be written from the text alone (exact geometry, emission order, rounding). - Add cases to
spec/tools/gen_vectors.pyand regenerate:make -C core && python3 spec/tools/gen_vectors.py. - Check scannability:
python3 spec/tools/check_decode.py(needspip install zxing-cpp cairosvg pillow). Every new style should decode with zxing; if it does not in some combination, add alintrule. - Update every port until its vector tests pass again. A pull request that changes vectors without updating the ports is fine as long as it says so; ports are then fixed in follow-ups before the next release.
- Update the documentation (next section).
Purely internal changes (performance, refactors, new helpers in one package) do not need vectors, as long as all vector tests keep passing.
Determinism rules for ports
- Numbers in SVG go through
fmt()(SPEC §8.1):floor(v * 1000 + 0.5)followed by integer formatting. Never use the language’s own fixed-point formatter. - Keep the operation order of the C code for geometry (
(1 - s) / 2,rho * s / 2,sqrt(2.5) * h…). IEEE doubles then agree bit for bit. - Compare points with exact equality where the reference does (path
normalization,
H/Vselection). - Gradient directions for 0/90/180/270 degrees are exact constants, not
cos/sinresults.
Documentation
QRKude is used by people who are not QR code experts, so documentation is part of every change:
- A new or changed style option goes into
docs/STYLES.md(table row, default, range, a picture) and intospec/style.schema.json. Add it todocs/tools/gen_images.pyand runmake -C core && python3 docs/tools/gen_images.py. - A new scannability rule (lint flag) goes into the table in
docs/GUIDE.mdwith what it means and how to fix it. - Package READMEs share one structure (Status and installation, Quick start, Styling, Output, Content helpers, Making sure it scans, Untrusted styles, API reference, Platform notes, Development, License). Keep the API reference complete: every public symbol, one line each.
- Every code example must run. Before merging, extract the examples you touched and run or compile them.
- Write plain English with short sentences. Explain a term the first time you use it, or link to the glossary. Do not link to URLs that do not exist yet.
Running the tests
| package | command |
|---|---|
| core | make -C core test |
| core under sanitizers | see the core job in .github/workflows/ci.yml |
| vectors up to date | python3 spec/tools/gen_vectors.py && git diff --exit-code spec/vectors |
| decode check | python3 spec/tools/check_decode.py |
| others | see each package README |
Code style
- Match the surrounding code. C: C99, 4 spaces, no allocation in the core.
- Every source file starts with:
Copyright 2026 The QRKude Authors SPDX-License-Identifier: Apache-2.0
License
By contributing you agree that your contributions are licensed under the
Apache License 2.0 (see section 5 of LICENSE).
This page is CONTRIBUTING.md in the QRKude repository.