| study (临摹) | repainting from the source as a reference. Judged by whether it looks like a person painted it and whether it resembles the source at low frequencies, not by matching pixel for pixel |
| replica (复刻) | reconstructing the source pixel for pixel. The old route’s goal, judged by PSNR |
| 1x / 4x / 8x | the source’s resolution (1024x1536), the default delivery resolution (4096x6144), and 8K (8192x12288, more than twice as slow and an option only). The planner works at 1x and painting happens at 4x; a stroke length quoted “@8x” in this book is a historical figure |
| sub-part / part | a piece segmentation produced: a face, a torso, a skirt, a frill. One row of the hand-written ASSIGN table, and what the one-shot route builds its groups from |
| group | the layered route’s unit of layering: the union of some sub-parts (GROUPS), each becoming one group in the .kra – a Shape, a flat colour, shading, named bands and lines |
| route (走法) | one path through the steps: one-shot (segment -> trace) or layered (segment -> lineart -> complete -> lines -> draft -> paint). One picture, one route, one subproject |
| worked example | ch. 19: one real picture’s complete record and numbers down both routes. The main text never quotes it |
| subproject / step | work/<name>/: the picture, the parts table, and one stepNN-<stage>/ per stage; steps pass files to each other through directories and nothing else |
| the hand-written ASSIGN table | a table of region number to sub-part, written from the region-number map; the one-shot route uses only this |
| growing from a seed | after the vote, where one class’s mask encloses a small, clearly differently coloured patch inside a region another class won, it grows outward from that patch by colour, within a distance limit |
| part / method | painting is divided by part – hair, skin, eyes, stockings, clothing – with one page and one module per part (dtp/paint/), and a person deciding each layer’s in the PAINT table (ch. 6). An unstudied part is a placeholder (⬜): the skeleton, how an artist paints it, what has to be decided, and an empty module in the code |
the copy-it baseline, generic | error-driven soft and hard brushes reproducing the source’s light and shade inside a group. It produces a complete picture and is not a way of painting; it is kept only as a ruler, and each part’s method has to beat it |
| band / tier (档) | a layer cut out of a part by luminance or by rule: the one-shot route’s Flat / Shadow1 / Light1 (by luminance, with no names), and the layered route’s Skin_Shadow / Eye_Light (named, a vector Shape plus a flat fill) |
| value band / cel | the bands a part is split into by luminance: Flat / Shadow1 / Shadow2 / Light1, nested inside one another |
| cell | the joint (part, band) label, pid x 100 + tier. The area a stroke may move in |
| alpha / sub-pixel coverage | what fraction of a boundary pixel belongs to a part, solved from the antialiased edge |
| SDF | a signed distance field, positive inside and negative outside, in pixels. The scalar field vectorization rests on |
| isoline | the curve where a scalar field takes a given value. The zero isoline is the boundary |
| RDP | Ramer-Douglas-Peucker polyline simplification, with tolerance eps |
| Catmull-Rom | a spline through every control point, converted to cubic beziers for SVG |
| clip / inherit alpha | Krita’s setInheritAlpha(True): clipping to the accumulated alpha of the layers below it in the same group |
| passthrough | a group’s passthrough mode. On, clipping stops working; off, a multiply inside the group does not multiply against what is below the group |
| 色トレス (colour trace) | coloured lineart: a line’s colour is sampled from the colour beside it and darkened, rather than being black |
| cel shading (赛璐璐) | the animation style of distinct value bands with hard edges |
| soft painterly | this book’s paint style: an airbrush plus a semi-transparent detail brush, with a gouache feel |
| wash / flat fill | scanning an area full at a fixed spacing without regard to error. Used only on a pure gradient |
| taper | a stroke thin at both ends and thick in the middle, from a pressure of 0 to 1 to 0 |
| gradient p99 | the 99th percentile of the luminance gradient’s magnitude: how sharp the edges are. It changes with resolution |
| the 8 px stair fingerprint | the periodic signal a 1x pixel grid leaves when enlarged eight times. High if anything was upscaled |
| K90 | the 90th percentile of the edge’s level-set curvature, a direct measure of per-pixel jaggedness. Analytic antialiasing reads about 0.04 to 0.06 |
| W | the edge’s 10-to-90% transition width in px. Small is sharp, large is soft |
| aliased% | the fraction of edge pixels with W below 1 (a hard step) |
| empty | a measure of empty resolution, in dB. It points the wrong way on an upscaling target and has to be paired with edge_ratio |
| edge_ratio | the fraction of high-frequency energy falling within 3 px of a gradient ridge. It drops to 0.6 when noise is cheating |
| low-frequency likeness | the PSNR after reducing both sides to 256 wide |
| normalization | resizing to the same physical width (2508) before measuring any whole-picture indicator |
| the source anchor | a criterion’s threshold is written as a percentage of the source’s own reading |
| measuring the wrong thing | the class of mistake where a measurement raises nothing and its conclusion points the wrong way. Ch. 16 |
| harness | the Krita runtime with its own HOME (krita-bot/) |
| pump | running a few rounds of Qt’s event loop. Needed before reading pixels; not needed when changing colour or brush size (a tax of 8.5x) |
| the undo stack | Krita stores one per paint* and has its own limit. Memory growth was once wrongly attributed to it; what actually grows is the tiles (below) |
| tile | a Krita layer’s 64x64 pixel block. Wherever a stroke lands, that block goes from empty to dense; the budget is the number of layers times the area painted on each |
| amodal | a part’s whole shape, including what the layers above hide. “The kettle is occluded, and the kettle itself is still a whole layer” |
| the majority vote | segmentation’s regions are assigned by how much each SAM mask covers them, ties going by priority; it corrects the hand-written ASSIGN |
| the candidate pool / support / flips | arbitrating the lines: both contours and model lines are candidates; support is the fraction of samples along a line where the source really has an edge, flips is curvature sign changes per 100 px, and score is support minus 0.05 times flips |
| Schneider fitting | least-squares cubic beziers (Graphics Gems’ FitCurve): approximation rather than interpolation, splitting only when the maximum error exceeds the tolerance |
| crossing number | how many 0-to-1 transitions there are going round a skeleton pixel’s eight neighbours: 1 is an endpoint, 2 the middle, 3 or more a junction. Counting neighbours instead takes a stair on a diagonal for a junction |
| the draft / the finished version | the layered route’s two deliverables: a .kra of each layer’s shape, its flat colour and its lines for a person to review; and once that passes, the shading, the bands, the strands and the background added. Sketch version is the draft’s old name, and it is not a sketch |
| per-layer lineart | once the layers exist, the lineart extracted from each layer alone on a ground and arbitrated against that layer’s own image; the lines step |
| made_up | the fraction of a line’s samples falling in the invented region; a line at 0.5 or above was extracted from the completed image and sits under the layers above in the finished painting |
| lines as walls | segmentation’s second pass (WALLS pointing at the lineart step): the lines arbitrated on the source are rasterized into the boundary barrier and the regions split along them; the labels are inherited from the old table and correcting them is left to the vote |
| gate (闸门) | each step ends by waiting for a person to look at the review images; overrides.json and parts.py are where they overrule it |
| interior sharpness | the gradient p90 more than 30 px from the outline. p99 is propped up by the outlines and cannot see a blurry interior |
| likeness | the PSNR after reducing both sides to 256 wide, resembling only at the low-frequency scale. A study reads at least 30 dB |
| SAM / GroundingDINO | text-prompted segmentation: GroundingDINO finds a box from a word and SAM produces the mask. The more specific the word the better |
| inpaint | erasing an area and having a diffusion model repaint it. Completion grows outward ring by ring with it (ch. 3) |
| the AMODAL rules | each group’s prompt, negative prompt, the SAM words that recover its shape and the words to subtract, in parts.py |
| the restack difference | stacking the completed group layers back in occlusion order and comparing pixel by pixel with the source inside the subject; the visible area is pinned to the source, so anything non-zero is a hole or a misalignment in the masks |
| probe | a small job answering one “does this actually work” question, whose conclusion goes into the book |
| Hertzmann 1998 | Painterly Rendering with Curved Brush Strokes of Multiple Sizes, where the detail brush’s algorithm comes from: multi-scale, growing along the gradient’s normal, and stopping when the canvas is close enough |
the layer tree IR / tree.json | the intermediate form painting takes inside the library: a JSON describing an editable .kra (appendix F). What used to pass was a list of strokes, a model that forced fills, gradients and erasing all to become strokes |
| the description count | recursively counting how many numbers a layer tree holds (ir/count.py). The criterion is that count over the source’s pixel count times three, at most 5%. How many pixels you write is not the sin; being unable to say why is: a gradient covering 8K is nineteen numbers, and pasting the 1x source in is 4.7 million (ch. 7) |
| a bare pixel write | a set_pixels with no why. The threshold is zero – writing pixels has to say why, not be forbidden |
| bake | the step that lays a tree down as a Krita document (ops/bake.py plus jobs/bake.py). The only painting job, shared by all three routes; it knows neither parts nor taste |
| the five ranks | the library is ranked by who decides what: atoms (geometry, raster, ir) -> capability and reading (ops, read) -> the vocabulary of painting (craft) -> parts (paint) -> wiring the stages (stages), plus the cross-cutting rulers (gauge). A rank may import downward only, and tests/test_layering.py enforces it (appendix B) |
the vocabulary of painting, craft | an artist’s actions: filling, banding, copying, hatching, strands, 色トレス. With aesthetic constants and no part names – how hair is painted belongs to the rank above (paint/) |
| colour field | a low-resolution image stretched out to serve as something blurred (the background). The criterion accounts for how many pixels it has itself, not how much it covers once stretched |