{
  "schemaVersion": 1,
  "id": "chocolate-pour",
  "version": "1.0.0",
  "status": "published",
  "kind": "object",
  "title": "Chocolate Pour",
  "summary": "A thick rope of glossy chocolate coils onto a white plate, folding into a spiralling heap. Loops perfectly.",
  "description": "Thick, glossy chocolate falling from a spout in one heavy rope onto a white plate, where it coils over and over as viscous liquids do, laying down a heap with a rotating spiral of folds and a scalloped skirt at its foot, shining in the studio light. Choose the chocolate (dark, milk, white or ruby), how many coils the rope makes in a loop, how tall the heap grows, how deep the folds are, the backdrop and whether the camera drifts.",
  "role": "Object (3D, three.js): a rich, mouth-watering hero object for food, dessert, confectionery and indulgence content.",
  "collections": [
    "satisfying",
    "hypnotic-loops",
    "product-reveals"
  ],
  "tags": [
    "chocolate",
    "pour",
    "coiling",
    "liquid",
    "viscous",
    "dessert",
    "food",
    "glossy",
    "satisfying",
    "loop",
    "3d"
  ],
  "synonyms": [
    "chocolate sauce",
    "melted chocolate",
    "liquid rope coiling",
    "chocolate fountain",
    "syrup pour",
    "viscous coil"
  ],
  "useCases": [
    "A food, dessert or bakery brand title scene",
    "A \"satisfying\" food loop",
    "A confectionery product background"
  ],
  "featured": null,
  "publishedAt": "2026-10-06",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/chocolate-pour.js",
    "exports": [
      {
        "name": "createChocolatePour",
        "signature": "createChocolatePour({ kind?, coils?, heap?, ridges? }) => { group, setProgress(progress), dispose() }",
        "description": "The plate, heap, rope and spout as a group (plate 5 across on y = 0); add it with an environment map and a shadow-casting light."
      },
      {
        "name": "KINDS",
        "signature": "KINDS: { dark, milk, white, ruby }",
        "description": "Chocolate colours and roughness."
      }
    ],
    "reusable": [
      "src/chocolate-pour.js"
    ],
    "demo": "demo.js",
    "harness": "index.html"
  },
  "dependencies": [
    {
      "id": "three",
      "version": "0.185.1",
      "reason": "Renderer, geometry and shader materials."
    },
    {
      "id": "chrome-material",
      "version": "1.1.0",
      "scope": "demo",
      "reason": "Studio environment light, backdrop and contact shadow."
    },
    {
      "id": "apw-runtime",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo harness."
    }
  ],
  "params": [
    {
      "key": "kind",
      "label": "Chocolate",
      "type": "select",
      "default": "dark",
      "options": [
        {
          "value": "dark",
          "label": "Dark"
        },
        {
          "value": "milk",
          "label": "Milk"
        },
        {
          "value": "white",
          "label": "White"
        },
        {
          "value": "ruby",
          "label": "Ruby"
        }
      ]
    },
    {
      "key": "coils",
      "label": "Coils per loop",
      "type": "integer",
      "min": 2,
      "max": 12,
      "step": 1,
      "default": 6
    },
    {
      "key": "heap",
      "label": "Heap height",
      "type": "number",
      "min": 0.6,
      "max": 1.5,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "ridges",
      "label": "Folds",
      "type": "number",
      "min": 0,
      "max": 2,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "background",
      "label": "Backdrop",
      "type": "color",
      "default": "#d8c8a8"
    },
    {
      "key": "orbit",
      "label": "Camera drift",
      "type": "boolean",
      "default": true
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Dark chocolate",
      "params": {}
    },
    {
      "id": "milk",
      "label": "Milk, slow coils",
      "params": {
        "kind": "milk",
        "coils": 3,
        "background": "#c8b898"
      }
    },
    {
      "id": "white",
      "label": "White, tall heap",
      "params": {
        "kind": "white",
        "heap": 1.4,
        "background": "#2a2220"
      }
    },
    {
      "id": "ruby",
      "label": "Ruby, deep folds",
      "params": {
        "kind": "ruby",
        "ridges": 1.8,
        "coils": 9,
        "background": "#e8d0c8"
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 12,
    "posterSeconds": 3,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": true,
      "cycleSeconds": 12,
      "method": "The rope's coil and the spiral folds of the heap turn a whole number of times per loop and the heap's skirt breathes in whole cycles, so the last frame meets the first."
    },
    "seed": null
  },
  "composition": {
    "inputs": "Time within the loop; the chocolate, coils, heap, folds, backdrop and camera drift.",
    "outputs": "A full frame rendered in 3D with soft shadows and a studio environment.",
    "coordinates": "The plate is centred on the origin on y = 0 (radius 2.65); the spout is at y = 6.55; the heap peaks at about 0.75.",
    "lighting": "A warm key light with a shadow map and the studio environment on the clear-coated chocolate.",
    "timing": "setProgress(progress) rewrites the heap's heights and the rope's curve; frames render in any order.",
    "compatibleWith": [
      "chrome-material",
      "orbit-camera",
      "kinetic-title",
      "number-reveal"
    ],
    "notes": [
      "The heap is a polar grid of 70 × 160 vertices whose height is (1 − u²)^1.4 plus a spiral fold sin(5θ − 21.6u − phase) rotating with the loop and a scalloped edge; the rope is a tube along a curve that falls straight and bends into a circle at the apex."
    ]
  },
  "reuse": [
    "Dessert brand title: Dark chocolate.",
    "Soft bakery scene: Milk, slow coils.",
    "Luxury confectionery loop: Ruby, deep folds."
  ],
  "integration": {
    "newProject": "Create a WebGLRenderer with shadows and a studio environment (see chrome-material), add createChocolatePour().group and call choc.setProgress(progress) each frame.",
    "existingProject": "Copy src/chocolate-pour.js; add choc.group to your scene with an environment map and a shadow-casting light."
  },
  "performance": {
    "notes": "A heap grid of about 11 000 vertices rewritten each frame and a 90-segment tube rebuilt each frame, one shadow map. A few milliseconds a frame on an integrated Intel GPU.",
    "limits": "Software WebGL renders in a second or two a frame."
  },
  "limitations": [
    "The coiling is a formula, not a fluid simulation: the heap never grows or flows over the plate's rim.",
    "The rope does not thin as it falls and the folds are a regular spiral."
  ],
  "license": {
    "spdx": "MIT",
    "notice": "Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.",
    "thirdParty": []
  },
  "provenance": "Adapted from the owner's threejs-sketches/liquid-fluid/chocolate-pour (MIT) and rebuilt for AI Pixel Wizard in October 2026 as an original object: a coiling rope, a heap with rotating spiral folds, a clear-coated chocolate material and an exact loop.",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-05",
      "notes": "Initial release."
    }
  ]
}
