{"id":15019022,"url":"https://github.com/w3reality/threelet","last_synced_at":"2025-03-17T13:11:39.350Z","repository":{"id":34846915,"uuid":"184553206","full_name":"w3reality/threelet","owner":"w3reality","description":"Portable 3D/WebXR component based on three.js","archived":false,"fork":false,"pushed_at":"2025-02-04T01:29:45.000Z","size":40303,"stargazers_count":48,"open_issues_count":1,"forks_count":5,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-12T18:50:29.400Z","etag":null,"topics":["threejs","webgl","webxr"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/w3reality.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-02T09:19:59.000Z","updated_at":"2025-02-28T16:14:42.000Z","dependencies_parsed_at":"2023-02-12T00:01:18.664Z","dependency_job_id":"eaa1cec6-f994-4063-8548-095861e39155","html_url":"https://github.com/w3reality/threelet","commit_stats":{"total_commits":399,"total_committers":2,"mean_commits":199.5,"dds":"0.17042606516290726","last_synced_commit":"adc220fa2a91a0778ad68244a54bc83e2465e90f"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w3reality%2Fthreelet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w3reality%2Fthreelet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w3reality%2Fthreelet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w3reality%2Fthreelet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/w3reality","download_url":"https://codeload.github.com/w3reality/threelet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243864808,"owners_count":20360357,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["threejs","webgl","webxr"],"created_at":"2024-09-24T19:52:47.075Z","updated_at":"2025-03-17T13:11:39.326Z","avatar_url":"https://github.com/w3reality.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# threelet\n\n[![npm][npm-badge]][npm-url]\n[![MIT licensed][mit-badge]][mit-url]\n[![CI][actions-badge]][actions-url]\n\n[npm-badge]: https://img.shields.io/npm/v/threelet.svg\n[npm-url]: https://www.npmjs.com/package/threelet\n[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg\n[mit-url]: https://github.com/w3reality/threelet/blob/master/LICENSE\n[actions-badge]: https://github.com/w3reality/threelet/workflows/CI/badge.svg\n[actions-url]: https://github.com/w3reality/threelet/actions\n\n**threelet** is a [three.js](https://github.com/mrdoob/three.js/) based component for rapidly developing 3D/WebXR apps all at once!\n\nUsing threelet\\'s built-in features, developers who have a minimal knowledge of three.js can immediately start writing interactive 3D apps with less code.\n\nSome notable features include:\n\n- built-in render loop manager (with auto VR context switching),\n- function interface `.update = (t, dt) =\u003e {}` for programming temporal 3D scenes, and\n- input device abstraction: mouse/pointer/xr-controller event listeners.\n\n## Demos\n\n### Basic demos\n\n- Hello world (with the default axes and a unit lattice) [ [live](https://w3reality.github.io/threelet/examples/simple/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/simple/index.html) |  [Observable](https://observablehq.com/@j-devel/hello-world-with-threelet) ]\n- Hello VR world [ [live](https://w3reality.github.io/threelet/examples/simple-webvr/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/simple-webvr/index.html) | [Observable](https://observablehq.com/@j-devel/hello-world-with-threelet/2) ]\n- Hybrid apps with WebXR buttons. [ [live](https://w3reality.github.io/threelet/examples/embed-multiple-buttons/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/embed-multiple-buttons/index.html) ]\n- App with a static scene (mouse-event driven passive rendering) [  [live](https://w3reality.github.io/threelet/examples/simple-static/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/simple-static/index.html) | [Observable](https://observablehq.com/@j-devel/making-a-static-3d-app) ]\n- App with a dynamic scene (rendering at 30 fps) [ [live](https://w3reality.github.io/threelet/examples/simple-dynamic/index.html) |  [source](https://github.com/w3reality/threelet/tree/master/examples/simple-dynamic/index.html) | [Observable](https://observablehq.com/@j-devel/making-a-dynamic-3d-app) ]\n- App extending the `Threelet` class (Object-Oriented Programming) [  [live](https://w3reality.github.io/threelet/examples/simple-oop/index.html)  | [source](https://github.com/w3reality/threelet/tree/master/examples/simple-oop/index.html) ]\n- Embedding a 3D viewer into a web page. [ [live](https://w3reality.github.io/threelet/examples/embed-inline-block/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/embed-inline-block/index.html) ]\n- 💡 Embedding multiple independent viewers into a web page. [ [live](https://w3reality.github.io/threelet/examples/embed-multiple/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/embed-multiple/index.html) ]\n- Hello glTF animation. [ [live](https://w3reality.github.io/threelet/examples/animation-hello/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/animation-hello/index.html) ]\n- 🦀 rust-canvas-hello: Drawing on a 3D plane via [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) and Rust. [ [live](https://w3reality.github.io/threelet/examples/rust-canvas-hello/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/rust-canvas-hello) ]\n\n### App demos\n\n- VR app with interactive objects [ [live](https://w3reality.github.io/threelet/examples/webvr-interactive/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/webvr-interactive/index.html) | [Observable](https://observablehq.com/@j-devel/making-an-interactive-vr-app) ]\n- 🎮 WebXR controller state visualizer [ [live](https://w3reality.github.io/threelet/examples/webvr-controllers/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/webvr-controllers) | [video](https://w3reality.github.io/threelet/examples/webvr-controllers/media/webvr-controllers.mp4) ]\n- 🎬 Animation player (with glTF, FBX and Collada models). [ [live](https://w3reality.github.io/threelet/examples/animation-player/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/animation-player/index.html) ]\n- glTF model selection panel. [ [live](https://w3reality.github.io/threelet/examples/model-selection/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/model-selection/index.html) ]\n- In-window VR casting. [ [live](https://w3reality.github.io/threelet/examples/vr-casting-in-window/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/vr-casting-in-window/index.html) ]\n- 🎨 vr-paint app [ [live](https://w3reality.github.io/threelet/examples/vr-paint/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/vr-paint) ]\n- 🤖 ML app (MNIST with LeNet) [ [live](https://w3reality.github.io/spacial-ml/examples/lenet/index.html) | [source](https://github.com/w3reality/spacial-ml/tree/master/examples/lenet/index.html) ] 🔗\n- 🦀 rust-canvas-juliaset: Interactive 3D app that can visualize Julia sets. [  [live](https://w3reality.github.io/threelet/examples/rust-canvas-juliaset/index.html)  | [source](https://github.com/w3reality/threelet/tree/master/examples/rust-canvas-juliaset) ]\n- 🦀 rust-fern-bench: WebXR app for benchmarking fractal computation with Rust+wasm vs JavaScript. [ [live](https://w3reality.github.io/threelet/examples/rust-fern-bench/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/rust-fern-bench) | [video](https://w3reality.github.io/threelet/examples/rust-fern-bench/rust-fern-bench.mp4) ]\n- 🗺️ geo-viewer [ [live](https://w3reality.github.io/three-geo/examples/geo-viewer/io/index.html?lat=46.5763\u0026lng=7.9904\u0026title=Eiger) | [source](https://github.com/w3reality/three-geo/tree/master/examples/geo-viewer) ] 🔗\n\n### Screenshots\n\n- [App with a dynamic scene](https://w3reality.github.io/threelet/examples/simple-dynamic/index.html)\n\n  [![image](https://w3reality.github.io/threelet/examples/simple-dynamic/index.jpg)](https://w3reality.github.io/threelet/examples/simple-dynamic/index.html)\n\n- [Animation player](https://w3reality.github.io/threelet/examples/animation-player/index.html)\n\n  [![image](https://w3reality.github.io/threelet/examples/media/img/mora2.jpg)](https://w3reality.github.io/threelet/examples/animation-player/index.html)\n\n- [In-window VR casting](https://w3reality.github.io/threelet/examples/vr-casting-in-window/index.html)\n\n  [![image](https://w3reality.github.io/threelet/examples/media/img/casting-2.jpg)](https://w3reality.github.io/threelet/examples/vr-casting-in-window/index.html)\n\n## Installation\n\n```\n$ npm i threelet\n```\n\n## Hello world\n\n```html\n\u003ccanvas id=\"canvas\" style=\"width: 100%; height: 100%;\"\u003e\u003c/canvas\u003e\n\n\u003cscript src=\"../deps/three/build/three.min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"../deps/three/examples/js/controls/OrbitControls.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"../deps/three/examples/js/libs/stats.min.js\"\u003e\u003c/script\u003e\n\n\u003cscript src=\"../../dist/threelet.min.js\"\u003e\u003c/script\u003e\n\n\u003cscript\u003e\nconst threelet = new Threelet({\n    canvas: document.getElementById('canvas'),\n});\n\nthreelet.setup('mod-controls', THREE.OrbitControls);\nthreelet.setup('mod-stats', window.Stats);\n\nthreelet.render(); // first time\n\u003c/script\u003e\n```\n\n[live](https://w3reality.github.io/threelet/examples/simple/index.html) | [source code](https://github.com/w3reality/threelet/tree/master/examples/simple/index.html)\n\n[![image](https://w3reality.github.io/threelet/examples/simple/img/threelet.png)](https://w3reality.github.io/threelet/examples/simple/index.html)\n\n## More usage\n\n### Basic\n\n`camera`, `scene` and `renderer` can be automatically/manually configured:\n\n```js\nconst threelet = new Threelet({canvas: myCanvas});\n// now the following objects are all set\n//   threelet.camera\n//   threelet.scene (with the default axes and a unit lattice)\n//   threelet.renderer\n```\n\n`scene` can be customized as:\n\n```js\nconst threelet = new Threelet({\n    canvas: myCanvas,\n    optScene: myScene, // instantiate with a custom scene\n});\n\nthreelet.scene.add(myObject) // add an object to the scene\n```\n\nspecifying render modes (passive, active, and fps-throttled) by the built-in loop controller:\n\n```js\nthreelet.updateLoop(fps); // render at fps using the built-in looper\n\nthreelet.render(); // atomic render manually\n```\n\nprogramming 3D scene dynamics ([example](https://w3reality.github.io/threelet/examples/simple-dynamic/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/simple-dynamic/index.html)):\n\n```js\nthreelet.update = (t, dt) =\u003e {\n   // your implementation\n};\n```\n\n`dispose()` terminates the loop and disposes all the scene objects:\n\n```js\nthreelet.dispose();\n```\n\n### Parameters\n\nCalling the constructor with the default parameters looks as:\n\n```js\nconst threelet = new Threelet({\n    canvas: null,\n    width: 480,\n    height: 320,\n    // ---- viewer options ----\n    optScene: null,\n    optVR: false, // enable VR 🔥\n    optAR: false, // enable AR 🔥\n    optXR: false, // enable both VR/AR\n    optVRAppendButtonTo: null, // specify an HTML element where the VR button is appended\n    optARAppendButtonTo: null, // specify an HTML element where the AR button is appended\n    optAxes: true, // axes and a unit lattice\n    optCameraPosition: [0, 1, 2], // initial camera position in desktop mode\n});\n```\n\n### Extending the Threelet class (Object-Oriented Programming)\n\n[example](https://w3reality.github.io/threelet/examples/simple-oop/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/simple-oop/index.html)\n\n```js\nclass App extends Threelet {\n    // override\n    onCreate(params) {\n        // ...\n    }\n\n    // override\n    onUpdate(t, dt) { // note: this method is not called when this.update is defined\n        // ...\n    }\n\n    // override\n    onDestroy() {\n        // ...\n    }\n}\n```\n\n### Embedding\n\nWithout the `canvas` parameter, the constructor creates an inline-block div element (`threelet.domElement`) that is ready to be embedded into a web page.\n\nExamples: [single](https://w3reality.github.io/threelet/examples/embed-inline-block/index.html) | [multiple](https://w3reality.github.io/threelet/examples/embed-multiple/index.html)\n\n```html\n\u003cdiv\u003e\n    This \u003cspan id=\"viewer\"\u003e\u003c/span\u003e is an inline-block element.\n\u003c/div\u003e\n\n\u003cscript\u003e\nconst threelet = new Threelet({width: 480, height: 320});\ndocument.getElementById('viewer').appendChild(threelet.domElement);\n\u003c/script\u003e\n```\n\n### High-level input management\n\n[example](https://w3reality.github.io/threelet/examples/vr-paint/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/vr-paint/index.html)\n\n```js\nthreelet.setupMouseInterface({\n    onClick: (mx, my) =\u003e { /* ... */ },\n    onDrag: (mx, my) =\u003e { /* ... */ },\n    onDragStart: (mx, my) =\u003e { /* ... */ },\n    onDragEnd: (mx, my) =\u003e { /* ... */ },\n});\n\nthreelet.setupPointerInterface({\n    onClick: (mx, my) =\u003e { /* ... */ },\n    onDrag: (mx, my) =\u003e { /* ... */ },\n    onDragStart: (mx, my) =\u003e { /* ... */ },\n    onDragEnd: (mx, my) =\u003e { /* ... */ },\n});\n\nthreelet.setupTouchInterface({\n    onClick: (mx, my) =\u003e { /* ... */ },\n    onDrag: (mx, my) =\u003e { /* ... */ },\n    onDragStart: (mx, my) =\u003e { /* ... */ },\n    onDragEnd: (mx, my) =\u003e { /* ... */ },\n});\n```\n\n### Low-level event listeners\n\nsetting mouse/pointer/touch listeners:\n\n[example](https://w3reality.github.io/threelet/examples/model-selection/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/model-selection/index.html)\n\n```js\n// mx, my: mouse coordinates\n\nthreelet.on('mouse-click', (mx, my) =\u003e { /* ... */ }); // alias of 'mouse-click-left'\nthreelet.on('mouse-click-left', (mx, my) =\u003e { /* ... */ });\nthreelet.on('mouse-click-middle', (mx, my) =\u003e { /* ... */ });\nthreelet.on('mouse-click-right', (mx, my) =\u003e { /* ... */ });\nthreelet.on('mouse-down', (mx, my) =\u003e { /* ... */ }); // alias of 'mouse-down-left'\nthreelet.on('mouse-down-left', (mx, my) =\u003e { /* ... */ });\nthreelet.on('mouse-down-middle', (mx, my) =\u003e { /* ... */ });\nthreelet.on('mouse-down-right', (mx, my) =\u003e { /* ... */ });\nthreelet.on('mouse-move', (mx, my) =\u003e { /* ... */ });\nthreelet.on('mouse-up', (mx, my) =\u003e { /* ... */ });\nthreelet.on('mouse-drag-end', (mx, my) =\u003e { /* ... */ });\n\nthreelet.on('pointer-click', (mx, my) =\u003e { /* ... */ }); // alias of 'pointer-click-left'\nthreelet.on('pointer-click-left', (mx, my) =\u003e { /* ... */ });\nthreelet.on('pointer-click-middle', (mx, my) =\u003e { /* ... */ });\nthreelet.on('pointer-click-right', (mx, my) =\u003e { /* ... */ });\nthreelet.on('pointer-down', (mx, my) =\u003e { /* ... */ }); // alias of 'pointer-down-left'\nthreelet.on('pointer-down-left', (mx, my) =\u003e { /* ... */ });\nthreelet.on('pointer-down-middle', (mx, my) =\u003e { /* ... */ });\nthreelet.on('pointer-down-right', (mx, my) =\u003e { /* ... */ });\nthreelet.on('pointer-move', (mx, my) =\u003e { /* ... */ });\nthreelet.on('pointer-up', (mx, my) =\u003e { /* ... */ });\nthreelet.on('pointer-drag-end', (mx, my) =\u003e { /* ... */ });\n\nthreelet.on('touch-start', (mx, my) =\u003e { /* ... */ });\nthreelet.on('touch-move', (mx, my) =\u003e { /* ... */ });\nthreelet.on('touch-end', (mx, my) =\u003e { /* ... */ });\nthreelet.on('touch-click', (mx, my) =\u003e { /* ... */ });\nthreelet.on('touch-drag-end', (mx, my) =\u003e { /* ... */ });\n```\n\nsetting VR controller listeners:\n\n[example](https://w3reality.github.io/threelet/examples/webvr-controllers/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/webvr-controllers/index.html)\n\n```js\n// i: controller index\n// x, y: controller touchpad coordinates\n\nthreelet.on('xr-trigger-press-start', i =\u003e { /* ... */ });\nthreelet.on('xr-trigger-press-end', i =\u003e { /* ... */ });\n\n// WIP\nthreelet.on('xr-touchpad-touch-start', (i, x, y) =\u003e { /* ... */ });\nthreelet.on('xr-touchpad-touch-end', (i, x, y) =\u003e { /* ... */ });\nthreelet.on('xr-touchpad-press-start', (i, x, y) =\u003e { /* ... */ });\nthreelet.on('xr-touchpad-press-end', (i, x, y) =\u003e { /* ... */ });   \n```\n\nunsetting listeners:\n\n```js\nthreelet.on(eventName, null);\n```\n\n### Raycasting\n\n```js\nthreelet.raycast(origin, direction, meshes, recursive=false, faceExclude=null);\nthreelet.raycastFromMouse(mx, my, meshes, recursive=false); // mx, my: mouse coordinates\nthreelet.raycastFromController(i, meshes, recursive=false); // i: VR controller index\n```\n\n### Utils\n\nanimation loading:\n\n[example](https://w3reality.github.io/threelet/examples/animation-hello/index.html) | [source](https://github.com/w3reality/threelet/tree/master/examples/animation-hello/index.html)\n\n```js\n// Using 'three/examples/jsm/loaders/GLTFLoader.js'\nconst data = await Threelet.Utils.loadGLTF(GLTFLoader, path, file);\n\n// Using 'three/examples/jsm/loaders/FBXLoader.js'\nconst data = await Threelet.Utils.loadFBX(FBXLoader, path);\n\n// Using 'three/examples/jsm/loaders/ColladaLoader.js'\nconst data = await Threelet.Utils.loadCollada(ColladaLoader, path);\n```\n\ncreating test THREE objects (used in the examples for shortcuts):\n\n```js\nconst obj = Threelet.Utils.createTestHemisphereLight();\nconst obj = Threelet.Utils.createTestDirectionalLight();\nconst obj = Threelet.Utils.createTestCube(size=[0.4, 0.1, 0.4], color=0xff00ff, wireframe=false);\nconst objs = Threelet.Utils.createTestObjects(offset=[0, 1, -2]);\n```\n\n### External modules\n\nOrbitControls, stats (and more to be added in future):\n\n```html\n\u003cscript src=\"OrbitControls.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"stats.min.js\"\u003e\u003c/script\u003e\n```\n\n```js\nthreelet.setup('mod-controls', THREE.OrbitControls); // enable controls\nthreelet.setup('mod-stats', window.Stats); // show the stats meter\n```\n\nSky based on the [shaders/sky](https://threejs.org/examples/?q=sky#webgl_shaders_sky) example in three.js:\n\n```html\n\u003cscript src=\"Sky.js\"\u003e\u003c/script\u003e\n\nthreelet.setup('mod-sky', THREE.Sky); // show sky with the analytical daylight\n```\n\n## Build\n\n```\n$ npm i\n$ npm run build\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fw3reality%2Fthreelet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fw3reality%2Fthreelet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fw3reality%2Fthreelet/lists"}