{
  "schemaVersion": 1,
  "slug": "macrame-cord-calculator",
  "category": "diy-craft",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "c274dec097d66c79edb04b8347d950abfe8690e9c8849772c8be773805fe498a",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/macrame-cord-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": "perStrand = L × f × (1 + g ÷ 100); totalLength = perStrand × n",
    "vars": [
      [
        "L",
        "finished length (in)"
      ],
      [
        "f",
        "cord factor by project type"
      ],
      [
        "g",
        "extra for fringe (%)"
      ],
      [
        "n",
        "number of strands"
      ],
      [
        "m",
        "total cord length (m)"
      ],
      [
        "spools",
        "100 m spools needed"
      ]
    ],
    "note": "Factors are rough planning heuristics (keychain 3, dreamcatcher 4.5, wall hanging 4, plant hanger 5, bag 6). Spool count assumes 100 m; actual use depends on cord and knot pattern."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const factor = projectType === 'plantHanger' ? 5 : projectType === 'bag' ? 6 : projectType === 'dreamcatcher' ? 4.5 : projectType === 'keychain' ? 3 : 4; const perStrand = finishedLength*factor*(1 + fringeExtra/100); const totalIn = perStrand*strandCount; const meters = totalIn*0.0254; return { lengthPerStrand: perStrand, totalCordInches: totalIn, totalCordMeters: meters, spoolsNeeded: Math.ceil(meters/100), totalCost: meters*pricePerMeter };",
    "inputs": [
      {
        "name": "projectType",
        "type": "select",
        "default": "wallhanging",
        "options": [
          {
            "value": "wallhanging"
          },
          {
            "value": "plantHanger"
          },
          {
            "value": "keychain"
          },
          {
            "value": "bag"
          },
          {
            "value": "dreamcatcher"
          }
        ]
      },
      {
        "name": "finishedLength",
        "type": "number",
        "default": 30,
        "min": 1,
        "max": 200,
        "step": 0.5,
        "slider": true
      },
      {
        "name": "strandCount",
        "type": "number",
        "default": 16,
        "min": 1,
        "max": 200,
        "step": 1,
        "slider": true
      },
      {
        "name": "fringeExtra",
        "type": "number",
        "default": 25,
        "min": 0,
        "max": 200,
        "step": 5,
        "slider": true
      },
      {
        "name": "pricePerMeter",
        "type": "number",
        "default": 0.8,
        "min": 0,
        "max": 100,
        "step": 0.01
      }
    ],
    "outputs": [
      {
        "name": "lengthPerStrand",
        "precision": 1,
        "unit": "in"
      },
      {
        "name": "totalCordInches",
        "precision": 0,
        "unit": "in"
      },
      {
        "name": "totalCordMeters",
        "precision": 2,
        "unit": "m"
      },
      {
        "name": "spoolsNeeded",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "totalCost",
        "precision": 2,
        "unit": "$"
      }
    ],
    "interpret": null
  }
}
