{
  "schemaVersion": 1,
  "id": "glass-container",
  "version": "1.0.0",
  "status": "published",
  "kind": "object",
  "title": "Glass Container",
  "summary": "A clear glass box with real wall thickness, set up so objects inside it look right.",
  "description": "A see-through glass box (open top by default) made of solid panes with real thickness, and a physically based glass material that bends the light behind it. Glass is easy to get wrong in 3D: this one is configured the way the renderer needs it, so you can drop things inside, pour balls into it, or turn it on a turntable. Its inside measurements line up with the Bouncing Balls simulation by default.",
  "role": "Container object: a transparent box whose inner volume matches physics boxes.",
  "collections": [
    "chrome-glass",
    "product-reveals",
    "bouncing-falling"
  ],
  "tags": [
    "glass",
    "transparent",
    "refraction",
    "container",
    "box",
    "jar",
    "tank",
    "clear",
    "3d",
    "material"
  ],
  "synonyms": [
    "see-through",
    "glass box",
    "glass container",
    "fish tank",
    "terrarium",
    "jar",
    "crystal",
    "clear box",
    "aquarium"
  ],
  "useCases": [
    "Balls or objects falling into a glass box",
    "Product in a display case",
    "Terrarium or specimen-jar looks"
  ],
  "featured": 5,
  "publishedAt": "2026-10-02",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/glass-container.js",
    "exports": [
      {
        "name": "createGlassMaterial",
        "signature": "createGlassMaterial({ tint?, roughness?, thickness?, ior?, attenuationDistance? }) => THREE.MeshPhysicalMaterial",
        "description": "Transmission-based clear glass."
      },
      {
        "name": "createGlassBox",
        "signature": "createGlassBox({ width?, height?, depth?, wall?, open?, material? }) => THREE.Group",
        "description": "Box of slab walls. Inner size = width × height × depth, floor top at y = 0."
      },
      {
        "name": "disposeGlassBox",
        "signature": "disposeGlassBox(group) => void",
        "description": "Frees geometries and material."
      }
    ],
    "reusable": [
      "src/glass-container.js"
    ],
    "demo": "demo.js",
    "harness": "index.html"
  },
  "dependencies": [
    {
      "id": "three",
      "version": "0.185.1",
      "reason": "WebGL rendering (MeshPhysicalMaterial transmission)."
    },
    {
      "id": "chrome-material",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo uses createStudioEnvironment for reflections and a chrome ball. Any environment map works with the glass."
    },
    {
      "id": "apw-runtime",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo harness."
    }
  ],
  "params": [
    {
      "key": "tint",
      "label": "Glass tint",
      "help": "Colour the glass picks up through its thickness.",
      "type": "color",
      "default": "#e8fbff"
    },
    {
      "key": "frost",
      "label": "Frosting",
      "help": "0 is crystal clear; higher is frosted.",
      "type": "number",
      "min": 0,
      "max": 0.4,
      "step": 0.01,
      "default": 0.03
    },
    {
      "key": "ior",
      "label": "Bend of light (IOR)",
      "help": "1.5 is window glass, 1.33 water, 2.4 diamond.",
      "type": "number",
      "min": 1.1,
      "max": 2.4,
      "step": 0.01,
      "default": 1.5
    },
    {
      "key": "wall",
      "label": "Wall thickness",
      "type": "number",
      "min": 0.03,
      "max": 0.2,
      "step": 0.01,
      "default": 0.07
    },
    {
      "key": "turns",
      "label": "Turns per clip",
      "type": "integer",
      "min": 0,
      "max": 2,
      "step": 1,
      "default": 1
    },
    {
      "key": "accent",
      "label": "Accent colour",
      "type": "color",
      "default": "#7c6cff"
    },
    {
      "key": "background",
      "label": "Background",
      "type": "color",
      "default": "#0b0b10"
    }
  ],
  "presets": [
    {
      "id": "clear",
      "label": "Crystal clear",
      "params": {}
    },
    {
      "id": "frosted",
      "label": "Frosted",
      "params": {
        "frost": 0.28,
        "tint": "#ffffff"
      }
    },
    {
      "id": "emerald",
      "label": "Thick green glass",
      "params": {
        "tint": "#5fe3a8",
        "wall": 0.16,
        "ior": 1.7,
        "accent": "#ffcf73"
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 8,
    "posterSeconds": 1,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": true,
      "cycleSeconds": 8,
      "method": "Whole turntable turns over the clip (seamless when Turns per clip is a whole number, which it always is)."
    },
    "seed": null
  },
  "composition": {
    "inputs": "Inner size and wall thickness. Needs scene.environment for highlights.",
    "outputs": "A THREE.Group named GlassBox; inner volume x ∈ [−w/2, w/2], y ∈ [0, h], z ∈ [−d/2, d/2].",
    "coordinates": "Y-up. Floor top at y = 0, centred on the origin. Matches Bouncing Balls' default box when width 4, height 3, depth 4.",
    "lighting": "Image-based: set scene.environment (e.g. createStudioEnvironment from Chrome Material). Tone mapping recommended.",
    "timing": "Static object. The demo rotates a turntable group.",
    "compatibleWith": [
      "chrome-material",
      "bouncing-balls",
      "orbit-camera"
    ],
    "notes": [
      "Glass seen through glass is not rendered (Three.js transmission samples opaque objects only). Keep contents opaque.",
      "Transmission is a WebGL2 feature; it costs one extra render pass."
    ]
  },
  "reuse": [
    "Pour Bouncing Balls into it — the default inner size is the same 4 × 3 × 4 box (see Bouncing Marbles in a Box).",
    "Use createGlassMaterial alone on a sphere or a bottle shape.",
    "Close the lid (open: false) for a display case around a product."
  ],
  "integration": {
    "newProject": "Create a renderer with tone mapping, set scene.environment, add createGlassBox({ width, height, depth }) and put opaque objects inside.",
    "existingProject": "Copy src/glass-container.js. Add the group to your existing scene at the position you want; make sure your scene has an environment map. Do not switch your other materials to transmission."
  },
  "performance": {
    "notes": "One extra render pass for transmission. Fine on laptops; heavy on low-end phones at 4K.",
    "limits": "Avoid many separate transmissive objects; each one still shares the single transmission pass but overdraw adds up."
  },
  "limitations": [
    "No glass-behind-glass: the back pane is not visible through the front pane.",
    "No caustics (light focused through glass onto the floor)."
  ],
  "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": "Original code written for AI Pixel Wizard in October 2026. No external textures or models.",
  "changelog": [
    {
      "version": "1.0.0",
      "date": "2026-10-02",
      "notes": "Initial release."
    }
  ]
}
