CalcC is a desktop calculator written entirely in C, built on raylib with signed-distance-field rendering in GLSL and a native Wayland window. Transparent, resizable, fully proportional layout, light/dark theme detected from the operating system, spring animations on the buttons.
Requirements
| Component | Version |
|---|---|
| CMake | ≥ 4.0 (the policy version is set explicitly, 3.x fails) |
| Session | An active Wayland session |
| Toolchain | C11 + pthreads |
| Network | Only at first configure — raylib is downloaded by FetchContent |
raylib 5.0 is fetched automatically at configure time; GLFW 3.4 ships inside
it. System libraries (libGL, freetype, fontconfig) are resolved by the
platform packages.
Build
cmake -S . -B build
cmake --build build -j
./build/calcC
Run from the repository root: the font is loaded by relative path
(assets/Comfortaa.ttf), and launched from anywhere else the app falls back to
raylib's default font without an error message.
CMAKE_BUILD_TYPE defaults to Release (-O3 -DNDEBUG). If build/ already
exists with an empty cache, delete it and reconfigure — otherwise the build
silently compiles at -O0.
Tests
eval_test.c covers the arithmetic engine without opening a window:
gcc -O2 -o /tmp/eval_test eval_test.c logic/eval.c -lm && /tmp/eval_test
Exit code 0 on success. It covers operator precedence, left associativity,
negative numbers and unary minus, eight syntax errors, overflow edge cases,
ten exact formatting contracts, and the absence of node-pool leaks. It is not
wired into CMake: there is no ctest.
How it is built
- A static node pool, not
malloc: 4096 nodes with a free list, O(1), no fragmentation. When the pool runs out the expression is truncated silently — a known limit, recorded in the README. - Two fragment shaders (GLSL 330): one for the SDF panel, one for the background. If the shaders fail to compile the renderer falls back to flat rounded rectangles on the CPU and the app stays usable.
- One source of truth for the keymap: the
KEYS[5][4]table inmain.cgenerates both the layout and the key lookup, so mouse and keyboard cannot disagree. - Theme detection on its own thread:
DetectSystemThemeDark()used to run 19 times per frame (570 ms/frame);bench_baseline.cmeasures the fix.
What it does — and what it deliberately does not
Present: the four operations, modulo (binary fmod, not a percentage),
decimals with both . and ,, Ans to chain the result, navigable history
with ↑/↓, backspace, C, one pending operation (5++3 → 5+3), spring
and ripple animations, proportional layout, system theme.
Absent, by choice: no parentheses, no √, no 1/x, no ±, no memory
keys, no clipboard, no scientific input notation, no localization (the string
Errore and the comments are in Italian).
Known limits
1/0and5%0both produceErrore, with no indication of where the problem is.ExprPopis O(n): it walks to the penultimate node instead of holding a pointer to it. Irrelevant with the 160-token ceiling.- Pool exhaustion truncates silently.
shoot.shstays tied to niri for the floating placement.
Full detail in docs.md
inside the repository.