{
  "schemaVersion": 1,
  "id": "chain-links",
  "version": "1.0.0",
  "status": "published",
  "kind": "object",
  "title": "Chain Links",
  "summary": "A heavy polished chain hangs between two posts and sways in a slow wave. Loops perfectly.",
  "description": "A chain of polished links hanging between two posts in a catenary curve, swaying gently: a slow wave runs along it from post to post, each link turning a little as it goes, every second link at right angles to its neighbours as in a real chain, the whole thing breathing in and out of its sag. Choose the number of links, the metal (steel, brass, copper or black), how deep the chain hangs, how much it sways, the backdrop and whether the camera drifts.",
  "role": "Object (3D, three.js): a strong, tactile hero object for security, connection, industry and strength content.",
  "collections": [
    "satisfying",
    "chrome-glass",
    "hypnotic-loops"
  ],
  "tags": [
    "chain",
    "links",
    "catenary",
    "steel",
    "metal",
    "swaying",
    "industrial",
    "connection",
    "strength",
    "loop",
    "3d"
  ],
  "synonyms": [
    "hanging chain",
    "steel chain",
    "metal chain",
    "chain loop",
    "catenary chain",
    "swinging chain"
  ],
  "useCases": [
    "A security, engineering or industrial title scene",
    "A \"connected\" or \"unbreakable\" brand metaphor",
    "A tactile metal loop for a product page"
  ],
  "featured": null,
  "publishedAt": "2026-10-06",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/chain-links.js",
    "exports": [
      {
        "name": "createChain",
        "signature": "createChain({ links?, metal?, sag?, sway? }) => { group, setProgress(progress), dispose() }",
        "description": "The chain (one instanced mesh of links) and its two posts as a group; the posts are 10 apart, the chain hangs from y = 5; add it with an environment map and a shadow-casting light."
      },
      {
        "name": "METALS",
        "signature": "METALS: { steel, brass, copper, black }",
        "description": "Metal finishes."
      }
    ],
    "reusable": [
      "src/chain-links.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": "links",
      "label": "Links",
      "type": "integer",
      "min": 12,
      "max": 40,
      "step": 1,
      "default": 24
    },
    {
      "key": "metal",
      "label": "Metal",
      "type": "select",
      "default": "steel",
      "options": [
        {
          "value": "steel",
          "label": "Steel"
        },
        {
          "value": "brass",
          "label": "Brass"
        },
        {
          "value": "copper",
          "label": "Copper"
        },
        {
          "value": "black",
          "label": "Black iron"
        }
      ]
    },
    {
      "key": "sag",
      "label": "Sag",
      "type": "number",
      "min": 0.5,
      "max": 1.6,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "sway",
      "label": "Sway",
      "type": "number",
      "min": 0,
      "max": 2,
      "step": 0.05,
      "default": 1
    },
    {
      "key": "background",
      "label": "Backdrop",
      "type": "color",
      "default": "#1c2430"
    },
    {
      "key": "orbit",
      "label": "Camera drift",
      "type": "boolean",
      "default": true
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Steel, twenty-four links",
      "params": {}
    },
    {
      "id": "brass",
      "label": "Brass, deep sag",
      "params": {
        "metal": "brass",
        "sag": 1.4,
        "links": 30,
        "background": "#241c14"
      }
    },
    {
      "id": "black",
      "label": "Black iron, gentle",
      "params": {
        "metal": "black",
        "sway": 0.4,
        "background": "#2a2e36"
      }
    },
    {
      "id": "copper",
      "label": "Copper, heavy swing",
      "params": {
        "metal": "copper",
        "sway": 1.8,
        "links": 18,
        "background": "#1c1818"
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 12,
    "posterSeconds": 3,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": true,
      "cycleSeconds": 12,
      "method": "The sag breathes in a sine of the loop and a wave of sway runs along the chain as sines of whole cycles of the loop (two and three), so the last frame meets the first."
    },
    "seed": null
  },
  "composition": {
    "inputs": "Time within the loop; the links, metal, sag, sway, backdrop and camera drift.",
    "outputs": "A full frame rendered in 3D with soft shadows and a studio environment.",
    "coordinates": "Posts at x = ±5.2; the chain runs between y = 5 on the posts and sags to about y = 2.4; it sways along z.",
    "lighting": "A warm key light with a shadow map and the studio environment on the polished metal.",
    "timing": "setProgress(progress) places every link; frames render in any order.",
    "compatibleWith": [
      "chrome-material",
      "orbit-camera",
      "kinetic-title",
      "number-reveal"
    ],
    "notes": [
      "The links are spaced evenly by arc length along a catenary re-solved for each frame's sag; each link's orientation follows the tangent with an extra quarter-turn on alternate links."
    ]
  },
  "reuse": [
    "Industrial or security title: Steel, twenty-four links.",
    "Luxury accent: Brass, deep sag.",
    "Heavy impact scene: Copper, heavy swing."
  ],
  "integration": {
    "newProject": "Create a WebGLRenderer with shadows and a studio environment (see chrome-material), add createChain().group and call chain.setProgress(progress) each frame.",
    "existingProject": "Copy src/chain-links.js; add chain.group to your scene with an environment map and a shadow-casting light."
  },
  "performance": {
    "notes": "One instanced mesh of up to 40 links (about 3 000 triangles each) and two posts, 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 links are placed along a curve rather than simulated: they do not collide or interlock physically.",
    "The chain's length is fixed by its link count, so a deep sag stretches the spacing a little."
  ],
  "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/objects-scenes/chain-links (MIT) and rebuilt for AI Pixel Wizard in October 2026 as an original object: stadium-shaped links on a re-solved catenary with alternating orientation, a travelling sway wave and an exact loop.",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-05",
      "notes": "Initial release."
    }
  ]
}
