{"record":{"id":"f8ea464b7c59f8e9","repo":"asgeirtj/system_prompts_leaks","slug":"three-d-stage-not-ready-await-stage-ready-first","errorCode":null,"errorMessage":"three-d-stage: not ready — await stage.ready first","messagePattern":"three-d-stage: not ready — await stage\\.ready first","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"Anthropic/Claude Design/Starter components/three-d-stage.js","lineNumber":307,"sourceCode":"      }\n\n      this._readyResolve({ THREE });\n    }\n\n    disconnectedCallback() {\n      // Stop rendering and observing while detached; connectedCallback\n      // resumes both. (The renderer itself is kept — a move within the\n      // document must not rebuild the scene.)\n      if (this._renderer) this._renderer.setAnimationLoop(null);\n      if (this._ro) this._ro.disconnect();\n    }\n\n    /** Show (and own) the object. Replaces any previous object, enables\n     *  shadows on every mesh, rests it on the ground plane, and frames\n     *  the camera to its bounds. */\n    setObject(object) {\n      const THREE = this._THREE;\n      if (!THREE) throw new Error('three-d-stage: not ready — await stage.ready first');\n      if (this._object) this._scene.remove(this._object);\n      this._object = object;\n      object.traverse((o) => {\n        if (o.isMesh) {\n          o.castShadow = true;\n          o.receiveShadow = true;\n        }\n      });\n      const box = new THREE.Box3().setFromObject(object);\n      if (!box.isEmpty()) {\n        // Rest the object on the ground without moving its origin.\n        this._ground.position.y = box.min.y;\n        const sphere = box.getBoundingSphere(new THREE.Sphere());\n        const dist =\n          (sphere.radius / Math.tan((this._camera.fov * Math.PI) / 360)) * 1.35;\n        const dir = new THREE.Vector3(1, 0.55, 1.25).normalize();\n        this._camera.position\n          .copy(sphere.center)","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/asgeirtj/system_prompts_leaks/blob/93c999115b300a6faac567830b0450a5478800cd/Anthropic/Claude Design/Starter components/three-d-stage.js#L289-L325","documentation":"The <three-d-stage> custom element throws this from setObject() when this._THREE is undefined. _THREE is only assigned inside the async _boot() (line 213), which dynamically imports three.js and its addons through the page import map. The ready Promise (created in the constructor at line 179, resolved at the end of _boot() at line 291) is the synchronization point — it yields { THREE } once the scene is live. Calling setObject before that promise settles dereferences a null THREE namespace, so the guard throws rather than producing a less obvious TypeError deeper in.","triggerScenarios":"Calling stage.setObject(model) synchronously after document.querySelector('three-d-stage') without awaiting stage.ready. Also fires when _boot() rejected (import map missing/broken, CDN unreachable, version mismatch) so _THREE was never assigned — the ready Promise rejects but if the caller never awaited it, the rejection is swallowed and the next setObject call hits the null guard.","commonSituations":"Copy-pasting usage code that omits the `const { THREE } = await stage.ready` line shown in the header docs. Placing the <script type=\"importmap\"> after the module script, or omitting it entirely, so import('three') fails. A wrong/unpinned three.js version in the import map where the addons path layout differs. Calling setObject from a non-async callback that cannot await the promise.","solutions":["Await stage.ready before calling setObject — `const { THREE } = await stage.ready;` resolves once three.js is loaded and the scene is built.","Verify the <script type=\"importmap\"> block is in <head> before any module script, with the exact pinned three@0.184.0 URLs and integrity hashes from the header docs.","If _boot() rejected, read the red .err overlay on the stage element — it shows the specific import failure (CDN, version, or integrity) that prevented _THREE from being set.","If calling from a non-async context, restructure so the model build and setObject happen inside an async function that can await stage.ready."],"exampleFix":"// before\nconst stage = document.querySelector('three-d-stage');\nconst model = new THREE.Group(); // THREE is not in scope / _THREE not set\nstage.setObject(model); // throws: not ready\n\n// after\nconst stage = document.querySelector('three-d-stage');\nconst { THREE } = await stage.ready;\nconst model = new THREE.Group();\nstage.setObject(model);","handlingStrategy":"validation","validationCode":"// stage.ready is a Promise<{ THREE }> created in the constructor\n// and resolved at the end of _boot(). Awaiting it is the only\n// correct precondition for setObject — there is no sync flag.\nconst { THREE } = await stage.ready; // resolves, or rejects on _boot failure\n// Now safe to build the model and call stage.setObject(...)","typeGuard":"// There is no public sync readiness flag; _THREE is the internal\n// signal set inside _boot(). Use it only if you must check without\n// awaiting (it can be undefined during the initial boot race):\nfunction isStageReady(stage) {\n  return Boolean(stage._THREE) && Boolean(stage._scene);\n}\n// Prefer awaiting stage.ready — this guard is for diagnostics only.","tryCatchPattern":"try {\n  stage.setObject(model);\n} catch (e) {\n  if (e.message.startsWith('three-d-stage: not ready')) {\n    const { THREE } = await stage.ready; // may itself reject if _boot failed\n    stage.setObject(model);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always structure three-d-stage usage inside an async function whose first line is `const { THREE } = await stage.ready;` — this matches the documented usage block at the top of the file.","Put the <script type=\"importmap\"> in <head> before any module script so import('three') in _boot() never fails.","Add `three-d-stage:not(:defined){visibility:hidden}` CSS so the stage is never visible (and setObject never tempting) before the element upgrades.","If _boot() may reject (flaky CDN), wrap `await stage.ready` in its own try/catch and surface the failure rather than letting a subsequent setObject hit the null guard."],"tags":["three-js","web-component","lifecycle","async","import-map"],"backgroundTag":null,"analyzedSha":"93c999115b300a6faac567830b0450a5478800cd","analyzedAt":"2026-08-13T00:22:15.267Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}