Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Concepts: subproject, parts table, step, gate, delivery

✅ verified · the conventions live in AGENTS.md one directory up · the code behind every stage: appendix B

Three things, three places

Krita/
  dtp/                     the library (a uv project, its own git): atomic pure functions plus readers
                           and writers, `import dtp`; one main.py template per stage
  work/<name>/             subprojects (not in git): one picture, one route, one subproject; one stage
                           per step; one main.py per step
  diffusion-to-painting/   this handbook (mdBook, its own git)

The library knows no particular picture: no part names, no coordinates, no prompts. Everything a picture has to tell the tool lives in that subproject’s parts.py. The library also knows nothing about step directories, orchestrates no stages and has no command line: its functions take arrays, dicts, a parts table and the path of a single file, and return values. What wires them into a stage is the main.py inside each step.

A subproject, work/<name>/

work/pic/
  input/origin.png        the picture
  parts.py                this picture's parts table (copied from the template in the library)
  README.md               written by a person: what is wanted, and the verdict at each gate
  overrides.json          overruling the lines (optional, ch. 2 and 4)
  phase1-layers/          one phase per milestone: every layer's whole shape and its lines
    README.md             what this phase produces, plus the verdict (written by a person)
    step01-segment/       one step per stage, numbered globally; inside it a main.py (copied from
                          the template) plus the artifacts and README it writes
    step02-lineart/  step03-segment/  step04-complete/  step05-lines/
  phase2-draft/           the draft (a gate)
    step06-draft/
  phase3-paint/           the finished painting; the one-shot route's trace lives here too
    step07-paint/  step08-gauge/

One picture, one route, one subproject: taking a picture down the one-shot route creates pic-basic/, down the layered route pic-pro/, and a second attempt is pic-basic-2/. Two subprojects share only the picture and parts.py (copied), and each keeps its own account in its steps.

Phases and steps

Phases are the milestones a person wants to look at, and there are three: phase1-layers/ for every layer’s whole shape and lines (segment, lineart, segment again with the lines as walls, complete, per-layer lineart; the one-shot route has only segment), phase2-draft/ for the draft, which is the gate, and phase3-paint/ for the finished painting (paint and gauge; the one-shot route’s trace lives here too). A phase holds several stages, and a redone step stays in its own phase. A phase’s README.md records what it produces when it is first opened; the verdict is written by a person.

One stage is one step, one step has one main.py, the living chain is consecutively numbered, and a failure consumes no number. Opening a step means making its directory, copying that stage’s main.py template into it, editing the two blocks of constants at the top, and running it (appendix A). When a step is judged a failure it is mvd to stepNN-<stage>-legacy-wrong-1 and kept in its phase as a record (an experiment becomes -legacy-experiment-1), and the rerun uses the same number; grep renames it in the READMEs and main.py files that refer to it. A second pass that is not a failure (segmenting again once the lineart exists) keeps both numbers. Inside each step directory:

filewritten bycontents
main.pya person (copied from the template and edited)Two blocks of constants at the top: # ---- upstream (which steps it reads, as paths relative to the subproject root) and # ---- knobs; below them the body wires the library’s pure functions together and writes the artifacts and the README. It is the complete record of this step: what it read, what the parameters were, how it was computed
README.mdmain.py writes the numbers, a person adds ## VerdictIt opens with the table of numbers this step wrote (creation time, inputs, knobs, the table); it ends with ## Verdict, a person’s “pass or fail, and why” after looking, which a rerun preserves
the job descriptionmain.py (the three steps that paint)the Krita job’s arguments, which is also what a person replays the job from on a real desktop (appendix A)
artifactsmain.pythe plans (in 1x coordinates), the layer tree, what painting produced, the review images, and what ComfyUI produced – which is not asked for again once it is there. The names are fixed; they are all in appendix F

Steps pass files to each other through step directories and nothing else. The upstream is named at the top of main.py as the path of the step to read, and changing that one line is what changes the upstream. The knobs are constants at the top too, not environment variables – the only things the library takes from the environment are machine-level settings, where this machine keeps ComfyUI and the layering model; the multiplier and the seed are constants in each main.py.

The parts table, parts.py

An ordinary Python module of uppercase constants, in three tiers:

tierwhat a person writes thereused by
sub-partswhich raw regions make up each named sub-part, bottom to top by occlusionsegment; the one-shot route divides its parts by this tier alone
classesthe words to ask the segmentation model for, and which sub-parts each word’s class coversthe majority vote in segment
groupswhich sub-parts make up each layer, which layers share one flat colour, which layer is cut out of a mask, which lineart layer a layer’s lines go to, which layers grow strands or get hatching, which of the model’s layers a group may be completed from, which method paints it, and where the 1:1 close-ups are centredevery step of the layered route

