{
  "schemaVersion": 1,
  "id": "silk-ribbons",
  "version": "1.0.0",
  "status": "published",
  "kind": "background",
  "title": "Silk Ribbons",
  "summary": "Long ribbons of silk weaving across the frame, overlapping with soft seams and a moving highlight along each fold. Loops perfectly.",
  "description": "Long ribbons of silk drifting across the frame. Each ribbon is a smooth band whose centre line is a sum of sines, with its own width, colour and speed; where ribbons cross they overlap with a soft, slightly brighter seam, and a gentle highlight runs along each ribbon's fold. Every sine makes a whole number of cycles per loop, so the loop is exact. Choose the number of ribbons, the colours (dusk, ocean, gold or mono), how broad they are, how far they weave and the seed.",
  "role": "Shader background (three.js): an elegant flowing backdrop for titles, covers and calm scenes.",
  "collections": [
    "backgrounds",
    "hypnotic-loops",
    "satisfying"
  ],
  "tags": [
    "ribbons",
    "silk",
    "waves",
    "flowing",
    "fabric",
    "abstract",
    "gradient",
    "elegant",
    "luxury",
    "loop"
  ],
  "synonyms": [
    "flowing ribbons",
    "satin waves",
    "silk waves",
    "fabric background",
    "ribbon animation",
    "curtain waves"
  ],
  "useCases": [
    "A fashion, beauty or luxury title backdrop",
    "A calm background behind text or a product",
    "A flowing abstract loop for music or wellness"
  ],
  "featured": null,
  "publishedAt": "2026-10-08",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/silk-ribbons.js",
    "exports": [
      {
        "name": "createSilkRibbons",
        "signature": "createSilkRibbons({ ribbons?, palette?, width?, sway?, seed? }) => { scene, camera, setSize(width, height), update(time, loopSeconds), dispose() }",
        "description": "The ribbons as one full-screen shader; render its scene with its camera, ideally through createBloomPass."
      },
      {
        "name": "createBloomPass",
        "signature": "createBloomPass(renderer, { width, height, glow?, exposure?, grain? }) => { render(scene, camera, output?), dispose() }",
        "description": "A small bloom with tone mapping and a fixed grain."
      },
      {
        "name": "PALETTES",
        "signature": "PALETTES: { dusk, ocean, gold, mono }",
        "description": "Backdrop and ribbon colours."
      }
    ],
    "reusable": [
      "src/silk-ribbons.js"
    ],
    "demo": "demo.js",
    "harness": "index.html"
  },
  "dependencies": [
    {
      "id": "three",
      "version": "0.185.1",
      "reason": "Renderer and a full-screen shader material."
    },
    {
      "id": "apw-runtime",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo harness."
    }
  ],
  "params": [
    {
      "key": "ribbons",
      "label": "Ribbons",
      "type": "integer",
      "min": 2,
      "max": 6,
      "step": 1,
      "default": 6
    },
    {
      "key": "palette",
      "label": "Colours",
      "type": "select",
      "default": "dusk",
      "options": [
        {
          "value": "dusk",
          "label": "Dusk"
        },
        {
          "value": "ocean",
          "label": "Ocean"
        },
        {
          "value": "gold",
          "label": "Gold"
        },
        {
          "value": "mono",
          "label": "Mono"
        }
      ]
    },
    {
      "key": "width",
      "label": "Ribbon width",
      "type": "number",
      "min": 0.5,
      "max": 1.6,
      "step": 0.1,
      "default": 1
    },
    {
      "key": "sway",
      "label": "Sway",
      "type": "number",
      "min": 0.3,
      "max": 1.6,
      "step": 0.1,
      "default": 1
    },
    {
      "key": "seed",
      "label": "Seed",
      "type": "integer",
      "min": 1,
      "max": 999,
      "step": 1,
      "default": 3
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Dusk, six ribbons",
      "params": {}
    },
    {
      "id": "ocean",
      "label": "Ocean, broad",
      "params": {
        "palette": "ocean",
        "width": 1.5,
        "ribbons": 4,
        "seed": 8
      }
    },
    {
      "id": "gold",
      "label": "Gold, slow sway",
      "params": {
        "palette": "gold",
        "sway": 0.5,
        "seed": 15
      }
    },
    {
      "id": "mono",
      "label": "Mono, two ribbons",
      "params": {
        "palette": "mono",
        "ribbons": 2,
        "width": 1.3,
        "seed": 2
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 12,
    "posterSeconds": 3,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": true,
      "cycleSeconds": 12,
      "method": "Every sine that moves a ribbon makes a whole number of cycles per loop, so the last frame meets the first."
    },
    "seed": {
      "param": "seed",
      "behavior": "Seed places the ribbons and sets their widths, speeds and folds: same seed, same silk."
    }
  },
  "composition": {
    "inputs": "Time within the loop; the ribbons, colours, width, sway and seed.",
    "outputs": "A full-frame shader image through a bloom pass.",
    "coordinates": "Screen-centred, ±1 vertically; each ribbon's centre line is a function of x; ribbons are drawn back to front.",
    "lighting": "Self-lit; each ribbon is shaded across its width like a fold of silk, with brighter seams at its edges.",
    "timing": "update(time, loopSeconds) sets the loop phase; frames render in any order.",
    "compatibleWith": [
      "kinetic-title",
      "number-reveal"
    ],
    "notes": [
      "No textures: the whole look is trigonometry, which is why it loops exactly."
    ]
  },
  "reuse": [
    "Luxury title: Dusk, six ribbons.",
    "Cool and calm: Ocean, broad.",
    "Warm: Gold, slow sway."
  ],
  "integration": {
    "newProject": "Create a WebGLRenderer, createSilkRibbons() and createBloomPass(renderer, { width, height }); call silk.setSize(w, h) and each frame silk.update(time, loopSeconds) then bloom.render(silk.scene, silk.camera).",
    "existingProject": "Copy src/silk-ribbons.js and render silk.scene with silk.camera into your own target."
  },
  "performance": {
    "notes": "One full-screen fragment shader with six ribbons, plus the bloom: about 2 ms a frame at 1080² on an integrated Intel GPU.",
    "limits": "Software WebGL renders in about two seconds a frame."
  },
  "limitations": [
    "Ribbons are flat bands, not cloth: they do not fold over themselves.",
    "Many broad ribbons overlap into a solid wash of colour."
  ],
  "license": {
    "spdx": "MIT",
    "notice": "Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.",
    "thirdParty": []
  },
  "provenance": "Original code written for AI Pixel Wizard in October 2026, to the catalog quality bar (docs/QUALITY.md).",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-08",
      "notes": "Initial release."
    }
  ]
}
