{
  "schemaVersion": 1,
  "id": "hourglass",
  "version": "1.0.0",
  "status": "published",
  "kind": "object",
  "title": "Hourglass",
  "summary": "A glass-and-brass hourglass: the sand runs, the glass flips, the sand runs again. Loops perfectly.",
  "description": "A classic sand glass floating in a dark studio: a glass double-bulb between two turned metal plates on three slender posts. A thin stream of sand runs through the neck, the upper pile sinking into a funnel while the lower one builds a cone at the angle of repose; when it has all run through the glass turns over, the sand slumping from the cone into a funnel on its new top, and it runs again. Choose the sand (any colour), the metal of the frame (brass, copper, chrome or black), a tint in the glass, and how much of the loop is spent turning the glass over.",
  "role": "Hero object (Three.js 3D): the classic symbol of time running out, for countdowns, deadlines and reflective content.",
  "collections": [
    "satisfying",
    "hypnotic-loops",
    "product-reveals"
  ],
  "tags": [
    "hourglass",
    "sand timer",
    "time",
    "countdown",
    "deadline",
    "sand",
    "glass",
    "brass",
    "clock",
    "loop",
    "3d"
  ],
  "synonyms": [
    "sand glass",
    "sand clock",
    "egg timer",
    "time running out",
    "countdown timer",
    "falling sand",
    "time passing",
    "deadline animation"
  ],
  "useCases": [
    "A deadline, countdown or limited-offer visual: time is running out",
    "A reflective, philosophical or documentary shot about time",
    "A calm, satisfying loop behind a quote or a title"
  ],
  "featured": null,
  "publishedAt": "2026-10-06",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/hourglass.js",
    "exports": [
      {
        "name": "createHourglass",
        "signature": "createHourglass({ sand?, finish?, tint?, origin?, seed? }) => { group, half, uniforms, update(time, loopSeconds, { flip? }), dispose() }",
        "description": "The hourglass as a THREE.Group (1 unit = 10 cm), hung at origin. update(time, loopSeconds) runs the sand and then turns the glass over; the whole thing repeats exactly. Set uniforms.uKey to your key light's direction."
      },
      {
        "name": "FINISHES",
        "signature": "FINISHES: { brass, copper, chrome, black }",
        "description": "Finishes for the plates and posts."
      }
    ],
    "reusable": [
      "src/hourglass.js"
    ],
    "demo": "demo.js",
    "harness": "index.html"
  },
  "dependencies": [
    {
      "id": "three",
      "version": "0.185.1",
      "reason": "Renderer, physical glass and metal, and the sand's ray-marching shader."
    },
    {
      "id": "chrome-material",
      "version": "1.1.0",
      "scope": "demo",
      "reason": "Studio environment light, backdrop, floor and contact shadow."
    },
    {
      "id": "apw-runtime",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo harness."
    }
  ],
  "params": [
    {
      "key": "sand",
      "label": "Sand",
      "type": "color",
      "default": "#e3b86a"
    },
    {
      "key": "finish",
      "label": "Frame",
      "type": "select",
      "default": "brass",
      "options": [
        {
          "value": "brass",
          "label": "Brass"
        },
        {
          "value": "copper",
          "label": "Copper"
        },
        {
          "value": "chrome",
          "label": "Chrome"
        },
        {
          "value": "black",
          "label": "Black lacquer"
        }
      ]
    },
    {
      "key": "tint",
      "label": "Glass tint",
      "type": "color",
      "default": "#ffffff"
    },
    {
      "key": "flip",
      "label": "Time spent turning over",
      "help": "The share of the loop that the glass spends turning, 0.1 to 0.35.",
      "type": "number",
      "min": 0.1,
      "max": 0.35,
      "step": 0.01,
      "default": 0.2
    },
    {
      "key": "background",
      "label": "Backdrop",
      "type": "color",
      "default": "#10131b"
    },
    {
      "key": "seed",
      "label": "Seed",
      "help": "Changes the grain of the sand.",
      "type": "integer",
      "min": 1,
      "max": 999,
      "step": 1,
      "default": 3
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Golden sand, brass frame",
      "params": {}
    },
    {
      "id": "chrome",
      "label": "White sand, chrome frame",
      "params": {
        "sand": "#f1efe8",
        "finish": "chrome",
        "background": "#0b121d",
        "seed": 8
      }
    },
    {
      "id": "red",
      "label": "Red sand, black lacquer",
      "params": {
        "sand": "#d13a2e",
        "finish": "black",
        "tint": "#e6f4ff",
        "background": "#1a1012",
        "seed": 12
      }
    },
    {
      "id": "copper",
      "label": "Slate sand, copper frame",
      "params": {
        "sand": "#6b7388",
        "finish": "copper",
        "background": "#241b17",
        "flip": 0.14,
        "seed": 5
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 16,
    "posterSeconds": 6,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": true,
      "cycleSeconds": 16,
      "method": "The sand runs, then the glass turns over by exactly half a turn. The glass, plates, posts and sand are all symmetric under that half turn (the grain is defined in each bulb's own frame), so the last frame meets the first."
    },
    "seed": {
      "param": "seed",
      "behavior": "Seed changes the grain of the sand and the glints in it."
    }
  },
  "composition": {
    "inputs": "Time within the loop; the sand colour, frame finish, glass tint and the share of the loop spent turning over.",
    "outputs": "A THREE.Group: plates, posts, glass and the sand volume, centred on the origin (or origin option).",
    "coordinates": "1 unit = 10 cm. The glass is 2.6 tall inside two plates, 3.0 overall, and 1.1 across at its widest.",
    "lighting": "Physical glass and metal: needs scene.environment. The sand is lit in its own shader by a key light (set uniforms.uKey to the real light's direction) and a sky fill.",
    "timing": "update(time, loopSeconds) is a pure function of time; frames render in any order.",
    "compatibleWith": [
      "chrome-material",
      "orbit-camera",
      "kinetic-title"
    ],
    "notes": [
      "The sand volume is opaque on purpose: three.js transmission refracts only opaque objects, so the glass can show it.",
      "To make a countdown, set the loop to your countdown's length and spend the flip share at its end."
    ]
  },
  "reuse": [
    "Deadline: Golden sand, brass frame, with a bold 'Time is running out' over the top.",
    "Timer sting: White sand in chrome, a 10-second loop, then your logo.",
    "Documentary: Slate sand in copper, slow, behind a voice-over about time."
  ],
  "integration": {
    "newProject": "Set scene.environment (createStudioEnvironment from Chrome Material works), add createHourglass({ origin }).group and a light, set uniforms.uKey, and call update(time, loopSeconds) each frame.",
    "existingProject": "Copy src/hourglass.js. Add the group to your scene (scale it to suit), set uniforms.uKey to your key light, and call update(seconds, loopSeconds) every frame."
  },
  "performance": {
    "notes": "One ray-marched pass over the glass's silhouette (up to 110 steps) and one transmissive glass shell. Smooth at 1080p on laptop GPUs.",
    "limits": "Software WebGL (no GPU) renders slowly. Transmission renders the opaque scene a second time."
  },
  "limitations": [
    "The sand is a smooth volume with a grain texture, not simulated grains: the stream is a thin steady column.",
    "The glass turns about its centre in mid-air; it never rests on a surface."
  ],
  "license": {
    "spdx": "MIT",
    "notice": "Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.",
    "thirdParty": [
      {
        "name": "three.js",
        "version": "0.185.1",
        "license": "MIT",
        "url": "https://github.com/mrdoob/three.js"
      }
    ]
  },
  "provenance": "Adapted from the owner's threejs-sketches/objects-scenes/hourglass-sand (and webgpu-hourglass-flow) (MIT), rebuilt for AI Pixel Wizard in October 2026: a ray-marched sand volume with a cone and a funnel at the angle of repose, a stream, a modelled glass and turned frame that are symmetric under a half turn so the flip loops exactly, and the frame/time contract.",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-05",
      "notes": "Initial release."
    }
  ]
}