Each tier is explained in the chapter of the stage that governs it; appendix G is the field-by-field reference – the exact names, the format of each one, and which step to rerun after changing it. A missing field is an error rather than a guess.

The intermediate form is a tree

The final form “painting” takes is a layer tree, written out as one file: a description of an editable .kra, where every layer has a kind (fill, gradient, strokes, mask, filter, group), a blending mode, an opacity and a shape. The painting job – there is exactly one, shared by all three routes – reads it, builds the tree and paints, and decides nothing else.

What used to pass between the two was a list of strokes. That model forced everything to become strokes: filling an area took hundreds of scanning strokes, a shadow could not be written as “a multiply layer at 65%” but only as the composited RGB filled flat, and “draw the whole highlight band and then cut it” could not be expressed at all. With a tree, it can be read, diffed and edited without opening Krita, and a 1x preview of it draws in twenty seconds; and when the artist opens it, the shadow really is a layer they can adjust.

The criterion changed with it: what is counted is how many numbers this tree takes to say what the picture is (ch. 7).

Gates

What numbers cannot measure is put in front of a person: whether a layer is whole, why a line is there, whether what was invented looks right. The gates are at these steps:

stepwhat to look atwhat to change
segmentthe three-column review image – the hand-written table, the majority vote, and what the vote changed – and the map of numbered regionswhich regions make up which sub-part, and the words; run it once more with the lineart as walls
lineartthe review image on top of the source: blue for a kept AI line, brown for a kept contour, red dashes for droppedoverrides.json
completethe completion review image – per group: the hidden area, its completed layer, the layer alone, the outline – and the restack differencewhich of the model’s layers that group is completed from
linesone review image per layer, in the same three colours; and the combined one, where kept lines are coloured by layer and the pale ones are inventedoverrides.json (its boxes are 1x full-image coordinates)
draftthe review images painting writes: one per layer, one per group, the 1x composite and the 1:1 close-ups; hide the upper layers to see the lines underneathany of the four above
paint / tracethe same, plus the layer tree’s description countwhich method paints that group

The file names are fixed and are listed in appendix F; the field to change in each case is in appendix G.

The images are to be looked at, not merely produced: every time the baseline changes, look at the 1:1 close-ups of at least the face, the neck, a hand and a foot, whose centres the parts table fixes. The verdict goes at the end of the step’s README.md and into the gate record in the subproject’s README.md.

What is delivered

Each painting step leaves five things behind: the .kra (the whole layer tree, with clip / blend / opacity / label / vector layers surviving the round trip), the composite, the painting journal (one line per stroke and per pixel write – the only evidence that this picture was painted, and the input for replaying it), a manifest of every node in the tree (path, type, blend, clip, bounds), and the review images, plus one image per stage. The names are in appendix F; what the tree looks like is in ch. 5.

The two routes

one-shot (ch. 9)layered (ch. 10)
stepsegment -> tracesegment -> lineart -> segment -> complete -> lines -> draft -> a person looks -> paint
the question it answerscan a diffusion image become a 4K painting where every pixel has a provenancecan an artist take it over
Layerseach part cut into bands by luminance, one vector shape plus two paint layers per band; several hundred nodes, and no layer called “eye”each group = shape / flat colour / shading / named bands / lines; dozens of nodes
linesnoneeach layer’s own lines, one stroke at a time, each with a source and open to being overruled; a line in a hidden area is invented, and accounted for
what is hiddenemptya layering model invents the whole shape, only the hidden part is taken, and exactly which pixels those are is written down
Gatesnonedraft
needs ComfyUISAM onlyall four of segment, lineart, complete and per-layer lineart need it
how closely it resembles the sourcecloser, and sharper insideslightly softer; the difference is what layering costs

How to choose: for a picture that resembles the source with no interest in the layers, take the one-shot route; for a file an artist can edit, take the layered one. The comparison only exists once both have been run – point the criteria step at the other subproject’s finished picture and it produces the crops from both at matching positions.

Experiments

Trying an idea without changing the library: open a step and write its main.py however you like (it need not come from a template), calling the library’s pure functions. The conventions for an experiment: copy the plans from a baseline step, change the plan for one group only, turn the Krita job off and look at the 1x simulation first (which takes seconds), and after painting point the criteria step at the baseline so the two are compared on the same rulers. When it works, it sinks into the library as a pure function with tests, and the main.py stays in the step as the record.