{"$schema":"https://json-schema.org/draft/2020-12/schema","title":"Emaki studio material scene","type":"object","additionalProperties":false,"required":["version","title","seed","width","height","layers","material"],"properties":{"version":{"const":"astra-sketch-1"},"title":{"type":"string","maxLength":200},"seed":{"type":"integer","minimum":0,"maximum":4294967295},"width":{"type":"integer","minimum":256,"maximum":2400},"height":{"type":"integer","minimum":256,"maximum":3000},"layers":{"type":"array","maxItems":32,"items":{"type":"object","additionalProperties":false,"required":["id","intent","marks"],"properties":{"id":{"type":"string","minLength":1,"maxLength":80},"intent":{"type":"string","maxLength":500},"marks":{"type":"array","maxItems":6000,"items":{"oneOf":[{"type":"object","additionalProperties":false,"required":["type","points","opacity","width"],"properties":{"type":{"const":"brush"},"points":{"type":"array","minItems":2,"maxItems":256,"items":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"number","minimum":0,"maximum":1}}},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"opacity":{"type":"number","minimum":0,"maximum":1},"width":{"type":"number","minimum":0.0001,"maximum":0.15},"texture":{"type":"number","minimum":0,"maximum":1},"softness":{"type":"number","minimum":0,"maximum":0.02},"dry":{"type":"number","minimum":0,"maximum":1},"pressure":{"type":"array","minItems":2,"maxItems":256,"items":{"type":"number","minimum":0.05,"maximum":1},"description":"Brush contact fraction per point; length must match points."},"water":{"type":"number","minimum":0,"maximum":1},"duration":{"type":"number","minimum":0.1,"maximum":20},"tilt":{"type":"number","minimum":0,"maximum":1},"angle":{"type":"number","minimum":0,"maximum":360},"load":{"type":"number","minimum":0,"maximum":1},"granulation":{"type":"number","minimum":0,"maximum":1},"lift":{"type":"number","minimum":0,"maximum":1},"gesture":{"type":"object","additionalProperties":false,"required":["version","provenance","samples"],"properties":{"version":{"const":"pose-v1"},"provenance":{"enum":["procedural","measured","estimated"]},"samples":{"type":"array","minItems":2,"maxItems":256,"items":{"type":"object","additionalProperties":false,"required":["t","tiltX","tiltY","rotation"],"properties":{"t":{"type":"number","minimum":0,"maximum":20},"tiltX":{"type":"number","minimum":-1,"maximum":1},"tiltY":{"type":"number","minimum":-1,"maximum":1},"rotation":{"type":"number","minimum":0,"maximum":360}}}}},"description":"Experimental material-only pose. Samples match points, time strictly increases from 0 to explicit duration, tilt vector magnitude <=1. Scalar angle/tilt are disallowed. Procedural approximation, not calibrated six-DOF physics."},"dynamics":{"type":"object","additionalProperties":false,"required":["model","compliance","recovery"],"properties":{"model":{"const":"tuft-v1"},"compliance":{"type":"number","minimum":0,"maximum":1},"recovery":{"type":"number","minimum":0.02,"maximum":0.4}},"description":"Experimental overdamped single-tuft bend and recovery. Requires gesture. Compliance=0 disables deformation. Recovery is seconds. Not calibrated individual bristles."},"supply":{"oneOf":[{"type":"object","additionalProperties":false,"required":["model","id","action","capacity","release","pickup"],"properties":{"model":{"const":"reservoir-v1"},"id":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,40}$"},"action":{"enum":["reload","continue"]},"capacity":{"type":"number","minimum":0.1,"maximum":30},"release":{"type":"number","minimum":0.01,"maximum":12},"pickup":{"type":"number","minimum":0,"maximum":4}},"description":"Experimental finite persistent brush. reload rinses prior charge to waste then loads; continue retains charge. Requires material, gesture, explicit water, no load or lift. Capacity in full-pressure footprint areas, release/pickup are empirical rates. Runtime validates prior load and unchanged width/color/opacity/water/granulation/capacity on continue."},{"type":"object","additionalProperties":false,"required":["model","id","action","capacity","conductance"],"properties":{"model":{"const":"reservoir-v2"},"id":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,40}$"},"action":{"enum":["reload","continue"]},"capacity":{"type":"number","minimum":0.1,"maximum":30},"conductance":{"type":"number","minimum":0.01,"maximum":12}},"description":"Opt-in simultaneous wetness-gradient exchange; single conductance replaces release/pickup. Same loading/continuation rules. Relative water content proxy, not calibrated capillary physics."},{"type":"object","additionalProperties":false,"required":["model","id","action"],"properties":{"model":{"const":"brush-v5"},"id":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,40}$"},"action":{"enum":["reload","continue"]}},"description":"paper-brush-v5 only. Keeps one physical brush between marks: continue paints with what is left, including colour picked up from the paper; reload rinses and recharges."}]},"tip":{"description":"paper-brush-v5 only. A preset name, or {preset, ...parameters} for a customised brush. Presets: round (sable), flat, fan, liner (rigger), hake, mop (squirrel), hog (stiff bristle).","oneOf":[{"enum":["round","flat","fan","liner","hake","mop","hog"]},{"type":"object","additionalProperties":false,"properties":{"preset":{"enum":["round","flat","fan","liner","hake","mop","hog"]},"shape":{"enum":["round","flat","fan"]},"bristles":{"type":"integer","minimum":4,"maximum":160},"length":{"type":"number","minimum":0.3,"maximum":8},"point":{"type":"number","minimum":0,"maximum":1},"stiffness":{"type":"number","minimum":0,"maximum":1},"capacity":{"type":"number","minimum":0.1,"maximum":4},"spread":{"type":"number","minimum":0,"maximum":1.5},"thickness":{"type":"number","minimum":0.02,"maximum":1}}}]},"pigment":{"description":"paper-brush-v5 only. A named paint, or a palette mix of 1-4 {name, part}. Sets optics (Kubelka-Munk), granulation and staining; color stays the display colour. Do not combine with granulation or staining.","oneOf":[{"enum":["french-ultramarine","phthalo-blue","cerulean","viridian","sap-green","hansa-yellow","yellow-ochre","cadmium-red","quinacridone-rose","burnt-sienna","raw-umber","lamp-black","chinese-white"]},{"type":"array","minItems":1,"maxItems":4,"items":{"type":"object","additionalProperties":false,"required":["name","part"],"properties":{"name":{"enum":["french-ultramarine","phthalo-blue","cerulean","viridian","sap-green","hansa-yellow","yellow-ochre","cadmium-red","quinacridone-rose","burnt-sienna","raw-umber","lamp-black","chinese-white"]},"part":{"type":"number","minimum":0.01,"maximum":1}}}}]},"staining":{"type":"number","minimum":0,"maximum":1,"description":"paper-brush-v5 only, plain colours only. Share of the fine particles that bond to the fibres (0 lifts easily, 1 stains). Default 0.45, a medium-staining paint."}},"anyOf":[{"required":["color"]},{"required":["pigment"]}]},{"type":"object","additionalProperties":false,"required":["type","seconds"],"properties":{"type":{"const":"wait"},"seconds":{"type":"number","minimum":0.1,"maximum":180}}},{"type":"object","additionalProperties":false,"required":["type","points","spread","drops","size","opacity"],"description":"paper-brush-v5 only: drops flicked from a loaded brush around each point.","properties":{"type":{"const":"spatter"},"points":{"type":"array","minItems":1,"maxItems":64,"items":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"number","minimum":0,"maximum":1}}},"spread":{"type":"number","minimum":0.001,"maximum":0.3,"description":"Scatter radius, fraction of sheet width"},"drops":{"type":"integer","minimum":1,"maximum":400,"description":"Drops per point; points × drops ≤ 4000"},"size":{"type":"number","minimum":0.2,"maximum":4,"description":"Median drop diameter, mm"},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"pigment":{"description":"paper-brush-v5 only. A named paint, or a palette mix of 1-4 {name, part}. Sets optics (Kubelka-Munk), granulation and staining; color stays the display colour. Do not combine with granulation or staining.","oneOf":[{"enum":["french-ultramarine","phthalo-blue","cerulean","viridian","sap-green","hansa-yellow","yellow-ochre","cadmium-red","quinacridone-rose","burnt-sienna","raw-umber","lamp-black","chinese-white"]},{"type":"array","minItems":1,"maxItems":4,"items":{"type":"object","additionalProperties":false,"required":["name","part"],"properties":{"name":{"enum":["french-ultramarine","phthalo-blue","cerulean","viridian","sap-green","hansa-yellow","yellow-ochre","cadmium-red","quinacridone-rose","burnt-sienna","raw-umber","lamp-black","chinese-white"]},"part":{"type":"number","minimum":0.01,"maximum":1}}}}]},"opacity":{"type":"number","minimum":0,"maximum":1},"granulation":{"type":"number","minimum":0,"maximum":1},"staining":{"type":"number","minimum":0,"maximum":1,"description":"paper-brush-v5 only, plain colours only. Share of the fine particles that bond to the fibres (0 lifts easily, 1 stains). Default 0.45, a medium-staining paint."}}},{"type":"object","additionalProperties":false,"required":["type","points","spread","grains","size"],"description":"paper-brush-v5 only: salt crystals on a wet or damp wash. Each draws water and loose paint from a zone about 2.5 crystal widths across.","properties":{"type":{"const":"salt"},"points":{"type":"array","minItems":1,"maxItems":64,"items":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"number","minimum":0,"maximum":1}}},"spread":{"type":"number","minimum":0,"maximum":0.3},"grains":{"type":"integer","minimum":1,"maximum":200,"description":"Crystals per point; points × grains ≤ 4000"},"size":{"type":"number","minimum":0.2,"maximum":3,"description":"Crystal size, mm"}}},{"type":"object","additionalProperties":false,"required":["type","points","width"],"description":"paper-brush-v5 only: masking fluid along a path. It sets over 600 drying-clock seconds (100 s with fast drying); until then a wet brush smears it.","properties":{"type":{"const":"mask"},"points":{"type":"array","minItems":2,"maxItems":256,"items":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"number","minimum":0,"maximum":1}}},"width":{"type":"number","minimum":0.001,"maximum":0.1},"pressure":{"type":"array","items":{"type":"number","minimum":0.05,"maximum":1},"description":"One value per point"},"duration":{"type":"number","minimum":0.1,"maximum":20}}},{"type":"object","additionalProperties":false,"required":["type"],"description":"paper-brush-v5 only: peels all masking fluid off the sheet.","properties":{"type":{"const":"unmask"}}}]}},"environment":{"type":"object","additionalProperties":false,"properties":{"drying":{"enum":["normal","hold","fast"]},"tilt":{"type":"number","minimum":0,"maximum":60,"description":"paper-brush-v5 only: board tilt in degrees, top edge raised. Wet paint runs down the sheet; about 6 degrees starts runs, 15 or more stops backruns."}},"description":"Drying clock and board for the layer. hold pauses fixation, absorption and evaporation; transport continues. fast (paper-brush-v5 only) is a hair dryer: evaporation six times faster. tilt (paper-brush-v5 only) raises the top of the board. Requires material.","minProperties":1}}}},"material":{"type":"object","additionalProperties":false,"required":["model","resolution","roughness","absorbency"],"properties":{"model":{"enum":["paper-brush-v1","paper-brush-v2","paper-brush-v3","paper-brush-v4","paper-brush-v5"]},"resolution":{"enum":[384,640,768,960]},"roughness":{"type":"number","minimum":0,"maximum":1},"absorbency":{"type":"number","minimum":0,"maximum":1}}},"canvas":{"type":"object","additionalProperties":false,"required":["profile","aspectRatio"],"properties":{"profile":{"enum":["watercolor-standard-v2","watercolor-standard-v1","watercolor-study-v2"]},"aspectRatio":{"type":"string","enum":["1:1","4:5","3:4","2:3","9:16","5:4","4:3","3:2","16:9"]}}}},"description":"Studio brush/wait scenes; paper-brush-v5 also accepts spatter, salt, mask and unmask. New work uses watercolor-standard-v2 (paper-brush-v5, physical paper and brush): choose aspectRatio with emakiStudio.newDocument; retain the returned canvas/width/height/seed/material header. watercolor-standard-v1 (paper-brush-v3) and untagged historical imports preserve their settings. tip and pigment are v5 only; v5 rejects dry, load, lift, texture, softness and dynamics. Runtime also checks total work/time and cross-field constraints.","$comment":"validateScene also enforces material-only brush fields, lift opacity=0, total grid <=1.5M, wet brush/wait only, global time/point budgets. Gesture also requires explicit duration, per-point samples, bounded contact work, increasing times and no scalar angle/tilt; validateScene enforces these.","allOf":[{"if":{"required":["canvas"],"properties":{"canvas":{"properties":{"profile":{"const":"watercolor-standard-v2"}}}}},"then":{"required":["material","seed","width","height"],"properties":{"width":{"const":720},"seed":{"const":42},"material":{"const":{"model":"paper-brush-v5","resolution":640,"roughness":0.26,"absorbency":0.42}}},"allOf":[{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"1:1"}}}}},"then":{"properties":{"height":{"const":720}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"4:5"}}}}},"then":{"properties":{"height":{"const":900}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"3:4"}}}}},"then":{"properties":{"height":{"const":960}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"2:3"}}}}},"then":{"properties":{"height":{"const":1080}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"9:16"}}}}},"then":{"properties":{"height":{"const":1280}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"5:4"}}}}},"then":{"properties":{"height":{"const":576}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"4:3"}}}}},"then":{"properties":{"height":{"const":540}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"3:2"}}}}},"then":{"properties":{"height":{"const":480}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"16:9"}}}}},"then":{"properties":{"height":{"const":405}}}}]}},{"if":{"required":["canvas"],"properties":{"canvas":{"properties":{"profile":{"const":"watercolor-standard-v1"}}}}},"then":{"required":["material","seed","width","height"],"properties":{"width":{"const":720},"seed":{"const":42},"material":{"const":{"model":"paper-brush-v3","resolution":640,"roughness":0.26,"absorbency":0.42}}},"allOf":[{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"1:1"}}}}},"then":{"properties":{"height":{"const":720}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"4:5"}}}}},"then":{"properties":{"height":{"const":900}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"3:4"}}}}},"then":{"properties":{"height":{"const":960}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"2:3"}}}}},"then":{"properties":{"height":{"const":1080}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"9:16"}}}}},"then":{"properties":{"height":{"const":1280}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"5:4"}}}}},"then":{"properties":{"height":{"const":576}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"4:3"}}}}},"then":{"properties":{"height":{"const":540}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"3:2"}}}}},"then":{"properties":{"height":{"const":480}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"16:9"}}}}},"then":{"properties":{"height":{"const":405}}}}]}},{"if":{"required":["canvas"],"properties":{"canvas":{"properties":{"profile":{"const":"watercolor-study-v2"}}}}},"then":{"required":["material","seed","width","height"],"properties":{"width":{"const":720},"seed":{"const":42},"material":{"const":{"model":"paper-brush-v4","resolution":640,"roughness":0.26,"absorbency":0.42}}},"allOf":[{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"1:1"}}}}},"then":{"properties":{"height":{"const":720}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"4:5"}}}}},"then":{"properties":{"height":{"const":900}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"3:4"}}}}},"then":{"properties":{"height":{"const":960}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"2:3"}}}}},"then":{"properties":{"height":{"const":1080}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"9:16"}}}}},"then":{"properties":{"height":{"const":1280}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"5:4"}}}}},"then":{"properties":{"height":{"const":576}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"4:3"}}}}},"then":{"properties":{"height":{"const":540}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"3:2"}}}}},"then":{"properties":{"height":{"const":480}}}},{"if":{"properties":{"canvas":{"properties":{"aspectRatio":{"const":"16:9"}}}}},"then":{"properties":{"height":{"const":405}}}}]}}]}
