generate-coloring-page
activev2026.09.16Generate a printable coloring page: clean black line art on a white background (no fills, no shading), post-processed for paper or tablet, quality-gated against KDP print and WCAG touch standards, plus classifier-produced catalog metadata.
This page renders the template’s published registry entry — the contract itself, not a description of it. Immutable versions; sealed properties exist but are not public.
What you provide — intake contract
How it runs — step topology
1
Render line artimageimageGenerator
promptTemplate
2
Post-process line arttool
3
Audit line arttool
4
Text gatellmtextGategate
Hard gate: the run fails unless pass — OCR text gate rejected the render
systempromptTemplatemaxTokens
5
Classify assetllmclassifier
systempromptTemplatemaxTokens
Model roles: imageGenerator textGate classifier bindings budgetPolicy
What you get — artifact
coloring-pagevisual
Version lineage
2026.09.16rev 88current2026-09-20
sha256:8534d8500…
2026.09.10rev 862026-09-12
sha256:857afae2f…
2026.09.09.1rev 852026-09-12
sha256:9d9b4f4e7…
2026.09.10rev 842026-09-12
sha256:857afae2f…
2026.09.09.1rev 802026-09-09
sha256:9d9b4f4e7…
2026.07.04rev 522026-08-06
sha256:e2361b169…
2026.07.04rev 262026-07-26
sha256:10c84d784…
2026.07.04rev 12026-07-04
sha256:fde512a83…
Full contract (as served)
GET /v1/catalog/workflows/generate-coloring-page
{
"_comment": "SYNCED SNAPSHOT — do not hand-edit. Regenerate with: node scripts/sync-workflow-catalog.mjs (pulls api.esy.com GET /v1/catalog/workflows/{id}).",
"generatedAt": "2026-09-22T16:13:54.045073Z",
"id": "generate-coloring-page",
"name": "Generate Coloring Page",
"description": "Generate a printable coloring page: clean black line art on a white background (no fills, no shading), post-processed for paper or tablet, quality-gated against KDP print and WCAG touch standards, plus classifier-produced catalog metadata.",
"shortDescription": "Printable line-art coloring page, post-processed, gated, classified.",
"artifactClass": "visual",
"outputType": "visual",
"status": "active",
"supersededById": null,
"version": "2026.09.16",
"stages": [
{
"name": "Render",
"description": "Compose the line-art prompt and call the image model.",
"stepCount": 1
},
{
"name": "Post-process",
"description": "Threshold, seal contour gaps, raise strokes to the print floor, despeckle.",
"stepCount": 1
},
{
"name": "Audit",
"description": "Measure stroke weight, grey, margin ink, gaps and tappable regions; fail what would not print or fill.",
"stepCount": 1
},
{
"name": "Text gate",
"description": "OCR the page against its text contract: exact lettering on a facts page, none on an art page.",
"stepCount": 1
},
{
"name": "Classify",
"description": "Produce catalog metadata.",
"stepCount": 1
}
],
"intakeSchema": {
"fields": [
{
"name": "prompt",
"type": "string",
"required": true,
"description": "Subject of the coloring page"
},
{
"name": "style",
"type": "enum",
"required": false,
"description": "Coloring style",
"default": "coloring",
"options": [
"coloring"
]
},
{
"name": "aspectRatio",
"type": "enum",
"required": true,
"description": "Aspect ratio",
"default": "3:4",
"options": [
"1:1",
"3:4",
"4:3",
"3:2",
"2:3",
"16:9",
"9:16"
]
},
{
"name": "quality",
"type": "enum",
"required": false,
"description": "Render quality tier",
"default": "medium",
"options": [
"low",
"medium",
"high",
"xhigh",
"max"
]
},
{
"name": "size",
"type": "string",
"required": false,
"default": "",
"description": "Exact WIDTHxHEIGHT for this render, e.g. '2560x1440'. Empty (the default) means aspectRatio decides. Both edges must be multiples of 16, neither over 3840, the ratio between 1:3 and 3:1, and the total pixels between 655,360 and 8,294,400. Above 2560x1440 the provider calls results experimental — allowed, more variable."
},
{
"name": "detail",
"type": "enum",
"required": false,
"default": "print",
"description": "Which product this page is: 'print' (paper — bold strokes, clear margins) or 'app' (tablet — sealed contours, tappable regions)",
"options": [
"print",
"app"
]
},
{
"name": "renderModel",
"type": "string",
"required": false,
"default": "openai/gpt-image-2.5-flare-2026-09-08",
"description": "Registry id of the image model to render with. Print: openai/gpt-image-2.5-flare-2026-09-08. App: openai/gpt-image-2.5-sunburst-2026-09-08. An unregistered id falls back to the bound provider."
},
{
"name": "postProcess",
"type": "boolean",
"required": false,
"default": true,
"description": "Threshold, seal gaps, raise strokes to the floor, despeckle. Off skips with provenance; the audit still runs on the raw render."
},
{
"name": "lineArtAuditMode",
"type": "enum",
"required": false,
"default": "enforce",
"description": "Quality gate: 'enforce' (default) fails a page that would print or fill badly so the order re-renders it, 'report' records metrics only, 'off' skips the audit",
"options": [
"enforce",
"report",
"off"
]
},
{
"name": "categories",
"type": "string",
"required": true,
"description": "Comma-separated category slugs the classifier must choose from (empty fails the run in preflight)"
},
{
"name": "textPolicy",
"type": "enum",
"required": false,
"default": "",
"options": [
"",
"none",
"exact",
"freeform"
],
"description": "Per-item text contract: none = text forbidden; exact = must match expectedText; freeform = text allowed, judged on legibility/spelling only. Empty derives from textBearing (true=exact, false=freeform). Use 'none' deliberately, for assets that must carry no characters at all."
},
{
"name": "textBearing",
"type": "boolean",
"required": false,
"default": false,
"description": "True when the asset must carry legible text (the OCR gate then checks it)"
},
{
"name": "expectedText",
"type": "string",
"required": false,
"default": "",
"description": "The EXACT text the asset must carry; leave empty unless textPolicy is 'exact'"
}
]
},
"runtimeSteps": [
{
"id": "step-1",
"name": "Render line art",
"kind": "image",
"role": "imageGenerator",
"promptTemplate": "redacted"
},
{
"id": "step-2",
"name": "Post-process line art",
"kind": "tool",
"inputPath": "step-1.url"
},
{
"id": "step-3",
"name": "Audit line art",
"kind": "tool",
"inputPath": "step-2.url"
},
{
"id": "step-3b",
"name": "Text gate",
"kind": "llm",
"capability": "text",
"role": "textGate",
"requireTrue": "pass",
"failMessage": "OCR text gate rejected the render",
"jsonSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"foundText": {
"type": "string",
"description": "All legible text read from the image; empty if none"
},
"pass": {
"type": "boolean"
},
"reason": {
"type": "string"
}
},
"required": [
"foundText",
"pass",
"reason"
]
},
"system": "redacted",
"promptTemplate": "redacted",
"maxTokens": "redacted"
},
{
"id": "step-4",
"name": "Classify asset",
"kind": "llm",
"capability": "text",
"role": "classifier",
"jsonSchema": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "Catalog-ready title, <= 60 chars"
},
"slug": {
"type": "string",
"description": "kebab-case URL slug"
},
"description": {
"type": "string",
"description": "1-2 sentence SEO-friendly description"
},
"category": {
"type": "string",
"description": "Exactly one of the provided category slugs"
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "3-8 search tags"
}
},
"required": [
"title",
"slug",
"description",
"category"
],
"additionalProperties": false
},
"system": "redacted",
"promptTemplate": "redacted",
"maxTokens": "redacted"
}
],
"gates": [
{
"id": "gate-render",
"name": "Provider execution",
"type": "quality",
"inputs": [
"intake"
],
"outputs": [
"line-art"
],
"unlocks": [
"step-2"
]
},
{
"id": "gate-line-art",
"name": "Line-art audit",
"type": "quality",
"inputs": [
"post-processed"
],
"outputs": [
"audited"
],
"unlocks": [
"step-3b"
]
},
{
"id": "gate-text",
"name": "OCR text gate",
"type": "quality",
"inputs": [
"audited"
],
"outputs": [
"lettering-checked"
],
"unlocks": [
"step-4"
]
}
],
"artifactSchema": {
"artifactClass": "visual",
"artifactType": "coloring-page",
"files": [
"image/png"
],
"metadata": {
"aspectRatio": "enum [3:4, 1:1, 4:3]",
"quality": "enum [low, medium, high, xhigh, max]",
"detail": "enum [print, app]",
"lineArtAudit": "object",
"classification": "object"
}
},
"providers": {
"imageGenerator": "redacted",
"textGate": "redacted",
"classifier": "redacted"
},
"budgetPolicy": "redacted",
"versions": [
{
"version": "2026.07.04",
"revision": 1,
"contentHash": "sha256:fde512a832e869e9e8f20b4e0be2d4e839f1d578961e99ce7f64fd9d09b45576",
"createdAt": "2026-07-04T21:49:03.195883Z"
},
{
"version": "2026.07.04",
"revision": 26,
"contentHash": "sha256:10c84d7845b8f8639c3c94fe43273ef08568071e14202c2fafd0919463b6db45",
"createdAt": "2026-07-26T00:51:05.101830Z"
},
{
"version": "2026.07.04",
"revision": 52,
"contentHash": "sha256:e2361b169361fe6e0963846552a4ce645567b0d5340cbeb090da3f92194ffc81",
"createdAt": "2026-08-06T22:08:47.462572Z"
},
{
"version": "2026.09.09.1",
"revision": 80,
"contentHash": "sha256:9d9b4f4e743530ad96d5392cbf5701d240a900bd6c9c7505658076b39dac2004",
"createdAt": "2026-09-09T22:42:07.692657Z"
},
{
"version": "2026.09.10",
"revision": 84,
"contentHash": "sha256:857afae2f856745fb09fb7d695279a6584b30b7fe2ec9d53e4c3f29d30cece57",
"createdAt": "2026-09-12T04:56:49.454434Z"
},
{
"version": "2026.09.09.1",
"revision": 85,
"contentHash": "sha256:9d9b4f4e743530ad96d5392cbf5701d240a900bd6c9c7505658076b39dac2004",
"createdAt": "2026-09-12T23:37:44.483737Z"
},
{
"version": "2026.09.10",
"revision": 86,
"contentHash": "sha256:857afae2f856745fb09fb7d695279a6584b30b7fe2ec9d53e4c3f29d30cece57",
"createdAt": "2026-09-12T23:42:41.582175Z"
},
{
"version": "2026.09.16",
"revision": 88,
"contentHash": "sha256:8534d85006b48d544c4a93066d6f5868695b431a8bbf9dcc7ecb276bf4d09899",
"createdAt": "2026-09-20T02:38:59.510757Z"
}
],
"updatedAt": "2026-09-20T02:38:59.510757Z"
}Snapshot generated 2026-09-22 from the live registry.
