{
  "schemaVersion": 1,
  "id": "dupin-cyclide",
  "version": "1.0.0",
  "status": "published",
  "kind": "object",
  "title": "Dupin Cyclide",
  "summary": "A smooth iridescent cyclide that breathes from a fat ring to a lopsided loop and back while it turns. Loops perfectly.",
  "description": "A Dupin cyclide: the smooth surface that bends, pinches and swells as its two shape numbers change, the generalisation of the torus. Here the numbers glide round a closed circle of values, so the surface breathes between a fat ring and a lopsided pear-shaped loop while it turns in space and an iridescent finish plays across it. Choose the finish (iridescent, chrome, pearl or gold), whether a net of curves lies on the surface, the mesh fineness, the turns per loop, how far the shape changes, the backdrop colour and whether the camera sways.",
  "role": "Object (3D, three.js): a mathematical showpiece with a liquid, iridescent look for science, design and tech content.",
  "collections": [
    "chrome-glass",
    "hypnotic-loops",
    "product-reveals"
  ],
  "tags": [
    "dupin cyclide",
    "cyclide",
    "torus",
    "surface",
    "geometry",
    "mathematics",
    "iridescent",
    "morph",
    "studio",
    "loop",
    "3d"
  ],
  "synonyms": [
    "cyclide surface",
    "morphing torus",
    "parametric surface",
    "ring cyclide",
    "math sculpture",
    "liquid metal ring"
  ],
  "useCases": [
    "A maths or design-tech title scene",
    "A premium product-style abstract loop",
    "A calm iridescent backdrop"
  ],
  "featured": null,
  "publishedAt": "2026-10-05",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/dupin-cyclide.js",
    "exports": [
      {
        "name": "createCyclide",
        "signature": "createCyclide({ finish?, lines?, detail?, turns?, morph? }) => { group, setProgress(progress), dispose() }",
        "description": "The morphing cyclide (about 4.4 across, centred on the origin); needs an environment map."
      },
      {
        "name": "FINISHES",
        "signature": "FINISHES: { iridescent, chrome, pearl, gold }",
        "description": "Surface finishes: colour, metalness, roughness, iridescence and film index."
      }
    ],
    "reusable": [
      "src/dupin-cyclide.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": "finish",
      "label": "Finish",
      "type": "select",
      "default": "iridescent",
      "options": [
        {
          "value": "iridescent",
          "label": "Iridescent"
        },
        {
          "value": "chrome",
          "label": "Chrome"
        },
        {
          "value": "pearl",
          "label": "Pearl"
        },
        {
          "value": "gold",
          "label": "Gold"
        }
      ]
    },
    {
      "key": "lines",
      "label": "Surface lines",
      "type": "boolean",
      "default": true
    },
    {
      "key": "detail",
      "label": "Mesh detail",
      "type": "number",
      "min": 0.6,
      "max": 1.4,
      "step": 0.1,
      "default": 1
    },
    {
      "key": "turns",
      "label": "Turns per loop",
      "type": "integer",
      "min": 0,
      "max": 3,
      "step": 1,
      "default": 1
    },
    {
      "key": "morph",
      "label": "Shape change",
      "type": "number",
      "min": 0,
      "max": 1.5,
      "step": 0.1,
      "default": 1
    },
    {
      "key": "background",
      "label": "Backdrop",
      "type": "color",
      "default": "#161a28"
    },
    {
      "key": "orbit",
      "label": "Camera sway",
      "type": "boolean",
      "default": true
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Iridescent, one turn",
      "params": {}
    },
    {
      "id": "chrome",
      "label": "Chrome, bare",
      "params": {
        "finish": "chrome",
        "lines": false,
        "background": "#10141c"
      }
    },
    {
      "id": "gold",
      "label": "Gold, big morph",
      "params": {
        "finish": "gold",
        "morph": 1.5,
        "background": "#241a12"
      }
    },
    {
      "id": "pearl",
      "label": "Pearl, two turns",
      "params": {
        "finish": "pearl",
        "turns": 2,
        "background": "#1e1a28"
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 16,
    "posterSeconds": 3,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": true,
      "cycleSeconds": 16,
      "method": "The two shape numbers are sines of the loop, the surface turns a whole number of times per loop and the camera sway is a sine of the loop, so the last frame meets the first."
    },
    "seed": null
  },
  "composition": {
    "inputs": "Time within the loop; the finish, lines, detail, turns, shape change, backdrop and camera sway.",
    "outputs": "A full frame rendered in 3D with a studio environment.",
    "coordinates": "The cyclide is centred on the origin, scaled to a fixed root-mean-square radius of 2, hung 3.3 above the floor.",
    "lighting": "A warm key light with a shadow map and the studio environment.",
    "timing": "setProgress(progress) rewrites the mesh from a closed form; frames render in any order.",
    "compatibleWith": [
      "chrome-material",
      "orbit-camera",
      "kinetic-title",
      "number-reveal"
    ],
    "notes": [
      "About 11 000 vertices are rewritten on the CPU each frame and the seam normals are averaged."
    ]
  },
  "reuse": [
    "Maths title: Iridescent, one turn.",
    "Product-style loop: Chrome, bare.",
    "Warm accent: Gold, big morph."
  ],
  "integration": {
    "newProject": "Create a WebGLRenderer with a studio environment, add createCyclide().group and call cyclide.setProgress(progress) each frame.",
    "existingProject": "Copy src/dupin-cyclide.js; add the group to your scene with an environment map."
  },
  "performance": {
    "notes": "About 11 000 vertices rewritten and re-normalised each frame: a few milliseconds a frame on an integrated Intel GPU.",
    "limits": "Software WebGL renders in about a second and a half a frame."
  },
  "limitations": [
    "The surface is scaled to a steady size, so its horns and pinches change apparent proportions.",
    "The ring cyclide has a singular point at its horn at the extreme of the morph, softened by the limited range."
  ],
  "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/geometry-math/dupin-cyclide (MIT) and rebuilt for AI Pixel Wizard in October 2026 as an original studio object: the ring cyclide's closed form with its two shape numbers on a closed loop, a size-steady mesh rewritten each frame and an iridescent finish on an exact loop.",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-05",
      "notes": "Initial release."
    }
  ]
}
