{
  "schemaVersion": 1,
  "slug": "paint-color-mixer-calculator",
  "category": "diy-craft",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "cf4ce6e3848c7753c564b28ef6945286c343fb1f1d8d09f1853c91442671b331",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/paint-color-mixer-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "a_i = p_i × B ÷ (p1 + p2 + p3); q_i = p_i ÷ (p1 + p2 + p3) × 100",
    "vars": [
      [
        "p_i",
        "Parts of colour i (i = 1, 2, 3)"
      ],
      [
        "B",
        "Total batch size (ml)"
      ],
      [
        "a_i",
        "Amount of colour i (ml)"
      ],
      [
        "q_i",
        "Share of colour i (%)"
      ]
    ],
    "note": "Negative parts are clamped to 0; recipe amounts are rounded to 0.1 ml, percentages keep full precision."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const p1=Math.max(0,parts1),p2=Math.max(0,parts2),p3=Math.max(0,parts3),total=p1+p2+p3;if(total<=0)return{totalParts:0,amount1:null,amount2:null,amount3:null,percentage1:null,percentage2:null,percentage3:null,recipe:'—',__error:'inputError'};const per=batchSize/total,a1=p1*per,a2=p2*per,a3=p3*per;return{totalParts:total,amount1:a1,amount2:a2,amount3:a3,percentage1:p1/total*100,percentage2:p2/total*100,percentage3:p3/total*100,recipe:String(baseColor1)+': '+Math.round(a1*10)/10+' ml | '+String(baseColor2)+': '+Math.round(a2*10)/10+' ml | '+String(baseColor3)+': '+Math.round(a3*10)/10+' ml'}",
    "inputs": [
      {
        "name": "baseColor1",
        "type": "text",
        "default": "Titanium White",
        "step": 1
      },
      {
        "name": "parts1",
        "type": "number",
        "default": 6,
        "min": 0,
        "max": 1000,
        "step": 0.5,
        "slider": true
      },
      {
        "name": "baseColor2",
        "type": "text",
        "default": "Ultramarine Blue",
        "step": 1
      },
      {
        "name": "parts2",
        "type": "number",
        "default": 2,
        "min": 0,
        "max": 1000,
        "step": 0.5,
        "slider": true
      },
      {
        "name": "baseColor3",
        "type": "text",
        "default": "Burnt Sienna",
        "step": 1
      },
      {
        "name": "parts3",
        "type": "number",
        "default": 1,
        "min": 0,
        "max": 1000,
        "step": 0.5,
        "slider": true
      },
      {
        "name": "batchSize",
        "type": "number",
        "default": 500,
        "min": 1,
        "max": 100000,
        "step": 1
      }
    ],
    "outputs": [
      {
        "name": "totalParts",
        "precision": 1,
        "unit": ""
      },
      {
        "name": "amount1",
        "precision": 1,
        "unit": "ml"
      },
      {
        "name": "amount2",
        "precision": 1,
        "unit": "ml"
      },
      {
        "name": "amount3",
        "precision": 1,
        "unit": "ml"
      },
      {
        "name": "percentage1",
        "precision": 2,
        "unit": "%"
      },
      {
        "name": "percentage2",
        "precision": 2,
        "unit": "%"
      },
      {
        "name": "percentage3",
        "precision": 2,
        "unit": "%"
      },
      {
        "name": "recipe",
        "precision": 0,
        "unit": "",
        "type": "text"
      }
    ],
    "interpret": null
  }
}
