{"id":16397648,"url":"https://github.com/safrmo/vue-three-wrap","last_synced_at":"2025-03-21T02:32:34.056Z","repository":{"id":33979542,"uuid":"162466629","full_name":"SaFrMo/vue-three-wrap","owner":"SaFrMo","description":"Vue THREE.js wrapper","archived":false,"fork":false,"pushed_at":"2022-12-30T04:22:46.000Z","size":1473,"stargazers_count":10,"open_issues_count":20,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-05-06T21:43:37.903Z","etag":null,"topics":["three","threejs","vue"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SaFrMo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-19T16:57:35.000Z","updated_at":"2022-11-24T05:42:22.000Z","dependencies_parsed_at":"2023-01-15T03:46:25.152Z","dependency_job_id":null,"html_url":"https://github.com/SaFrMo/vue-three-wrap","commit_stats":null,"previous_names":["safrmo/vue-three"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SaFrMo%2Fvue-three-wrap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SaFrMo%2Fvue-three-wrap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SaFrMo%2Fvue-three-wrap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SaFrMo%2Fvue-three-wrap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SaFrMo","download_url":"https://codeload.github.com/SaFrMo/vue-three-wrap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244102831,"owners_count":20398386,"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":["three","threejs","vue"],"created_at":"2024-10-11T05:10:38.882Z","updated_at":"2025-03-21T02:32:33.737Z","avatar_url":"https://github.com/SaFrMo.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Bare-bones Vue component wrapping a THREE.js instance.\n\nSee examples [here](https://three-examples.netlify.com/) ([source](https://github.com/SaFrMo/nuxt-three/tree/master/components)).\n\n# Table of Contents\n\n1. [Main](#main)\n    1. [Props](#props)\n    1. [`start` and `update`](#start-and-update)\n    1. [CSS Renderer](#css-renderer)\n    1. [Shader Injection](#shader-injection)\n1. [Extras](#extras)\n    1. [Raycaster](#raycaster)\n    1. [Postprocessing](#postprocessing)\n        1. [Post Shaders](#post-shaders)\n    1. [Object Loader](#object-loader)\n    1. [BMFont](#bmfont)\n\n## Main\n\nUsage:\n\n`npm install vue-three-wrap --save`\n\nThen:\n\n```html\n\u003ctemplate\u003e\n    \u003cmain class=\"example\"\u003e\n        \u003c!-- vue-three-wrap will stretch to fit its container by default --\u003e\n        \u003cvue-three-wrap :start=\"start\" :update=\"update\" /\u003e\n    \u003c/main\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\n    import VueThreeWrap from 'vue-three-wrap'\n    import * as THREE from 'three'\n\n    // can be handy to store THREE objects in an unwatched object\n    const ref = {}\n\n    export default {\n        components: {\n            'vue-three-wrap': VueThreeWrap\n        },\n        methods: {\n            // called once when the scene is created\n            start({ scene, camera, renderer }) {\n                // example - add a cube to the scene\n                const geometry = new THREE.BoxGeometry()\n                const material = new THREE.MeshBasicMaterial({\n                    color: 0xff0000\n                })\n                ref.cube = new THREE.Mesh(geometry, material)\n                ref.cube.position.z = -4\n\n                scene.add(ref.cube)\n            },\n            // called once per frame\n            update({ scene, camera, renderer }) {\n                ref.cube.rotation.y -= 0.01\n            }\n        }\n    }\n\u003c/script\u003e\n```\n\n### Props\n\n| Name            | Type                                                                                     | Default                                              | Notes                                                                                                                                                    |\n| --------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| camera          | Object                                                                                   | `new THREE.PerspectiveCamera(75, 0.5625, 0.1, 1000)` | Main camera.                                                                                                                                             |\n| cameraType      | Object, Boolean, String                                                                  | `perspective`                                        | `perspective`, `orthographic`, or `ortho`. Creates the desired [camera](https://threejs.org/docs/index.html#api/en/cameras/Camera) as the scene default. |\n| fov             | Number, String                                                                           | `75`                                                 | Camera field of view.                                                                                                                                    |\n| height          | Number                                                                                   | -1                                                   | Height of the canvas. -1 to take up full height of container.                                                                                            |\n| injectShaders   | Boolean                                                                                  | `false`                                              | Whether or not to inject custom shaders. See [below](#shader-injection).                                                                                 |\n| rendererOptions | Object                                                                                   | {}                                                   | Object of [options](https://threejs.org/docs/#api/en/renderers/WebGLRenderer) to be passed directly to the WebGLRenderer.                                |\n| renderLoop      | Boolean                                                                                  | true                                                 | Whether or not to call `update` every frame.                                                                                                             |\n| renderType      | String                                                                                   | webgl                                                | `webgl` or `css`. Uses the [CSS3DRenderer](https://threejs.org/docs/#examples/renderers/CSS3DRenderer) if set to `css`. (See [below](#css-renderer))     |\n| start           | Function({ scene, camera, renderer, slot, elements, CSS, vertexShader, fragmentShader }) | null                                                 | Function to be called once at scene creation.                                                                                                            |\n| update          | Function({ scene, camera, renderer, slot, elements, CSS, vertexShader, fragmentShader }) | null                                                 | Function called once per frame.                                                                                                                          |\n| width           | Number                                                                                   | -1                                                   | Width of the canvas. -1 to take up full width of container.                                                                                              |\n\n### `start` and `update`\n\n`start` and `update` functions accept one object with the following parameters:\n\n```js\n{\n    // The THREE scene created by this VueThreeWrap\n    scene,\n        // The main camera\n        camera,\n        // The main renderer\n        renderer,\n        // The contents of the default slot\n        slot,\n        // An array of all valid elements in the default slot\n        elements,\n        // an object containing CSS renderer objects (see below)\n        CSS,\n        // the text of the first \u003cscript\u003e tag in the default slot whose type is set to \"shader/vertex\"\n        // (defaults to a standard vertex shader if none exists - see src/utils/shader-defaults.js)\n        vertexShader,\n        // the text of the first \u003cscript\u003e tag in the default slot whose type is set to \"shader/fragment\"\n        // (defaults to a pink fragment shader if none exists - see src/utils/shader-defaults.js)\n        fragmentShader\n}\n```\n\n### CSS Renderer\n\nYou can use THREE's CSS renderer with `vue-three-wrap`:\n\n```html\n\u003ctemplate\u003e\n    \u003cvue-three-wrap :start=\"start\" :update=\"update\" renderType=\"css\"\u003e\n        \u003ch2\u003eI'm an h2\u003c/h2\u003e\n        \u003cp\u003eAnd I'm a paragraph\u003c/p\u003e\n    \u003c/vue-three-wrap\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\n    const ref = {}\n    export default {\n        methods: {\n            start({ scene, camera, renderer, elements, CSS }) {\n                // `elements` is a list of valid elements in the default slot\n                // you'll need to manually create a new CSS3DObject for each separate element, then add it to the scene\n                ref.h2 = new CSS.CSS3DObject(elements[0])\n                ref.p = new CSS.CSS3DObject(elements[1])\n                scene.add(ref.h2)\n                scene.add(ref.p)\n\n                // you can also do something iterative like:\n                // elements.map(el =\u003e new CSS.CSS3DObject(el)).map(cssObj =\u003e scene.add(cssObj))\n\n                // some arbitrary scaling and positioning\n                // the important thing is that you can work with CSS3DObjects just like regular meshes\n                ref.h2.position.set(20, 0, 0)\n                ref.h2.lookAt(new THREE.Vector3(0, 20, 20))\n\n                ref.p.position.set(-20, -20, 0)\n                ref.p.lookAt(new THREE.Vector3(0, 0, 20))\n                camera.position.z = 150\n            },\n            update() {\n                ref.h2.rotation.z += 0.01\n            }\n        }\n    }\n\u003c/script\u003e\n```\n\nTo do so:\n\n1. Set the `renderType` prop to `css`.\n1. Use the `elements` argument in the `start` method to access elements in the default render slot.\n1. Create new CSS3DObjects using the `CSS` property passed to the `start` and `update` functions.\n\nOtherwise, it's just like working with a normal THREE.js scene, just with usable DOM objects.\n\n### Shader Injection\n\nSet the `inject-shaders` prop to `true` to inject some common [noise functions](https://github.com/ashima/webgl-noise). You can use THREE's `#include` convention. All return a value of -1 to 1.\n\n-   `float snoise(vec2)` - 2D simplex noise.\n-   `float cnoise(vec2)` - 2D Perlin noise.\n\nAn example fragment shader using 2D simplex noise:\n\n```html\n\u003cvue-three-wrap :inject-shaders=\"true\"\u003e\n    \u003cscript type=\"shader/fragment\"\u003e\n        #include \u003csnoise\u003e\n\n        varying vec2 vUv;\n        uniform float time;\n\n        void main() {\n            /* increase the viewing area (* 3) */\n            /* scale from -1 -\u003e 1 to 0 -\u003e 2 (+ 1) */\n            /* scale from 0 -\u003e 2 to 0 -\u003e 1 (/ 2) */\n            float noise = (snoise((vUv + time) * 3.) + 1.) / 2.;\n            vec4 dark = vec4(0., 0., 0., 1.);\n            vec4 light = vec4(1.);\n            gl_FragColor = mix(dark, light, noise);\n        }\n    \u003c/script\u003e\n\u003c/vue-three-wrap\u003e\n```\n\n**Note that comments in your custom shaders must use `/* this format */`, not `// this format`.**\n\n## Extras\n\n### Raycaster\n\nA class that wraps Three's [raycaster](https://threejs.org/docs/index.html#api/en/core/Raycaster).\n\nExample:\n\n```html\n\u003ctemplate\u003e\n    \u003cvue-three-wrap ref=\"threeWrap\" :start=\"start\" :update=\"update\" /\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\n    import Raycaster from 'vue-three-wrap/extras/raycaster'\n\n    const ref = {}\n\n    export default {\n        methods: {\n            start({ camera }) {\n                ref.raycaster = new Raycaster({\n                    el: this.$refs.threeWrap.$el,\n                    camera: camera\n                })\n\n                // (add your scene objects here)\n            },\n            update({ scene }) {\n                // cast against all objects in the scene\n                const intersects = ref.raycaster.intersectObjects(\n                    scene.children\n                )\n                // get objects from intersections\n                const intersectedObjects = intersects.map(i =\u003e i.object)\n                console.log(intersects, intersectedObjects)\n            }\n        }\n    }\n\u003c/script\u003e\n```\n\n### Constructor\n\nDefaults shown.\n\n```js\nnew Raycaster({\n    // the area to check on mouseover\n    el: document.querySelector('canvas'),\n\n    // the camera that will be doing the raycasting\n    camera: null,\n\n    // whether or not to print debug messages\n    debug: false,\n\n    // raycaster (optional - will create automatically if not specified)\n    raycaster: null\n})\n```\n\n### Properties\n\n| Name          | Type   | Notes                                                   |\n| ------------- | ------ | ------------------------------------------------------- |\n| interpolatedX | Number | The normalized relative mouse X position, from -1 to 1. |\n| interpolatedY | Number | The normalized relative mouse Y position, from -1 to 1. |\n| mouseX        | Number | The latest mouseX position relative to the container.   |\n| mouseY        | Number | The latest mouseY position relative to the container.   |\n\n### Methods\n\n| Name             | Arguments                                                         | Notes                                                                                                                                                                                              |\n| ---------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| init             | options (same as constructor)                                     | Initializes this raycaster. Same method as called by constructor.                                                                                                                                  |\n| updateMouse      | mouse event                                                       | Updates relative mouse coordinates. Called internally.                                                                                                                                             |\n| cast             | `{ coordinates: { x: Number, y: Number }, camera: THREE.Camera }` | Raycast and save the results internally. If `coordinates` are unspecified, uses the last coordinates set by `updateMouse`. If `camera` is unspecified, uses the camera added during instantiation. |\n| intersectObject  | (object, recursive, optionalTarget, coordinates, camera)          | Calls `cast()` with the given `coordinates` and `camera`, then runs [intersectObject](https://threejs.org/docs/index.html#api/en/core/Raycaster.intersectObject) with the first three arguments.   |\n| intersectObjects | (objects, recursive, optionalTarget, coordinates, camera)         | Calls `cast()` with the given `coordinates` and `camera`, then runs [intersectObjects](https://threejs.org/docs/index.html#api/en/core/Raycaster.intersectObjects) with the first three arguments. |\n| destroy          | None                                                              | Destroys the event listener created during `init`.                                                                                                                                                 |\n\n### Postprocessing\n\nYou can use the postprocessor from the [examples](https://threejs.org/examples/?q=post) very easily with the `custom-renderer` prop:\n\n```html\n\u003ctemplate\u003e\n    \u003cvue-three-wrap\n        :custom-renderer=\"composer\"\n        :start=\"start\"\n        :update=\"update\"\n    /\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\n    import * as THREE from 'three'\n    import QuickComposer from 'vue-three-wrap/extras/quick-composer'\n    import DotScreenShader from 'vue-three-wrap/shaders/DotScreenShader'\n    import RGBShiftShader from 'vue-three-wrap/shaders/RGBShiftShader'\n\n    const ref = {}\n\n    export default {\n        data() {\n            return {\n                composer: null\n            }\n        },\n        methods: {\n            start({ scene, camera, renderer }) {\n                // position camera\n                camera.position.z = 10\n\n                // add cube\n                const geo = new THREE.BoxGeometry()\n                const mat = new THREE.MeshLambertMaterial({ color: 0xffcccc })\n                ref.box = new THREE.Mesh(geo, mat)\n                scene.add(ref.box)\n\n                // add sun\n                const sun = new THREE.DirectionalLight()\n                sun.position.set(5, 5, 5)\n                scene.add(sun)\n\n                // build composer\n                this.composer = QuickComposer({\n                    scene,\n                    camera,\n                    renderer,\n                    passes: [DotScreenShader, RGBShiftShader]\n                })\n\n                // Set a uniform of a pass\n                // Note that passes are 1-indexed when using QuickComposer\n                this.composer.getPass(1).uniforms.scale.value = 4\n                // A quicker way to do the same thing:\n                this.composer.setUniform(1, 'scale', 4)\n            },\n            update() {\n                // rotate the box\n                ref.box.rotation.x += 0.002\n                ref.box.rotation.y -= 0.005\n\n                // move the box in a circle\n                const d = Date.now() * 0.0015\n                ref.box.position.set(Math.sin(d) * 2, Math.cos(d) * 2, 0)\n            }\n        }\n    }\n\u003c/script\u003e\n```\n\nTo use:\n\n1. Import `QuickComposer` from `vue-three-wrap/extras/quick-composer`.\n    1. If you want more control of your composer, you can also import `EffectComposer` from `vue-three-wrap/extras/effect-composer`.\n1. Set the `custom-renderer` prop in `vue-three-wrap` to an instance of the QuickComposer.\n1. Instantiate the QuickComposer with the following options as an object:\n\n    ```\n    {\n        // these three can just be passed from your start/update functions\n        scene,\n        camera,\n        renderer,\n\n        // an array of shader objects (see below)\n        passes: []\n    }\n    ```\n\n**TODO**: document EffectComposer and QuickComposer\n\n#### Post Shaders\n\n`vue-three-wrap` comes with some complete shaders in the form of JS objects:\n\n-   `DotScreenShader`\n-   `RGBShiftShader`\n\nYou can import any existing shader from `vue-three-wrap/shaders/YourDesiredShader`.\n\nYou can also create your own by making an object with `uniforms`, `vertexShader`, and `fragmentShader` properties:\n\n```\n// ExampleShader.js\nexport default {\n    uniforms: {\n        // Each uniform ust be an object with a `value` property\n        yourUniform: { value: 0}\n    },\n    vertexShader: 'A string containing your WebGL vertex shader',\n    fragmentShader: 'A string containing your WebGL fragment shader'\n}\n```\n\nYou can then use this shader as a pass in the QuickComposer or EffectComposer. Writing shaders is beyond the scope of this readme - take a look at [The Book of Shaders](https://thebookofshaders.com/) for more information.\n\n### Object Loader\n\nYou can import `.gltf` and `.glb` files, [the format that Three prefers](https://threejs.org/docs/#manual/en/introduction/Loading-3D-models), using the `load-gltf` extra.\n\n```html\n\u003ctemplate\u003e\n    \u003cvue-three-wrap class=\"object-loader\" :start=\"start\" /\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\n    // to use the loadObjects module:\n    import { loadObjects } from 'vue-three-wrap/extras/load-gltf/'\n    // to use the default full scene loader:\n    import loadScene from 'vue-three-wrap/extras/load-gltf'\n\n    export default {\n        methods: {\n            async start({ scene, camera, vertexShader, fragmentShader }) {\n                // you can load a full scene...\n                // const glb = await loadScene('/assets/scene.glb')\n                // scene.add(glb.scene)\n\n                // ...or individual objects\n                const objects = await loadObjects('/assets/scene.glb')\n                objects.forEach(obj =\u003e scene.add(obj))\n\n                // remember to add some lighting\n\n                // place and rotate the camera\n                camera.position.set(-4, 4, 4)\n                camera.lookAt(new THREE.Vector3(0, 0, 0))\n            }\n        }\n    }\n\u003c/script\u003e\n```\n\n### BMFont\n\n`vue-three-wrap` comes with methods to handle loading and displaying text with BMFonts. To use:\n\n1. Convert your font to a BMFont with a tool like [`msdf-bmfont`](https://github.com/Jam3/msdf-bmfont). Place the created `.fnt` and `.png` files in your project.\n1. Import the `bmfont` method from `vue-three-wrap/extras/bm-font`and use like this:\n\n```html\n\u003ctemplate\u003e\n    \u003cvue-three-wrap class=\"bmfont\" :start=\"start\" /\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\n    import bmFont from 'vue-three-wrap/extras/bm-font'\n\n    export default {\n        methods: {\n            async start({ scene }) {\n                // `result` is an object with properties { font, texture, geometry, mesh, material }\n                const result = await bmFont({\n                    // path to .fnt and .png files\n                    fnt: '/your-font-file.fnt',\n                    png: '/your-font-image.png',\n\n                    // the text you want to display\n                    text: 'Your text here!',\n\n                    // OPTIONAL: options to pass to material - see the MSDFShader method here:\n                    // https://tympanus.net/codrops/2019/10/10/create-text-in-three-js-with-three-bmfont-text/\n                    opts: {\n                        // fragmentShader: `void main() { ... }`,\n                        // vertexShader: `...`\n                        // etc\n                    }\n                })\n\n                // mesh will be very large by default, so we're moving it away from the camera here\n                // mesh is also instantiated upside-down, so the bmFont method rotates it 180deg on the X axis\n                scene.add(result.mesh)\n                result.mesh.position.z = -130\n            }\n        }\n    }\n\u003c/script\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsafrmo%2Fvue-three-wrap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsafrmo%2Fvue-three-wrap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsafrmo%2Fvue-three-wrap/lists"}