The Size of the Dream
Ariandel started with one sentence from Dad on 2026-10-01, and that sentence set the scale before a line of code existed:
"The goal this time is to dream big and build our very own Procreate. … It's Pippa, planted inside Procreate." — Dad (translated from Korean)
So: a Procreate-class painting app for the iPad, with Pippa beside the canvas in voice mode, looking at the picture when she needs to. The repository was born that night at 21:51, and TestFlight build 1 went up at 22:51. An hour is nowhere near enough time to write a brush engine. It is enough time to choose one, as long as the choosing is honest.
The Charter: Measure Before You Build
The todo that started it all (coop todo #294) carried two rules about engines. First, evaluate established open-source drawing technology before proposing anything bespoke. Second, base that evaluation on the repositories' actual local state, not on whatever earlier conversation had claimed about them. Dad named two candidates and had both cloned on office, the Mac that runs the family's builds.
The second rule is the one everybody skips. "MaLiang is a Swift brush engine for iOS" is a sentence. It might even be true. What it isn't is evidence about whether MaLiang compiles in the language mode you ship, or whether it can mix paint. A compiler and a source tree answer those questions in minutes.
Two Engines on the Bench
| MaLiang | libmypaint | |
|---|---|---|
| Clone HEAD | 594cd9e | d5a88fb |
| License | MIT | ISC |
| Activity | Last release 2.9.2 on 2020-12-16 | Last commit 2026-04-14; master is the 2.0.0-beta API |
| Language and size | Swift 5 and Metal, about 2,400 lines | C99, about 6,400 lines |
| Brush model | GPU stamping of a texture along Bézier curves | Procedural elliptical dabs, 65 settings over 18 inputs |
| Paint mixing | None | Smudge with spectral pigment mixing, eraser, lock alpha, colorize, posterize |
| Layers | None | None, by design: the surface is the host's job |
What the Builds Said
- libmypaint on the Mac. Its sixteen library sources, the generated settings headers, a three-line
config.hand json-c built with Apple clang. Five brushes from upstream's own test set (charcoal, modelling, bulk, impressionism, coarse bulk) rendered along pressure-ramped curves in 16.2 ms of CPU time. That's all five together. - libmypaint for the iPad. The same sixteen files compiled for
arm64-apple-ios17.0with zero errors. OpenMP is compiled out (#ifdef _OPENMP), so the library does its tile work on one thread. - MaLiang in Swift 5 mode. It failed first on a missing
import UIKitinGlowingBrush.swift. With that one line added it built, with deprecation warnings. - MaLiang in Swift 6 mode. Swift 6 language mode is the family's ruled direction, and Ariandel itself is built in it. MaLiang produced 33 distinct errors there.
Teach the Code, Not the Summary
The evaluation document says libmypaint is "driven by 64 settings and 18 inputs." The generated header at the vendored commit lists 65 MYPAINT_BRUSH_SETTING_* entries and 18 MYPAINT_BRUSH_INPUT_*, and upstream's brushsettings.json agrees: 65 and 18. So this quest says 65. An off-by-one in a write-up stays harmless right up until somebody builds a settings screen from it. When a document and the code it describes disagree, the code wins, and the fix is to count again with a tool, not to remember harder.
Those inputs matter more than the count does. Pressure, tilt declination and ascension, barrel rotation, speed, direction, view zoom: that's already the vocabulary an Apple Pencil speaks. And the setting upstream calls "Pigment" (paint_mode) does subtractive spectral mixing, so colors blend the way paint does instead of the way RGB averages.
What Nobody Measured
The evaluation wrote down its own blind spot: latency under Apple Pencil, feel, and memory on an iPad. Neither engine had run on Dad's hardware yet. As an instrument reading, that's still true. Ariandel has shipped two dozen builds since, and there is still no latency measurement on record. Feel gets reported by the person holding the Pencil; it hasn't been measured. Wherever it matters, this quest says so.
The Decision
libmypaint became the engine: maintained, ISC-licensed, the engine MyPaint, GIMP and OpenToonz already paint with, already fluent in Pencil, already mixing paint, and leaving exactly the app's parts (tiles, layers, compositing, persistence) to the app. MaLiang became a reference, not a dependency. In the evaluation's words, adopting it would have meant "a Swift 5 exception in a Swift 6 family for an engine weaker than the one chosen." One MaLiang idea survived, stamping a grain texture, and the evaluation even said where it would live if it ever arrived: in Ariandel's surface layer, as a modulation of libmypaint's dabs. Track 5 shows it arrived, and it landed exactly there.