├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── assets
├── by-the-ocean
│ └── by-the-ocean.glb
├── cell
│ └── scene.glb
├── eiffel
│ ├── license.txt
│ ├── scene.bin
│ └── scene.gltf
├── icons
│ ├── in-out-arrow.svg
│ ├── left-arrow.svg
│ ├── left-mouse.svg
│ ├── lock.svg
│ ├── middle-mouse.svg
│ ├── mouse-wheel.svg
│ ├── move-arrows.svg
│ ├── pitch-yaw-arrow.svg
│ ├── roll.svg
│ └── yaw-arrow.svg
├── milk-delivery
│ └── milk-delivery.glb
├── starry-night
│ ├── CoarseBristles.png
│ └── starry-night.glb
└── t-rex
│ ├── license.txt
│ ├── scene.bin
│ ├── scene.gltf
│ └── textures
│ ├── body_baseColor.jpeg
│ ├── eyes_0_metallicRoughness.png
│ └── eyes_baseColor.jpeg
├── component-usage
├── adaptive-frame-rate.html
├── bricks
│ ├── colors.js
│ ├── falling.html
│ ├── flexible.html
│ ├── single-alt.html
│ ├── single.html
│ ├── snapping.html
│ ├── snapping.js
│ └── wall.html
├── connecting-line.html
├── cursor-tracker.html
├── dat-gui
│ └── torus.html
├── desktop-vr-controller.html
├── desktop-xr-hands
│ ├── aframe-example.html
│ └── message.html
├── dynamic-snap.html
├── entity-screen-position.html
├── frame-rate.html
├── graph.html
├── labels.html
├── low-cost-raycasting.html
├── mouse-manipulation.html
├── mouse-object-control.html
├── object-manipulation.html
├── polygon-wireframe.html
├── raycaster-thresholds.html
├── screen-position.html
├── stats-collector.html
├── stats-panel.html
└── window-3d
│ ├── by-the-ocean.html
│ ├── configure-example.js
│ ├── draggable-div.js
│ ├── hello-aframe.html
│ ├── index.html
│ ├── milk-delivery.html
│ ├── starry-night.html
│ └── styles.css
├── components
├── anchored
│ ├── README.md
│ ├── dist
│ │ ├── anchored.js
│ │ ├── anchored.min.js
│ │ └── anchored.min.js.LICENSE.txt
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── test
│ │ ├── index.html
│ │ └── reset.js
│ ├── webpack.config.js
│ └── webpack.prod.config.js
├── ball-blaster
│ ├── README.md
│ ├── image-20230701171702787.png
│ ├── index.js
│ ├── package.json
│ └── test
│ │ ├── ammo-blaster.html
│ │ ├── cannon-blaster.html
│ │ └── physx-blaster.html
├── bricks
│ ├── README.md
│ ├── image-20230318103822805.png
│ ├── image-20230318113905914.png
│ ├── image-20230418165028833.png
│ ├── index.js
│ ├── package.json
│ └── test
│ │ ├── basic-bricks.html
│ │ ├── brick-geometry.html
│ │ └── single-brick.html
├── connecting-line
│ ├── README.md
│ ├── index.js
│ ├── package.json
│ └── test
│ │ ├── event-updates.html
│ │ ├── length-factor.html
│ │ └── width.html
├── cursor-tracker
│ ├── README.md
│ ├── index.js
│ └── package.json
├── dat-gui
│ ├── README.md
│ ├── dist
│ │ ├── dat-gui.js
│ │ └── dat-gui.min.js
│ ├── image-20240304145551473.png
│ ├── image-20240304150412011.png
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── test
│ │ ├── bricks.html
│ │ └── multiple-unnamed.html
│ ├── webpack.config.js
│ └── webpack.prod.config.js
├── desktop-vr-controller
│ ├── .gitignore
│ ├── .npmignore
│ ├── README.md
│ ├── dist
│ │ ├── desktop-vr-controller.js
│ │ └── desktop-vr-controller.min.js
│ ├── image-20220802185450073.png
│ ├── image-20220802185543518.png
│ ├── image-20220802185741939.png
│ ├── image-20220802190100076.png
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── webpack.config.js
│ └── webpack.prod.config.js
├── desktop-xr-hands
│ ├── README.md
│ ├── dist
│ │ ├── desktop-xr-hands.js
│ │ ├── desktop-xr-hands.js.map
│ │ ├── desktop-xr-hands.min.js
│ │ └── desktop-xr-hands.min.js.map
│ ├── image-20230829170643885.png
│ ├── image-20230829170851279.png
│ ├── image-20230829175405101.png
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── desktop-xr-hands.js
│ │ └── hand-landmarker.js
│ ├── test
│ │ ├── dots.html
│ │ ├── mesh.html
│ │ └── wrist-twist.html
│ └── webpack.config.js
├── desktop-xr-plane
│ ├── README.md
│ ├── index.js
│ └── package.json
├── dynamic-snap
│ ├── README.md
│ ├── dist
│ │ ├── dynamic-snap.js
│ │ └── dynamic-snap.min.js
│ ├── image-20230409165520988.png
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── test
│ │ ├── snap-to-grid.js
│ │ ├── test1.html
│ │ ├── test2.html
│ │ └── test3.html
│ ├── webpack.config.js
│ └── webpack.prod.config.js
├── frame-rate
│ ├── README.md
│ ├── index.js
│ └── package.json
├── graph
│ ├── .gitignore
│ ├── README.md
│ ├── dist
│ │ ├── graph.js
│ │ └── graph.min.js
│ ├── image-20230318092246915.png
│ ├── image-20230318092739663.png
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ └── utils.js
│ ├── test
│ │ └── index.html
│ ├── webpack.config.js
│ └── webpack.prod.config.js
├── head-tracking
│ ├── README.md
│ ├── dist
│ │ ├── head-tracking.js
│ │ ├── head-tracking.js.map
│ │ ├── head-tracking.min.js
│ │ └── head-tracking.min.js.map
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── face-detector.js
│ │ └── head-tracker.js
│ ├── test
│ │ ├── index.html
│ │ ├── rgbe-loader.js
│ │ ├── window-camera.html
│ │ ├── window-camera.js
│ │ ├── window-camera2.html
│ │ └── window-camera3.html
│ └── webpack.config.js
├── hide-on-hover.js
├── label
│ ├── README.md
│ ├── image-20220811164727667.png
│ ├── image-20220811164814125.png
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ └── test
│ │ └── test-overwite.html
├── laser-manipulation
│ ├── .gitignore
│ ├── .npmignore
│ ├── README.md
│ ├── dist
│ │ ├── laser-manipulation.js
│ │ └── laser-manipulation.min.js
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── webpack.config.js
│ └── webpack.prod.config.js
├── low-cost-raycasting.js
├── mouse-manipulation
│ ├── .gitignore
│ ├── .npmignore
│ ├── README.md
│ ├── dist
│ │ ├── mouse-manipulation.js
│ │ └── mouse-manipulation.min.js
│ ├── image-20220812163558569.png
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── webpack.config.js
│ └── webpack.prod.config.js
├── object-parent
│ ├── README.md
│ ├── index.js
│ └── package.json
├── plug-socket
│ ├── README.md
│ ├── dist
│ │ ├── plug-socket.js
│ │ └── plug-socket.min.js
│ ├── image-20230409165520988.png
│ ├── image-20230410115732409.png
│ ├── image-20230410120556987.png
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── plug.js
│ │ ├── socket-fabric.js
│ │ ├── socket-system.js
│ │ └── socket.js
│ ├── test
│ │ ├── test1.html
│ │ ├── test10.html
│ │ ├── test11.html
│ │ ├── test12.html
│ │ ├── test13.html
│ │ ├── test14.html
│ │ ├── test2.html
│ │ ├── test3.html
│ │ ├── test4.html
│ │ ├── test5.html
│ │ ├── test6.html
│ │ ├── test7.html
│ │ ├── test8.html
│ │ ├── test9.html
│ │ ├── unit-tests.html
│ │ └── ut
│ │ │ ├── common.js
│ │ │ ├── ut-basic.js
│ │ │ ├── ut-events.js
│ │ │ └── ut-multi-plug.js
│ ├── webpack.config.js
│ └── webpack.prod.config.js
├── polygon-wireframe
│ ├── README.md
│ ├── image-20220816094651445.png
│ ├── index.js
│ ├── package.json
│ └── test
│ │ └── hidden-line-options.html
├── raycast-target
│ ├── README.md
│ ├── index.js
│ └── package.json
├── raycaster-thresholds
│ ├── README.md
│ ├── index.js
│ └── package.json
├── scale-on-hover.js
├── screen-position
│ ├── README.md
│ ├── index.js
│ └── package.json
├── stats-panel
│ ├── README.md
│ ├── image-20221106161718921.png
│ ├── index.js
│ └── package.json
├── thumbstick-states
│ ├── README.md
│ ├── index.js
│ └── package.json
├── window-3d
│ ├── README.md
│ └── index.js
└── xr-room-physics
│ ├── README.md
│ ├── dist
│ ├── xr-room-physics.js
│ ├── xr-room-physics.min.js
│ └── xr-room-physics.min.js.LICENSE.txt
│ ├── image-20230702084154726.png
│ ├── image-20230702090037281.png
│ ├── image-20230702091131736.png
│ ├── image-20230702092025851.png
│ ├── image-20230702092318339.png
│ ├── image-20230702100955317.png
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ ├── test
│ ├── ammo-desktop-room.html
│ ├── ammo-desktop-room2.html
│ ├── ammo-desktop-room3.html
│ ├── ammo-desktop-room4.html
│ ├── ammo-desktop-room5.html
│ ├── ammo-room.html
│ ├── ammo-shape-test.html
│ ├── cannon-desktop-room5.html
│ ├── cannon-room.html
│ ├── cannon-shape-test.html
│ ├── index.html
│ ├── physx-desktop-room5.html
│ ├── physx-room.html
│ ├── physx-shape-test.html
│ ├── test-geometries.js
│ └── toggle-debug.js
│ └── webpack.config.js
├── compositions
└── wrapped-present
│ ├── README.md
│ ├── assets
│ └── sample-image.png
│ ├── index.html
│ ├── lib
│ ├── FontLoader.js
│ └── TextGeometry.js
│ └── src
│ ├── apply-url-params.js
│ └── components.js
├── docs
└── utility-components.md
└── styles.css
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | **/node_modules/**
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 diarmidmackenzie
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/assets/by-the-ocean/by-the-ocean.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/assets/by-the-ocean/by-the-ocean.glb
--------------------------------------------------------------------------------
/assets/cell/scene.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/assets/cell/scene.glb
--------------------------------------------------------------------------------
/assets/eiffel/license.txt:
--------------------------------------------------------------------------------
1 | Model Information:
2 | * title: ( FREE ) La tour Eiffel
3 | * source: https://sketchfab.com/3d-models/free-la-tour-eiffel-8553f94d06e24cb4b0fde1080f281674
4 | * author: SDC (https://sketchfab.com/3Duae)
5 |
6 | Model License:
7 | * license type: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
8 | * requirements: Author must be credited. Commercial use is allowed.
9 |
10 | If you use this 3D model in your project be sure to copy paste this credit wherever you share it:
11 | This work is based on "( FREE ) La tour Eiffel" (https://sketchfab.com/3d-models/free-la-tour-eiffel-8553f94d06e24cb4b0fde1080f281674) by SDC (https://sketchfab.com/3Duae) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
--------------------------------------------------------------------------------
/assets/eiffel/scene.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/assets/eiffel/scene.bin
--------------------------------------------------------------------------------
/assets/icons/in-out-arrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
16 |
18 |
38 |
42 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/assets/icons/left-arrow.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/icons/left-mouse.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/assets/icons/lock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/icons/mouse-wheel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/icons/move-arrows.svg:
--------------------------------------------------------------------------------
1 | move-arrows
--------------------------------------------------------------------------------
/assets/icons/pitch-yaw-arrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
51 |
--------------------------------------------------------------------------------
/assets/icons/yaw-arrow.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/assets/milk-delivery/milk-delivery.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/assets/milk-delivery/milk-delivery.glb
--------------------------------------------------------------------------------
/assets/starry-night/CoarseBristles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/assets/starry-night/CoarseBristles.png
--------------------------------------------------------------------------------
/assets/starry-night/starry-night.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/assets/starry-night/starry-night.glb
--------------------------------------------------------------------------------
/assets/t-rex/license.txt:
--------------------------------------------------------------------------------
1 | Model Information:
2 | * title: Tyrannosaurus Rex
3 | * source: https://sketchfab.com/3d-models/tyrannosaurus-rex-9eade2f07a8d4ae1aac8f53e5a3d0a7a
4 | * author: AVINAS (https://sketchfab.com/AVINAS)
5 |
6 | Model License:
7 | * license type: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
8 | * requirements: Author must be credited. Commercial use is allowed.
9 |
10 | If you use this 3D model in your project be sure to copy paste this credit wherever you share it:
11 | This work is based on "Tyrannosaurus Rex" (https://sketchfab.com/3d-models/tyrannosaurus-rex-9eade2f07a8d4ae1aac8f53e5a3d0a7a) by AVINAS (https://sketchfab.com/AVINAS) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
--------------------------------------------------------------------------------
/assets/t-rex/scene.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/assets/t-rex/scene.bin
--------------------------------------------------------------------------------
/assets/t-rex/textures/body_baseColor.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/assets/t-rex/textures/body_baseColor.jpeg
--------------------------------------------------------------------------------
/assets/t-rex/textures/eyes_0_metallicRoughness.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/assets/t-rex/textures/eyes_0_metallicRoughness.png
--------------------------------------------------------------------------------
/assets/t-rex/textures/eyes_baseColor.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/assets/t-rex/textures/eyes_baseColor.jpeg
--------------------------------------------------------------------------------
/component-usage/bricks/colors.js:
--------------------------------------------------------------------------------
1 | COLORS = ['#05131D',
2 | '#0055BF',
3 | '#237841',
4 | '#008F9B',
5 | '#C91A09',
6 | '#C870A0',
7 | '#583927',
8 | '#9BA19D',
9 | '#6D6E5C',
10 | '#B4D2E3',
11 | '#4B9F4A',
12 | '#55A5AF',
13 | '#F2705E',
14 | '#FC97AC',
15 | '#F2CD37',
16 | '#FFFFFF',
17 | '#C2DAB8',
18 | '#FBE696',
19 | '#E4CD9E',
20 | '#C9CAE2',
21 | '#D4D5C9',
22 | '#81007B',
23 | '#2032B0',
24 | '#FE8A18',
25 | '#923978',
26 | '#BBE90B',
27 | '#958A73',
28 | '#E4ADC8',
29 | '#AC78BA',
30 | '#E1D5ED']
--------------------------------------------------------------------------------
/component-usage/bricks/falling.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
53 |
54 |
55 |
56 |
57 |
Building bricks with basic collision physics
58 |
59 |
62 | view code
63 |
64 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/component-usage/bricks/single-alt.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
A building base plate - use mouse to move it around
13 |
14 |
17 | view code
18 |
19 |
21 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/component-usage/bricks/single.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
Default building brick - use mouse to move it around
13 |
14 |
17 | view code
18 |
19 |
21 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/component-usage/connecting-line.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Connecting lines between entities.
11 |
Specific offsets relative to the center of the entity can be specified.
12 |
13 |
16 | view code
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/component-usage/cursor-tracker.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | The cursor-tracker component ensures that an entity positioned at the camera stays aligned in
12 | orientation with the cursor.
13 | The orientation of this entity is shown in this example by a sphere mesh rotated so that one pole lies directly ahead.
14 | This is intended for use with RayOrigin: mouse.
15 | An example application of this is the mouse-manipulation component, where it is used together with
16 | object-parent to move an entity around in line with the mouse pointer.
17 | Note that this text overlay blocks the cursor
18 |
19 |
21 |
24 |
25 |
26 |
28 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 | view code
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/component-usage/dat-gui/torus.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Controllable parameters for a-torus using aframe-dat-gui
12 |
13 |
16 | view code
17 |
18 |
19 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/component-usage/desktop-xr-hands/message.html:
--------------------------------------------------------------------------------
1 | Hand tracking relies on an API proposal and is not yet part of the WebXR standard. Browser support is experimental, it might vary across vendors and it might require enabling the feature manually in settings.
--------------------------------------------------------------------------------
/component-usage/entity-screen-position.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
40 |
41 |
42 |
43 | This example displays the x/y screen position (same co-ordinates as mouse system) of the center of the cube
44 | Drag with mouse to look around, and use WASD to move
45 | Values are not necessarily valid when the cube is off-screen
46 |
47 |
48 |
51 | view code
52 |
53 |
54 |
55 |
56 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/component-usage/labels.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Fixed size labels that face the camera. Left-mouse and WASD to move view.
11 |
Distanced labels maintain a fixed distance on camera from the point that they label.
12 |
13 |
16 | view code
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
29 |
30 |
31 |
35 |
36 |
39 |
40 |
41 |
42 |
43 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/component-usage/low-cost-raycasting.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
Low-cost raycasting. Still under development...
13 |
14 |
17 | view code
18 |
19 |
24 |
25 |
28 |
29 |
32 |
33 |
36 |
37 |
38 |
39 |
40 |
43 |
44 |
47 |
48 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/component-usage/raycaster-thresholds.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
By default, raycaster has a threshold of 1m for detecting intersection with a point or line.
27 |
The raycaster-thresholds component provide more flexibility for A-Frame applications.
28 |
33 |
Enable raycaster-thresholds
34 |
When raycaster-threshold is not used, raycaster default of 1m is used, and the box will be hidden whenever the cursor is anywhere near or inside it.
35 |
When raycaster-thresholds is specified, raycaster-thresholds default of 0.01m is used, and the box will be hidden only when the cursor is on the line
36 |
Although not shown in this basic example, the "line" and "points" properties of raycaster-threshold can be used to set any desired threshold for raycasting against lines and points.
37 |
38 |
39 |
42 | view code
43 |
44 |
45 |
56 |
57 |
--------------------------------------------------------------------------------
/component-usage/screen-position.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Screen positions of entities. Move using left mouse or WASD to observe changes.
11 |
Small squares are 2D square overlays that show the tracked 2D position of each element on the screen.
12 |
13 | Cube: Calculating...
14 |
15 |
16 | Sphere: Calculating...
17 |
18 |
19 | Cylinder: Calculating...
20 |
21 |
22 |
25 | view code
26 |
27 |
32 |
33 |
38 |
39 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
53 |
54 |
57 |
58 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/component-usage/stats-collector.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
23 |
24 |
25 |
26 |
Collect and process stats from a data source, output in the style of A-Frame stats
27 |
28 |
31 | view code
32 |
33 |
34 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/component-usage/window-3d/by-the-ocean.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
40 |
41 |
42 |
43 |
44 |
45 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/component-usage/window-3d/configure-example.js:
--------------------------------------------------------------------------------
1 |
2 | const DIORAMA_LIST = ["hello-aframe", "by-the-ocean", "starry-night", "milk-delivery"]
3 |
4 | AFRAME.registerComponent('configure-example', {
5 |
6 | schema: {
7 | diorama: {oneOf: DIORAMA_LIST,
8 | default: "by-the-ocean"},
9 | width: {default: 600 },
10 | height: {default: 400 },
11 | xSensitivity: {default: 1 },
12 | ySensitivity: {default: 1 },
13 | headTracking: {default: false},
14 | zSensitivity: {default: 3 },
15 | stabilizationFactor: {default: 0.9},
16 | moveSideToSide: {default: true},
17 | },
18 |
19 | init() {
20 | this.dioramas = {}
21 | DIORAMA_LIST.forEach((id) => {
22 | this.dioramas[id] = document.getElementById(`${id}-container`)
23 | })
24 |
25 | this.viewport = document.getElementById('viewport1')
26 |
27 | this.cameraEntity = document.getElementById('camera1')
28 | },
29 |
30 | update() {
31 |
32 | const { data } = this
33 | DIORAMA_LIST.forEach((id) => {
34 | this.dioramas[id].setAttribute("visible", "false")
35 | })
36 |
37 | this.dioramas[data.diorama].setAttribute("visible", "true")
38 |
39 | this.viewport.style.width = `${data.width}px`
40 | this.viewport.style.height = `${data.height}px`
41 |
42 | const {xSensitivity, ySensitivity, zSensitivity } = data
43 |
44 | this.cameraEntity.setAttribute("window-3d", { xSensitivity,
45 | ySensitivity,
46 | zSensitivity})
47 |
48 |
49 | if (this.data.headTracking) {
50 | const { stabilizationFactor } = data
51 | this.cameraEntity.setAttribute("face-detector", "")
52 | this.cameraEntity.setAttribute("head-tracker", { stabilizationFactor })
53 | this.cameraEntity.setAttribute("head-tracker", "defaultPosition: 0 0 0.75")
54 | }
55 | else {
56 | this.cameraEntity.removeAttribute("face-detector")
57 | this.cameraEntity.removeAttribute("head-tracker")
58 | }
59 | }
60 | })
--------------------------------------------------------------------------------
/component-usage/window-3d/draggable-div.js:
--------------------------------------------------------------------------------
1 | let divLeft = 200;
2 | let divTop = 100;
3 | let mouseOffsetX = 0;
4 | let mouseOffsetY = 0;
5 | let dragging = false
6 | let direction = 1;
7 |
8 | const onMouseMove = (e) => {
9 |
10 | if (!dragging) return
11 |
12 | divLeft = e.clientX - mouseOffsetX
13 | divTop = e.clientY - mouseOffsetY
14 | const div = document.getElementById('viewport1')
15 | div.style.left = `${divLeft}px`
16 | div.style.top = `${divTop}px`
17 | }
18 |
19 | const onMouseDown = (e) => {
20 | dragging = true
21 | mouseOffsetX = e.offsetX;
22 | mouseOffsetY = e.offsetY;
23 | }
24 |
25 | const onMouseUp = (e) => {
26 | dragging = false
27 | const div = document.getElementById('viewport1')
28 | const rect = div.getBoundingClientRect()
29 | divLeft = rect.left
30 | divTop = rect.top
31 | }
32 |
33 | document.addEventListener('DOMContentLoaded', () => {
34 | const div = document.getElementById('viewport1')
35 | div.addEventListener("mousedown", onMouseDown)
36 | document.addEventListener("mouseup", onMouseUp)
37 | document.addEventListener("mousemove", onMouseMove)
38 | })
39 |
40 | setInterval(() => {
41 |
42 | config = document.getElementById('Configuration')?.components["configure-example"]?.data
43 |
44 | if (!config?.moveSideToSide) return
45 |
46 | const div = document.getElementById('viewport1')
47 | if (!dragging) {
48 | const rect = div.getBoundingClientRect()
49 |
50 | const hitLeft = (rect.left < 5)
51 | const hitRight = (rect.right > window.innerWidth - 5)
52 | if (hitLeft) {
53 | direction = 1
54 | }
55 | if (hitRight) {
56 | direction = -1
57 | }
58 |
59 | if (!hitLeft || !hitRight) {
60 | divLeft += (direction * 4)
61 | div.style.left = `${divLeft}px`
62 | }
63 | }
64 | }, 40)
65 |
--------------------------------------------------------------------------------
/component-usage/window-3d/hello-aframe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
43 |
44 |
45 |
46 |
47 |
48 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/component-usage/window-3d/milk-delivery.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/component-usage/window-3d/starry-night.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
40 |
41 |
42 |
43 |
44 |
45 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/component-usage/window-3d/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: grey;
3 | }
4 |
5 | video {
6 | visibility: hidden
7 | }
8 |
9 | #viewport1 {
10 | position: absolute;
11 | top: 100px;
12 | left: 200px;
13 | width: 600px;
14 | height:400px;
15 | margin: 10px;
16 | border-radius: 10px;
17 | border-width: 10px;
18 | border-color: #113;
19 | border-style: solid;
20 | box-shadow: inset 0px 0px 5px 2px #113;
21 | }
22 |
23 | #viewport-inner {
24 | width: 100%;
25 | height: 100%;
26 | }
27 |
28 | a {
29 | position: absolute;
30 | z-index: 10;
31 | bottom: 10px;
32 | left: 10px;
33 | }
--------------------------------------------------------------------------------
/components/anchored/dist/anchored.min.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /**
2 | * @license
3 | * Copyright 2010-2023 Three.js Authors
4 | * SPDX-License-Identifier: MIT
5 | */
6 |
--------------------------------------------------------------------------------
/components/anchored/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-anchored",
3 | "version": "0.0.1",
4 | "description": "Anchor A-Frame scene",
5 | "main": "index.js",
6 | "scripts": {
7 | "dist": "npm run dist:dev && npm run dist:prod",
8 | "dist:dev": "webpack --config webpack.config.js",
9 | "dist:prod": "webpack --config webpack.prod.config.js",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "keywords": [
13 | "A-Frame",
14 | "AR",
15 | "anchor",
16 | "WebXR"
17 | ],
18 | "author": "Diarmid Mackenzie",
19 | "license": "MIT",
20 | "dependencies": {
21 | "ratk": "^0.2.1"
22 | },
23 | "devDependencies": {
24 | "webpack": "^5.75.0",
25 | "webpack-cli": "^5.1.4"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/components/anchored/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Anchored scene. Always anchored to a fixed position in world space.
12 |
Press A to toggle anchoring on/off.
13 |
Hold down oculus button to reset scene origin.
14 |
15 |
18 | view code
19 |
20 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/components/anchored/test/reset.js:
--------------------------------------------------------------------------------
1 | AFRAME.registerComponent('toggle-anchored', {
2 |
3 | schema: {
4 | anchoredEl: { type: 'selector', default: '[anchored]' }
5 | },
6 |
7 | init() {
8 | this.toggleAnchored = this.toggleAnchored.bind(this)
9 | this.el.addEventListener('abuttondown', this.toggleAnchored)
10 | this.anchored = true
11 |
12 | },
13 |
14 | toggleAnchored() {
15 |
16 | const el = this.data.anchoredEl
17 | const anchoredComponent = el.components['anchored']
18 | this.anchored = !this.anchored
19 |
20 | if (this.anchored) {
21 | anchoredComponent.reAnchor()
22 | }
23 | else {
24 | anchoredComponent.unAnchor(false)
25 | }
26 |
27 | const plane = el.querySelector('a-plane')
28 | const color = this.anchored ? "#7BC8A4" : "white"
29 | plane.setAttribute('color', color)
30 | }
31 | })
32 |
--------------------------------------------------------------------------------
/components/anchored/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Webpack uses this to work with directories
2 | const path = require('path');
3 |
4 | // This is the main configuration object.
5 | // Here, you write different options and tell Webpack what to do
6 | module.exports = {
7 |
8 | // Path to your entry point. From this file Webpack will begin its work
9 | entry: './index.js',
10 |
11 | // Path and filename of your result bundle.
12 | // Webpack will bundle all JavaScript into this file
13 | output: {
14 | path: path.resolve(__dirname, 'dist'),
15 | publicPath: '',
16 | filename: 'anchored.js'
17 | },
18 |
19 | resolve: {
20 | fallback: {
21 | "fs": false,
22 | "path": false
23 | },
24 | },
25 |
26 | // Default mode for Webpack is production.
27 | // Depending on mode Webpack will apply different things
28 | // on the final bundle. For now, we don't need production's JavaScript
29 | // minifying and other things, so let's set mode to development
30 | mode: 'development'
31 | };
--------------------------------------------------------------------------------
/components/anchored/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var merge = require('webpack-merge').merge;
3 | var commonConfiguration = require('./webpack.config.js');
4 |
5 | module.exports = merge(commonConfiguration, {
6 | output: {
7 | path: path.resolve(__dirname, 'dist'),
8 | publicPath: '/dist/',
9 | filename: 'anchored.min.js'
10 | },
11 | mode: 'production'
12 | });
--------------------------------------------------------------------------------
/components/ball-blaster/image-20230701171702787.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/ball-blaster/image-20230701171702787.png
--------------------------------------------------------------------------------
/components/ball-blaster/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-ball-blaster",
3 | "version": "0.0.1",
4 | "description": "Simple blaster that shoots balls, for A-Frame",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "Diarmid Mackenzie",
10 | "license": "MIT"
11 | }
12 |
--------------------------------------------------------------------------------
/components/ball-blaster/test/ammo-blaster.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Ball Blaster in Ammo Physics Engine. Press any key to shoot.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Ball blaster with Ammo Physics. Left Blaster is directly in the scene. Press space to shoot.
17 |
Right blaster is a child of the right hand - only visible when in VR. Right trigger to shoot.
18 |
19 |
22 | view code
23 |
24 |
25 |
26 |
27 |
28 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/components/ball-blaster/test/cannon-blaster.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Ball Blaster in Cannon Physics Engine. Press any key to shoot.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Ball blaster with Cannon Physics. Left Blaster is directly in the scene. Press space to shoot.
16 |
Right blaster is a child of the right hand - only visible when in VR. Right trigger to shoot.
17 |
18 |
21 | view code
22 |
23 |
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/components/ball-blaster/test/physx-blaster.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Ball Blaster in PhysX Physics Engine. Press any key to shoot.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Ball blaster with PhysX Physics. Left Blaster is directly in the scene. Press space to shoot.
16 |
Right blaster is a child of the right hand - only visible when in VR. Right trigger to shoot.
17 |
18 |
21 | view code
22 |
23 |
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/components/bricks/image-20230318103822805.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/bricks/image-20230318103822805.png
--------------------------------------------------------------------------------
/components/bricks/image-20230318113905914.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/bricks/image-20230318113905914.png
--------------------------------------------------------------------------------
/components/bricks/image-20230418165028833.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/bricks/image-20230418165028833.png
--------------------------------------------------------------------------------
/components/bricks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-bricks",
3 | "version": "0.0.1",
4 | "description": "Building Bricks for A-Frame",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "A-Frame",
11 | "bricks",
12 | "building"
13 | ],
14 | "author": "Diarmid Mackenzie",
15 | "license": "MIT"
16 | }
17 |
--------------------------------------------------------------------------------
/components/bricks/test/basic-bricks.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 |
15 |
16 |
17 |
Basic selection of bricks
18 |
19 |
22 | view code
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/components/bricks/test/brick-geometry.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Basic brick geometry
11 |
12 |
15 | view code
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/components/bricks/test/single-brick.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Single brick, showing underside
11 |
12 |
15 | view code
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/components/connecting-line/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-connecting-line",
3 | "version": "0.3.1",
4 | "description": "Uses the A-Frame \"line\" component to draw a line between points on two entities.",
5 | "main": "index.js",
6 | "directories": {
7 | "example": "examples"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/connecting-line"
15 | },
16 | "keywords": [
17 | "A-Frame",
18 | "line"
19 | ],
20 | "bugs": {
21 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
22 | },
23 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/connecting-line#readme",
24 | "author": "Diarmid Mackenzie",
25 | "license": "MIT"
26 | }
27 |
--------------------------------------------------------------------------------
/components/cursor-tracker/README.md:
--------------------------------------------------------------------------------
1 | # cursor-tracker
2 |
3 | Set on an entity to track the orientation of the cursor's ray.
4 |
5 | Typically set on a entity that is a child of the camera that the cursor uses. This entity will then always point towards the cursor/mouse pointer.
6 |
7 |
8 |
9 | ## Schema
10 |
11 | | Property | Description | Default |
12 | | -------- | --------------------------------------- | ------- |
13 | | cursor | selector for the cursor entity to track | #cursor |
14 |
15 |
16 |
17 | ## Installation
18 |
19 | ```
20 |
21 | ```
22 |
23 | Or via [npm](https://www.npmjs.com/package/aframe-cursor-tracker)
24 |
25 | ```
26 | npm install aframe-cursor-tracker
27 | ```
28 |
29 |
30 | ## Examples
31 |
32 | [cursor-tracker.html](https://diarmidmackenzie.github.io/aframe-components/component-usage/cursor-tracker.html)
33 |
34 | Also Used by `mouse-manipulation` component to keep grabbed entities aligned with the mouse pointer.
35 |
36 | ## Code
37 |
38 | [cursor-tracker](https://github.com/diarmidmackenzie/aframe-components/blob/main/components/cursor-tracker/index.js)
--------------------------------------------------------------------------------
/components/cursor-tracker/index.js:
--------------------------------------------------------------------------------
1 | // Set on an entity to track the orientation of the cursor's ray.
2 | // Typically set on a entity that is a child of the camera that the cursor uses.
3 | AFRAME.registerComponent('cursor-tracker', {
4 |
5 | schema: {
6 | cursor: {type: 'selector', default: "#cursor"},
7 | },
8 |
9 | init() {
10 | this.cursor = this.data.cursor
11 | this.raycaster = this.cursor.components['raycaster'].raycaster
12 | this.forward = new THREE.Vector3(0, 0, -1)
13 | this.localRayVector = new THREE.Vector3();
14 | },
15 |
16 | tick() {
17 |
18 | // Get ray direction vector in the space of this object.
19 | this.el.object3D.getWorldPosition(this.localRayVector)
20 | this.localRayVector.add(this.raycaster.ray.direction)
21 | this.el.object3D.parent.worldToLocal(this.localRayVector)
22 | this.localRayVector.normalize()
23 | this.el.object3D.quaternion.setFromUnitVectors(this.forward, this.localRayVector)
24 | }
25 | });
26 |
--------------------------------------------------------------------------------
/components/cursor-tracker/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-cursor-tracker",
3 | "version": "0.1.0",
4 | "description": "Set on an entity to track the orientation of the cursor's ray.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/cursor-tracker"
12 | },
13 | "keywords": [
14 | "A-Frame",
15 | "Cursor"
16 | ],
17 | "bugs": {
18 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
19 | },
20 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/cursor-tracker#readme",
21 | "author": "Diarmid Mackenzie",
22 | "license": "MIT"
23 | }
24 |
--------------------------------------------------------------------------------
/components/dat-gui/image-20240304145551473.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/dat-gui/image-20240304145551473.png
--------------------------------------------------------------------------------
/components/dat-gui/image-20240304150412011.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/dat-gui/image-20240304150412011.png
--------------------------------------------------------------------------------
/components/dat-gui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-dat-gui",
3 | "version": "0.0.3",
4 | "description": "Dataarts dat.gui for A-Frame components",
5 | "main": "index.js",
6 | "scripts": {
7 | "dist": "npm run dist:dev && npm run dist:prod",
8 | "dist:dev": "webpack --config webpack.config.js",
9 | "dist:prod": "webpack --config webpack.prod.config.js",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "keywords": [
13 | "A-Frame",
14 | "dat.gui",
15 | "dat",
16 | "gui",
17 | "aframe"
18 | ],
19 | "author": "Diarmid Mackenzie",
20 | "license": "MIT",
21 | "devDependencies": {
22 | "webpack": "^5.75.0",
23 | "webpack-cli": "^5.0.1"
24 | },
25 | "dependencies": {
26 | "dat.gui": "^0.7.9"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/components/dat-gui/test/bricks.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
30 |
31 |
32 |
33 |
Basic dat.gui example
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/components/dat-gui/test/multiple-unnamed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
23 |
24 |
25 |
26 |
dat.gui example with multiple unnamed entities
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/components/dat-gui/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Webpack uses this to work with directories
2 | const path = require('path');
3 |
4 | // This is the main configuration object.
5 | // Here, you write different options and tell Webpack what to do
6 | module.exports = {
7 |
8 | // Path to your entry point. From this file Webpack will begin its work
9 | entry: './index.js',
10 |
11 | // Path and filename of your result bundle.
12 | // Webpack will bundle all JavaScript into this file
13 | output: {
14 | path: path.resolve(__dirname, 'dist'),
15 | publicPath: '',
16 | filename: 'dat-gui.js'
17 | },
18 |
19 | resolve: {
20 | fallback: {
21 | "fs": false,
22 | "path": false
23 | },
24 | },
25 |
26 | // Default mode for Webpack is production.
27 | // Depending on mode Webpack will apply different things
28 | // on the final bundle. For now, we don't need production's JavaScript
29 | // minifying and other things, so let's set mode to development
30 | mode: 'development'
31 | };
--------------------------------------------------------------------------------
/components/dat-gui/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var merge = require('webpack-merge').merge;
3 | var commonConfiguration = require('./webpack.config.js');
4 |
5 | module.exports = merge(commonConfiguration, {
6 | output: {
7 | path: path.resolve(__dirname, 'dist'),
8 | publicPath: '/dist/',
9 | filename: 'dat-gui.min.js'
10 | },
11 | mode: 'production'
12 | });
--------------------------------------------------------------------------------
/components/desktop-vr-controller/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/components/desktop-vr-controller/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
3 |
--------------------------------------------------------------------------------
/components/desktop-vr-controller/image-20220802185450073.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/desktop-vr-controller/image-20220802185450073.png
--------------------------------------------------------------------------------
/components/desktop-vr-controller/image-20220802185543518.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/desktop-vr-controller/image-20220802185543518.png
--------------------------------------------------------------------------------
/components/desktop-vr-controller/image-20220802185741939.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/desktop-vr-controller/image-20220802185741939.png
--------------------------------------------------------------------------------
/components/desktop-vr-controller/image-20220802190100076.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/desktop-vr-controller/image-20220802190100076.png
--------------------------------------------------------------------------------
/components/desktop-vr-controller/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-desktop-vr-controller",
3 | "version": "0.1.3",
4 | "description": "Simulates a VR controller on the desktop, controllable using mouse & keyboard.",
5 | "main": "index.js",
6 | "scripts": {
7 | "dist": "npm run dist:dev && npm run dist:prod",
8 | "dist:dev": "webpack --config webpack.config.js",
9 | "dist:prod": "webpack --config webpack.prod.config.js",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/desktop-vr-controller"
15 | },
16 | "keywords": [
17 | "A-Frame",
18 | "Controller",
19 | "6DoF",
20 | "Keyboard",
21 | "Mouse",
22 | "Desktop"
23 | ],
24 | "bugs": {
25 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
26 | },
27 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/desktop-vr-controller#readme",
28 | "author": "Diarmid Mackenzie",
29 | "license": "MIT",
30 | "devDependencies": {
31 | "webpack": "^5.75.0",
32 | "webpack-cli": "^5.0.1"
33 | },
34 | "dependencies": {
35 | "aframe-connecting-line": "^0.1.0",
36 | "aframe-label": "^0.1.2",
37 | "aframe-mouse-manipulation": "^0.1.0",
38 | "aframe-raycaster-thresholds": "^0.1.0",
39 | "aframe-screen-display": "^0.1.1"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/components/desktop-vr-controller/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Webpack uses this to work with directories
2 | const path = require('path');
3 |
4 | // This is the main configuration object.
5 | // Here, you write different options and tell Webpack what to do
6 | module.exports = {
7 |
8 | // Path to your entry point. From this file Webpack will begin its work
9 | entry: './index.js',
10 |
11 | // Path and filename of your result bundle.
12 | // Webpack will bundle all JavaScript into this file
13 | output: {
14 | path: path.resolve(__dirname, 'dist'),
15 | publicPath: '',
16 | filename: 'desktop-vr-controller.js'
17 | },
18 |
19 | resolve: {
20 | fallback: {
21 | "fs": false,
22 | "path": false
23 | },
24 | },
25 |
26 | // Default mode for Webpack is production.
27 | // Depending on mode Webpack will apply different things
28 | // on the final bundle. For now, we don't need production's JavaScript
29 | // minifying and other things, so let's set mode to development
30 | mode: 'development'
31 | };
--------------------------------------------------------------------------------
/components/desktop-vr-controller/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var merge = require('webpack-merge').merge;
3 | var commonConfiguration = require('./webpack.config.js');
4 |
5 | module.exports = merge(commonConfiguration, {
6 | output: {
7 | path: path.resolve(__dirname, 'dist'),
8 | publicPath: '/dist/',
9 | filename: 'desktop-vr-controller.min.js'
10 | },
11 | mode: 'production'
12 | });
--------------------------------------------------------------------------------
/components/desktop-xr-hands/image-20230829170643885.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/desktop-xr-hands/image-20230829170643885.png
--------------------------------------------------------------------------------
/components/desktop-xr-hands/image-20230829170851279.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/desktop-xr-hands/image-20230829170851279.png
--------------------------------------------------------------------------------
/components/desktop-xr-hands/image-20230829175405101.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/desktop-xr-hands/image-20230829175405101.png
--------------------------------------------------------------------------------
/components/desktop-xr-hands/index.js:
--------------------------------------------------------------------------------
1 | require('./src/hand-landmarker.js')
2 | require('./src/desktop-xr-hands.js')
3 |
--------------------------------------------------------------------------------
/components/desktop-xr-hands/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-desktop-xr-hands",
3 | "version": "0.0.4",
4 | "description": "Desktop simulation of WebXR Hand Tracking using Mediapipe",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "npm run dist",
8 | "deploy": "npm run build && netlify deploy --prod --dir=.",
9 | "dist": "npm run dist:min && npm run dist:max",
10 | "dist:max": "webpack",
11 | "dist:min": "cross-env NODE_ENV=production webpack",
12 | "prepublish": "npm run dist",
13 | "start": "cross-env webpack serve"
14 | },
15 | "keywords": [
16 | "aframe",
17 | "xr",
18 | "hand tracking"
19 | ],
20 | "author": "Diarmid Mackenzie",
21 | "license": "MIT",
22 | "dependencies": {
23 | "@mediapipe/drawing_utils": "^0.3.1675466124",
24 | "@mediapipe/tasks-vision": "^0.10.0",
25 | "aframe-screen-display": "^0.1.2"
26 | },
27 | "devDependencies": {
28 | "cross-env": "^7.0.3",
29 | "webpack": "^5.75.0",
30 | "webpack-cli": "^5.0.1",
31 | "webpack-dev-server": "^4.15.1"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/components/desktop-xr-hands/test/dots.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Desktop simulation of WebXR Hand Tracking using Mediapipe.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Desktop simulation of WebXR Hand Tracking using Mediapipe.
12 |
Left Hand Red, Right Hand Green.
13 |
Enter full screen to enable hand tracking via webcam.
14 |
15 |
18 | view code
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/components/desktop-xr-hands/test/mesh.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Desktop simulation of WebXR Hand Tracking using Mediapipe.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Desktop simulation of WebXR Hand Tracking using Mediapipe.
12 |
Left Hand Red, Right Hand Green.
13 |
Enter full screen to enable hand tracking via webcam.
14 |
15 |
18 | view code
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/components/desktop-xr-hands/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | output: {
6 | libraryTarget: 'umd',
7 | path: path.resolve(__dirname, 'dist'),
8 | publicPath: '/dist/',
9 | filename:
10 | process.env.NODE_ENV === 'production'
11 | ? 'desktop-xr-hands.min.js'
12 | : 'desktop-xr-hands.js'
13 | },
14 | externals: {
15 | // Stubs out `import ... from 'three'` so it returns `import ... from window.THREE` effectively using THREE global variable that is defined by AFRAME.
16 | three: 'THREE'
17 | },
18 | devtool: 'source-map',
19 | mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
20 | devServer: {
21 | port: process.env.PORT || 5000,
22 | hot: false,
23 | liveReload: true,
24 | server: {
25 | type: 'https'
26 | },
27 | static: {
28 | directory: path.resolve(__dirname + '../../..')
29 | }
30 | },
31 | resolve: {
32 | alias: {
33 | three: 'super-three'
34 | }
35 | }
36 | };
--------------------------------------------------------------------------------
/components/desktop-xr-plane/README.md:
--------------------------------------------------------------------------------
1 | # desktop-xr-plane
2 |
3 | ## Overview
4 |
5 | A component to simulate WebXR XRPlanes, while running on a desktop system
6 |
7 | ## Schema
8 |
9 | This component has no schema. Simulated planes are configured via the plane geometry configured on the same element.
10 |
11 | ## Usage
12 |
13 | Configure an `a-plane` (or other element with a `plane` geometry) with the desired position, size, rotation and appearance (can be invisible if desired)
14 |
15 | Then add the `desktop-xr-plane`component
16 |
17 | ```
18 |
25 |
26 | ```
27 |
28 |
29 |
30 | ## Limitations
31 |
32 | Does not support the `scale` attribute on the element - scale is assumed to be `1 1 1`
33 |
34 | Only supports rectangles. The WebXR standard supports XRPlanes that are arbitrary polygons, so this is a limitation vs. the WebXR standard. However note that as of July 2023, the Meta Quest room setup process always generates rectangles (even for the ceiling and floor of a non-rectangular room). So it's possible to simulate all XRPlanes that can be generated by Meta Quest room setup.
35 |
36 |
37 |
38 | ## Installation
39 |
40 | Via CDN
41 | ```
42 |
43 | ```
44 |
45 | Or via [npm](https://www.npmjs.com/package/aframe-polygon-wireframe)
46 |
47 | ```
48 | npm install aframe-desktop-xr-plane
49 | ```
50 |
51 |
52 |
53 | ## Examples
54 |
55 | This component is used in tests for the `xr-room-physics` component, for example:
56 |
57 | [ammo-desktop-room5.html](https://diarmidmackenzie.github.io/aframe-components/components/xr-room-physics/test/ammo-desktop-room5.html)
58 |
59 |
60 |
61 | ## Code
62 |
63 | [desktop-xr--plane](https://github.com/diarmidmackenzie/aframe-components/blob/main/components/desktop-xr-plane/index.js)
64 |
65 |
--------------------------------------------------------------------------------
/components/desktop-xr-plane/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-desktop-xr-plane",
3 | "version": "0.0.1",
4 | "description": "Simulation of XR Planes on Desktop, for A-Frame",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "XRPlane",
11 | "A-Frame"
12 | ],
13 | "author": "Diarmid Mackenzie",
14 | "license": "MIT"
15 | }
16 |
--------------------------------------------------------------------------------
/components/dynamic-snap/image-20230409165520988.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/dynamic-snap/image-20230409165520988.png
--------------------------------------------------------------------------------
/components/dynamic-snap/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-dynamic-snap",
3 | "version": "0.0.1",
4 | "description": "Dynamic snap-to-position for A-Frame",
5 | "main": "index.js",
6 | "scripts": {
7 | "dist": "npm run dist:dev && npm run dist:prod",
8 | "dist:dev": "webpack --config webpack.config.js",
9 | "dist:prod": "webpack --config webpack.prod.config.js",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "keywords": [
13 | "aframe",
14 | "snap",
15 | "dynamic",
16 | "position"
17 | ],
18 | "author": "Diarmid Mackenzie",
19 | "license": "MIT",
20 | "dependencies": {
21 | "aframe-polygon-wireframe": "^0.3.0"
22 | },
23 | "devDependencies": {
24 | "webpack": "^5.75.0",
25 | "webpack-cli": "^5.0.1"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/components/dynamic-snap/test/snap-to-grid.js:
--------------------------------------------------------------------------------
1 | // Snap to grid component for use with dynamic-snap component.
2 | AFRAME.registerComponent('snap-to-grid', {
3 | dependencies: ['position', 'rotation'],
4 |
5 | schema: {
6 | offset: {type: 'vec3', default: {x: 0, y: 0, z: 0}},
7 | snap: {type: 'vec3', default: {x: 0.5, y: 0.5, z: 0.5}}
8 | },
9 |
10 | init() {
11 |
12 | this.transform = new THREE.Object3D()
13 | this.eventData = {worldTransform: this.transform}
14 |
15 | this.axis = new THREE.Vector3()
16 | },
17 |
18 | tick() {
19 |
20 | const data = this.data;
21 | const transform = this.transform
22 |
23 | // get world transform of entity
24 | transform.position.set(0, 0, 0)
25 | transform.quaternion.identity()
26 | transform.scale.set(1, 1, 1)
27 | this.el.object3D.add(transform)
28 | this.el.sceneEl.object3D.attach(transform)
29 |
30 | // snap to position grid
31 | const pos = this.transform.position
32 | pos.x = Math.floor((pos.x + data.snap.x / 2) / data.snap.x) * data.snap.x + data.offset.x;
33 | pos.y = Math.floor((pos.y + data.snap.y / 2) / data.snap.y) * data.snap.y + data.offset.y;
34 | pos.z = Math.floor((pos.z + data.snap.z / 2) / data.snap.z) * data.snap.z + data.offset.z;
35 |
36 | // snap to 90 degree rotation
37 | // do this by converting to axis / angle as described here, then controlling the axis and angle.
38 | // https://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
39 | const quat = transform.quaternion
40 | quat.normalize()
41 | const s = Math.sqrt(1-quat.w*quat.w)
42 | if (s < 0.01) {
43 | quat.identity()
44 | }
45 | else {
46 | let x = quat.x
47 | let y = quat.y
48 | let z = quat.z
49 |
50 | if (Math.abs(x) >= Math.abs(y) && Math.abs(x) >= Math.abs(z)) {
51 | x = Math.sign(x)
52 | y = 0
53 | z = 0
54 | }
55 | else if (Math.abs(y) >= Math.abs(x) && Math.abs(y) >= Math.abs(z)) {
56 | x = 0
57 | y = Math.sign(y)
58 | z = 0
59 | }
60 | else {
61 | x = 0
62 | y = 0
63 | z = Math.sign(z)
64 | }
65 |
66 | this.axis.set(x, y, z)
67 |
68 | let angle = 2 * Math.acos(quat.w)
69 | const rotationSnap = Math.PI / 2
70 | angle = Math.floor(angle / rotationSnap) * rotationSnap
71 |
72 | quat.setFromAxisAngle(this.axis, angle)
73 | }
74 |
75 | this.el.emit('snapStart', this.eventData)
76 | },
77 | });
--------------------------------------------------------------------------------
/components/dynamic-snap/test/test1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
Dynamic snap to grid
13 |
Red Cone has transparent rendering for snap position, and wireframe rendering for precise position.
14 |
Blue Torus has transparent rendering for snap position, and object rendering for precise position (default).
15 |
16 |
19 | view code
20 |
21 |
23 |
27 |
28 |
29 |
36 |
37 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/components/dynamic-snap/test/test3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Dynamic snap to grid
15 |
Transparent rendering for precise position, wireframe rendering for snap position
16 |
17 |
20 | view code
21 |
22 |
24 |
28 |
29 |
30 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/components/dynamic-snap/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Webpack uses this to work with directories
2 | const path = require('path');
3 |
4 | // This is the main configuration object.
5 | // Here, you write different options and tell Webpack what to do
6 | module.exports = {
7 |
8 | // Path to your entry point. From this file Webpack will begin its work
9 | entry: './index.js',
10 |
11 | // Path and filename of your result bundle.
12 | // Webpack will bundle all JavaScript into this file
13 | output: {
14 | path: path.resolve(__dirname, 'dist'),
15 | publicPath: '',
16 | filename: 'dynamic-snap.js'
17 | },
18 |
19 | resolve: {
20 | fallback: {
21 | "fs": false,
22 | "path": false
23 | },
24 | },
25 |
26 | // Default mode for Webpack is production.
27 | // Depending on mode Webpack will apply different things
28 | // on the final bundle. For now, we don't need production's JavaScript
29 | // minifying and other things, so let's set mode to development
30 | mode: 'development'
31 | };
--------------------------------------------------------------------------------
/components/dynamic-snap/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var merge = require('webpack-merge').merge;
3 | var commonConfiguration = require('./webpack.config.js');
4 |
5 | module.exports = merge(commonConfiguration, {
6 | output: {
7 | path: path.resolve(__dirname, 'dist'),
8 | publicPath: '/dist/',
9 | filename: 'dynamic-snap.min.js'
10 | },
11 | mode: 'production'
12 | });
--------------------------------------------------------------------------------
/components/frame-rate/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-frame-rate",
3 | "version": "0.1.0",
4 | "description": "Adjust WebXR frame rate for A-Frame applications",
5 | "main": "index.js",
6 | "directories": {
7 | "example": "examples"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/diarmidmackenzie/aframe-components.git"
15 | },
16 | "keywords": [
17 | "A-Frame",
18 | "WebXR",
19 | "performance"
20 | ],
21 | "author": "Diarmid Mackenzie",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
25 | },
26 | "homepage": "https://github.com/diarmidmackenzie/aframe-components/components/frame-rate#readme"
27 | }
28 |
--------------------------------------------------------------------------------
/components/graph/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/components/graph/image-20230318092246915.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/graph/image-20230318092246915.png
--------------------------------------------------------------------------------
/components/graph/image-20230318092739663.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/graph/image-20230318092739663.png
--------------------------------------------------------------------------------
/components/graph/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-graph",
3 | "version": "0.0.1",
4 | "description": "Dynamically Connected Graphs for A-Frame",
5 | "main": "index.js",
6 | "scripts": {
7 | "dist": "npm run dist:dev && npm run dist:prod",
8 | "dist:dev": "webpack --config webpack.config.js",
9 | "dist:prod": "webpack --config webpack.prod.config.js",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "keywords": [
13 | "A-Frame",
14 | "aframe",
15 | "link",
16 | "cut",
17 | "tree"
18 | ],
19 | "author": "Diarmid Mackenzie",
20 | "license": "MIT",
21 | "dependencies": {
22 | "aframe-connecting-line": "^0.1.0",
23 | "graphology": "^0.25.1",
24 | "graphology-shortest-path": "^2.0.2"
25 | },
26 | "devDependencies": {
27 | "webpack": "^5.75.0",
28 | "webpack-cli": "^5.0.1"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/components/graph/src/utils.js:
--------------------------------------------------------------------------------
1 | const DFSStack = require('graphology-indices/dfs-stack');
2 |
3 | /**
4 | * Return the set of nodes connected to a given node.
5 | *
6 | * @param {Graph} graph - Target graph.
7 | * @param {string} node - The ID of the node.
8 | *
9 | * Code based on forEachConnectedComponent() from graphology/components
10 | */
11 | function getConnectedComponent(graph, node) {
12 |
13 | const stack = new DFSStack(graph);
14 | const push = stack.push.bind(stack);
15 | const component = []
16 |
17 | stack.push(node);
18 |
19 | var source;
20 |
21 | while (stack.size !== 0) {
22 | source = stack.pop();
23 |
24 | component.push(source);
25 |
26 | graph.forEachNeighbor(source, push);
27 | }
28 |
29 | return component
30 | }
31 |
32 | exports.getConnectedComponent = getConnectedComponent
--------------------------------------------------------------------------------
/components/graph/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Dynamic Graph in A-Frame.
11 |
12 |
15 | view code
16 |
17 |
18 |
19 |
20 |
24 |
25 |
29 |
30 |
34 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/components/graph/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Webpack uses this to work with directories
2 | const path = require('path');
3 |
4 | // This is the main configuration object.
5 | // Here, you write different options and tell Webpack what to do
6 | module.exports = {
7 |
8 | // Path to your entry point. From this file Webpack will begin its work
9 | entry: './index.js',
10 |
11 | // Path and filename of your result bundle.
12 | // Webpack will bundle all JavaScript into this file
13 | output: {
14 | path: path.resolve(__dirname, 'dist'),
15 | publicPath: '',
16 | filename: 'graph.js'
17 | },
18 |
19 | resolve: {
20 | fallback: {
21 | "fs": false,
22 | "path": false
23 | },
24 | },
25 |
26 | // Default mode for Webpack is production.
27 | // Depending on mode Webpack will apply different things
28 | // on the final bundle. For now, we don't need production's JavaScript
29 | // minifying and other things, so let's set mode to development
30 | mode: 'development'
31 | };
--------------------------------------------------------------------------------
/components/graph/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var merge = require('webpack-merge').merge;
3 | var commonConfiguration = require('./webpack.config.js');
4 |
5 | module.exports = merge(commonConfiguration, {
6 | output: {
7 | path: path.resolve(__dirname, 'dist'),
8 | publicPath: '/dist/',
9 | filename: 'graph.min.js'
10 | },
11 | mode: 'production'
12 | });
--------------------------------------------------------------------------------
/components/head-tracking/index.js:
--------------------------------------------------------------------------------
1 | require('./src/face-detector.js')
2 | require('./src/head-tracker.js')
3 |
--------------------------------------------------------------------------------
/components/head-tracking/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "head-tracking",
3 | "version": "0.0.1",
4 | "description": "Tracking head position using laptop webcam",
5 | "main": "index.js",
6 | "scripts": {
7 | "dist": "npm run dist:min && npm run dist:max",
8 | "dist:max": "webpack",
9 | "dist:min": "cross-env NODE_ENV=production webpack",
10 | "start": "cross-env webpack serve",
11 | "test": "echo \"Error: no test specified\" && exit 1"
12 | },
13 | "author": "Diarmid Mackenzie",
14 | "license": "MIT",
15 | "dependencies": {
16 | "@mediapipe/tasks-vision": "^0.10.0"
17 | },
18 | "devDependencies": {
19 | "cross-env": "^7.0.3",
20 | "webpack": "^5.75.0",
21 | "webpack-cli": "^5.0.1",
22 | "webpack-dev-server": "^4.15.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/components/head-tracking/src/face-detector.js:
--------------------------------------------------------------------------------
1 | const {FilesetResolver, FaceDetector} = require('@mediapipe/tasks-vision')
2 |
3 | AFRAME.registerComponent('face-detector', {
4 |
5 | init() {
6 |
7 | this.lastVideoTime = 0
8 | this.video = document.createElement('video')
9 | this.video.autoplay = true
10 | this.video.playsInline = true
11 | document.body.appendChild(this.video)
12 |
13 | this.eventData = {
14 | video: this.video,
15 | detections: null
16 | }
17 |
18 | this.predictWebcam = this.predictWebcam.bind(this)
19 |
20 | // start face detector (completes asynchronously)
21 | this.startFaceDetector()
22 | },
23 |
24 | async startFaceDetector() {
25 | const vision = await FilesetResolver.forVisionTasks(
26 | "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm"
27 | );
28 | const faceDetector = await FaceDetector.createFromModelPath(vision,
29 | "https://storage.googleapis.com/mediapipe-tasks/face_detector/face_detection_short_range.tflite"
30 | );
31 |
32 | await faceDetector.setOptions({ runningMode: "VIDEO" });
33 | this.faceDetector = faceDetector
34 |
35 | // activate webcam
36 | stream = await navigator.mediaDevices.getUserMedia({ video: true })
37 | this.video.srcObject = stream;
38 | this.video.addEventListener("loadeddata", this.predictWebcam);
39 |
40 | },
41 |
42 | async predictWebcam() {
43 |
44 | // Detect faces using detectForVideo
45 | let startTimeMs = performance.now();
46 | if (this.video.currentTime !== this.lastVideoTime) {
47 | this.lastVideoTime = this.video.currentTime;
48 | this.eventData.detections = this.faceDetector.detectForVideo(this.video, startTimeMs)
49 | .detections;
50 |
51 | this.el.emit('face-detected', this.eventData)
52 | }
53 |
54 | // Call this function again to keep predicting when the browser is ready
55 | window.requestAnimationFrame(this.predictWebcam);
56 | }
57 | })
--------------------------------------------------------------------------------
/components/head-tracking/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Basic head position detection
11 |
12 |
15 | view code
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/components/head-tracking/test/window-camera.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Desktop screen simulating window into 3D world using head tracking
12 |
13 |
14 |
17 | view code
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/components/head-tracking/test/window-camera2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
Desktop screen simulating window into 3D world using head tracking
13 |
14 |
15 |
18 | view code
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/components/head-tracking/test/window-camera3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
27 |
28 |
29 |
30 |
Desktop screen simulating window into 3D world using head tracking
31 |
32 |
33 |
36 | view code
37 |
38 |
39 |
40 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/components/head-tracking/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | output: {
6 | libraryTarget: 'umd',
7 | path: path.resolve(__dirname, 'dist'),
8 | publicPath: '/dist/',
9 | filename:
10 | process.env.NODE_ENV === 'production'
11 | ? 'head-tracking.min.js'
12 | : 'head-tracking.js'
13 | },
14 | externals: {
15 | // Stubs out `import ... from 'three'` so it returns `import ... from window.THREE` effectively using THREE global variable that is defined by AFRAME.
16 | three: 'THREE'
17 | },
18 | devtool: 'source-map',
19 | mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
20 | devServer: {
21 | port: process.env.PORT || 5000,
22 | hot: false,
23 | liveReload: true,
24 | server: {
25 | type: 'https'
26 | },
27 | static: {
28 | directory: path.resolve(__dirname)
29 | }
30 | },
31 | resolve: {
32 | alias: {
33 | three: 'super-three'
34 | }
35 | }
36 | };
--------------------------------------------------------------------------------
/components/hide-on-hover.js:
--------------------------------------------------------------------------------
1 | AFRAME.registerComponent("hide-on-hover", {
2 |
3 | init() {
4 | this.el.setAttribute("raycastable")
5 | },
6 |
7 | events: {
8 | 'mouseenter': function (evt) {
9 | this.el.setAttribute("visible", false)
10 | },
11 | 'mouseleave': function (evt) {
12 | this.el.setAttribute("visible", true)
13 | }
14 | }
15 | })
--------------------------------------------------------------------------------
/components/label/image-20220811164727667.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/label/image-20220811164727667.png
--------------------------------------------------------------------------------
/components/label/image-20220811164814125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/label/image-20220811164814125.png
--------------------------------------------------------------------------------
/components/label/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-label",
3 | "version": "0.1.2",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "aframe-label",
9 | "version": "0.1.2",
10 | "license": "MIT"
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/components/label/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-label",
3 | "version": "0.1.3",
4 | "description": "A set of components that can be used to add labels to entities in desktop & VR experiences.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/label"
12 | },
13 | "keywords": [
14 | "A-Frame",
15 | "Label",
16 | "VR",
17 | "Desktop"
18 | ],
19 | "bugs": {
20 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
21 | },
22 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/label#readme",
23 | "author": "Diarmid Mackenzie",
24 | "license": "MIT"
25 | }
26 |
--------------------------------------------------------------------------------
/components/laser-manipulation/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/components/laser-manipulation/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
3 |
--------------------------------------------------------------------------------
/components/laser-manipulation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-laser-manipulation",
3 | "version": "0.3.0",
4 | "description": "Enables the user to move objects around using a laser pointer.",
5 | "main": "index.js",
6 | "scripts": {
7 | "dist": "npm run dist:dev && npm run dist:prod",
8 | "dist:dev": "webpack --config webpack.config.js",
9 | "dist:prod": "webpack --config webpack.prod.config.js",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/laser-manipulation"
15 | },
16 | "keywords": [
17 | "A-Frame",
18 | "Laser Controls",
19 | "Manipulation",
20 | "VR",
21 | "Desktop",
22 | "Raycasting"
23 | ],
24 | "bugs": {
25 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
26 | },
27 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/laser-manipulation#readme",
28 | "author": "Diarmid Mackenzie",
29 | "license": "MIT",
30 | "dependencies": {
31 | "aframe-object-parent": "^0.1.0",
32 | "aframe-thumbstick-states": "^0.1.0"
33 | },
34 | "devDependencies": {
35 | "webpack": "^5.75.0",
36 | "webpack-cli": "^5.0.1"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/components/laser-manipulation/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Webpack uses this to work with directories
2 | const path = require('path');
3 |
4 | // This is the main configuration object.
5 | // Here, you write different options and tell Webpack what to do
6 | module.exports = {
7 |
8 | // Path to your entry point. From this file Webpack will begin its work
9 | entry: './index.js',
10 |
11 | // Path and filename of your result bundle.
12 | // Webpack will bundle all JavaScript into this file
13 | output: {
14 | path: path.resolve(__dirname, 'dist'),
15 | publicPath: '',
16 | filename: 'laser-manipulation.js'
17 | },
18 |
19 | resolve: {
20 | fallback: {
21 | "fs": false,
22 | "path": false
23 | },
24 | },
25 |
26 | // Default mode for Webpack is production.
27 | // Depending on mode Webpack will apply different things
28 | // on the final bundle. For now, we don't need production's JavaScript
29 | // minifying and other things, so let's set mode to development
30 | mode: 'development'
31 | };
--------------------------------------------------------------------------------
/components/laser-manipulation/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var merge = require('webpack-merge').merge;
3 | var commonConfiguration = require('./webpack.config.js');
4 |
5 | module.exports = merge(commonConfiguration, {
6 | output: {
7 | path: path.resolve(__dirname, 'dist'),
8 | publicPath: '/dist/',
9 | filename: 'laser-manipulation.min.js'
10 | },
11 | mode: 'production'
12 | });
--------------------------------------------------------------------------------
/components/mouse-manipulation/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/components/mouse-manipulation/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
3 |
--------------------------------------------------------------------------------
/components/mouse-manipulation/image-20220812163558569.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/mouse-manipulation/image-20220812163558569.png
--------------------------------------------------------------------------------
/components/mouse-manipulation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-mouse-manipulation",
3 | "version": "0.3.0",
4 | "description": "Enables the user to move objects in 3D space using a mouse on desktop.",
5 | "main": "index.js",
6 | "scripts": {
7 | "dist": "npm run dist:dev && npm run dist:prod",
8 | "dist:dev": "webpack --config webpack.config.js",
9 | "dist:prod": "webpack --config webpack.prod.config.js",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/mouse-manipulation"
15 | },
16 | "keywords": [
17 | "A-Frame",
18 | "Mouse",
19 | "Desktop",
20 | "Raycasting"
21 | ],
22 | "bugs": {
23 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
24 | },
25 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/mouse-manipulation#readme",
26 | "author": "Diarmid Mackenzie",
27 | "license": "MIT",
28 | "dependencies": {
29 | "aframe-cursor-tracker": "^0.1.0",
30 | "aframe-label": "^0.1.0",
31 | "aframe-object-parent": "^0.1.0"
32 | },
33 | "devDependencies": {
34 | "webpack": "^5.75.0",
35 | "webpack-cli": "^5.0.1"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/components/mouse-manipulation/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Webpack uses this to work with directories
2 | const path = require('path');
3 |
4 | // This is the main configuration object.
5 | // Here, you write different options and tell Webpack what to do
6 | module.exports = {
7 |
8 | // Path to your entry point. From this file Webpack will begin its work
9 | entry: './index.js',
10 |
11 | // Path and filename of your result bundle.
12 | // Webpack will bundle all JavaScript into this file
13 | output: {
14 | path: path.resolve(__dirname, 'dist'),
15 | publicPath: '',
16 | filename: 'mouse-manipulation.js'
17 | },
18 |
19 | resolve: {
20 | fallback: {
21 | "fs": false,
22 | "path": false
23 | },
24 | },
25 |
26 | // Default mode for Webpack is production.
27 | // Depending on mode Webpack will apply different things
28 | // on the final bundle. For now, we don't need production's JavaScript
29 | // minifying and other things, so let's set mode to development
30 | mode: 'development'
31 | };
--------------------------------------------------------------------------------
/components/mouse-manipulation/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var merge = require('webpack-merge').merge;
3 | var commonConfiguration = require('./webpack.config.js');
4 |
5 | module.exports = merge(commonConfiguration, {
6 | output: {
7 | path: path.resolve(__dirname, 'dist'),
8 | publicPath: '/dist/',
9 | filename: 'mouse-manipulation.min.js'
10 | },
11 | mode: 'production'
12 | });
--------------------------------------------------------------------------------
/components/object-parent/index.js:
--------------------------------------------------------------------------------
1 | // Change the parent of an object without changing its transform.
2 | AFRAME.registerComponent('object-parent', {
3 |
4 | schema: {
5 | parent: {type: 'selector'},
6 | },
7 |
8 | update() {
9 |
10 | const matches = document.querySelectorAll(`#${parent.id}`)
11 | if (matches.length > 1) {
12 | console.warn(`object-parent matches duplicate entities for new parent ${parent.id}`)
13 | }
14 |
15 | const newParent = this.data.parent.object3D
16 | this.reparent(newParent)
17 |
18 | },
19 |
20 | remove() {
21 |
22 | const originalParentEl = this.el.parentEl
23 | this.reparent(originalParentEl.object3D)
24 |
25 | },
26 |
27 | reparent(newParent) {
28 |
29 | const object = this.el.object3D
30 | const oldParent = object.parent
31 |
32 | if (object.parent === newParent) {
33 | return;
34 | }
35 |
36 | objectEl = (o) => {
37 | if (o.type === 'Scene') {
38 | return (this.el.sceneEl)
39 | }
40 | else {
41 | return o.el
42 | }
43 | }
44 |
45 | //console.log(`Reparenting ${object.el.id} from ${objectEl(oldParent).id} to ${objectEl(newParent).id}`);
46 |
47 | newParent.attach(object);
48 | },
49 | });
50 |
--------------------------------------------------------------------------------
/components/object-parent/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-object-parent",
3 | "version": "0.1.0",
4 | "description": "Changes the object3D parent of an A-Frame entity.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/object-parent"
12 | },
13 | "keywords": [
14 | "A-Frame",
15 | "Threejs",
16 | "object3D",
17 | "parent"
18 | ],
19 | "bugs": {
20 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
21 | },
22 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/object-parent#readme",
23 | "author": "Diarmid Mackenzie",
24 | "license": "MIT"
25 | }
26 |
--------------------------------------------------------------------------------
/components/plug-socket/image-20230409165520988.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/plug-socket/image-20230409165520988.png
--------------------------------------------------------------------------------
/components/plug-socket/image-20230410115732409.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/plug-socket/image-20230410115732409.png
--------------------------------------------------------------------------------
/components/plug-socket/image-20230410120556987.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/plug-socket/image-20230410120556987.png
--------------------------------------------------------------------------------
/components/plug-socket/index.js:
--------------------------------------------------------------------------------
1 | if (!AFRAME.components['polygon-wireframe']) require('aframe-polygon-wireframe')
2 | require('./src/socket-system.js')
3 | require('./src/socket-fabric.js')
4 | require('./src/socket.js')
5 | require('./src/plug.js')
--------------------------------------------------------------------------------
/components/plug-socket/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-plug-socket",
3 | "version": "0.0.1",
4 | "description": "Plugs & Sockets for A-Frame Entities",
5 | "main": "index.js",
6 | "scripts": {
7 | "dist": "npm run dist:dev && npm run dist:prod",
8 | "dist:dev": "webpack --config webpack.config.js",
9 | "dist:prod": "webpack --config webpack.prod.config.js",
10 | "test": "qunit"
11 | },
12 | "keywords": [
13 | "A-Frame",
14 | "aframe",
15 | "plug",
16 | "socket",
17 | "snap",
18 | "position"
19 | ],
20 | "author": "Diarmid Mackenzie",
21 | "license": "MIT",
22 | "dependencies": {
23 | "aframe-polygon-wireframe": "^0.2.1"
24 | },
25 | "devDependencies": {
26 | "qunit": "^2.19.4",
27 | "webpack": "^5.75.0",
28 | "webpack-cli": "^5.0.1"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/components/plug-socket/src/plug.js:
--------------------------------------------------------------------------------
1 | AFRAME.registerComponent('plug', {
2 |
3 | init() {
4 | this.el.setAttribute('socket', {type: 'plug'})
5 | }
6 | })
--------------------------------------------------------------------------------
/components/plug-socket/test/test1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Simple plug-socket test - bricks should snap together
11 |
12 |
14 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/components/plug-socket/test/test10.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Simple plug-socket test - bricks should snap together. Both have non-zero rotations.
11 |
12 |
14 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/components/plug-socket/test/test11.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Simple plug-socket test - bricks should snap together. Both have non-zero rotations.
11 |
12 |
14 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/components/plug-socket/test/test12.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
8-stud plug-socket test - bricks at various offsets and angles
12 |
Snap distance: 0 . Hit space to increase it (behaviour will degenerate above 0.9)
13 |
14 |
16 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/components/plug-socket/test/test13.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Simple plug-socket test - bricks should snap together. Both have non-zero rotations.
11 |
Specific combination of rotations that seems to expose a problem...
12 |
13 |
15 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/components/plug-socket/test/test14.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Simple plug-socket test - bricks should snap together. Both have non-zero rotations.
11 |
Another specific combination of rotations that exposed a problem...
12 |
13 |
15 |
17 |
18 |
23 |
24 |
25 |
26 |
27 |
28 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/components/plug-socket/test/test2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
2-stud plug-socket test - bricks should snap together
11 |
12 |
14 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/components/plug-socket/test/test3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
4-stud plug-socket test - bricks should snap together, offset
11 |
12 |
15 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/components/plug-socket/test/test8.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
19 |
20 |
21 |
22 |
Simple plug-socket test - bricks move under user control and snap into place
23 |
24 |
26 |
27 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/components/plug-socket/test/test9.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Plug-socket test with dynamic snap - bricks at various different positions
15 |
Can plug in above or below any block
16 |
17 |
20 |
21 |
36 |
37 |
41 |
42 |
43 |
44 |
45 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/components/plug-socket/test/unit-tests.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Test Suite
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/components/plug-socket/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Webpack uses this to work with directories
2 | const path = require('path');
3 |
4 | // This is the main configuration object.
5 | // Here, you write different options and tell Webpack what to do
6 | module.exports = {
7 |
8 | // Path to your entry point. From this file Webpack will begin its work
9 | entry: './index.js',
10 |
11 | // Path and filename of your result bundle.
12 | // Webpack will bundle all JavaScript into this file
13 | output: {
14 | path: path.resolve(__dirname, 'dist'),
15 | publicPath: '',
16 | filename: 'plug-socket.js'
17 | },
18 |
19 | resolve: {
20 | fallback: {
21 | "fs": false,
22 | "path": false
23 | },
24 | },
25 |
26 | // Default mode for Webpack is production.
27 | // Depending on mode Webpack will apply different things
28 | // on the final bundle. For now, we don't need production's JavaScript
29 | // minifying and other things, so let's set mode to development
30 | mode: 'development'
31 | };
--------------------------------------------------------------------------------
/components/plug-socket/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var merge = require('webpack-merge').merge;
3 | var commonConfiguration = require('./webpack.config.js');
4 |
5 | module.exports = merge(commonConfiguration, {
6 | output: {
7 | path: path.resolve(__dirname, 'dist'),
8 | publicPath: '/dist/',
9 | filename: 'plug-socket.min.js'
10 | },
11 | mode: 'production'
12 | });
--------------------------------------------------------------------------------
/components/polygon-wireframe/README.md:
--------------------------------------------------------------------------------
1 | # polygon-wireframe
2 |
3 | ## Overview
4 |
5 | A component to display wireframes composed of polygons, rather than triangles.
6 |
7 | 
8 |
9 |
10 |
11 | ## Schema
12 |
13 | | Property | Description | Default |
14 | | ------------- | ------------------------------------------------------------ | ------- |
15 | | color | The color to use for the lines of the wireframe | grey |
16 | | opacity | The opacity with which to render the non-hidden parts of the wireframe. This should not be set to a lower value than hiddenOpacity (doing so will trigger a warning, and result in the whole wireframe being rendered with the hiddenOpacity opacity setting). | 1 |
17 | | hiddenOpacity | The opacity with which to render any hidden parts of the wireframe. Setting this to a non-zero value means that parts of the wireframe that would normally be hidden (i.e. that are behind other objects) are still visible. By setting it to a value lower than `opacity` allows for a visible difference between the hidden and non-hidden parts of the wireframe, even though both are visible. | 0 |
18 | | dashed | Whether to use dashed lines. If false, solid lines are used | false |
19 | | dashSize | If dashed lines are used, the length of the dashes relative to the gaps | 3 |
20 | | gapSize | If dashed lines are used, the length of the gaps relative to the dashes | 1 |
21 | | dashScale | If dashed lines are used, this determines the scale of the dashes / gaps. Whatever units are used for dashSize & gapSize, this is the number of units that will fit into a 1 unit of length (i.e. 1 meter if the entity has default scaling). Larger values for dashScale result in smaller dashes / gaps. With the default values for dashScale, dashSize and gapSize, and default entity scaling, dashes will be 10cm (3 x 100 / 30), and gaps 3.33cm (1 x 100 / 30). | 30 |
22 |
23 | ## Installation
24 |
25 | Via CDN
26 | ```
27 |
28 | ```
29 |
30 | Or via [npm](https://www.npmjs.com/package/aframe-polygon-wireframe)
31 |
32 | ```
33 | npm install aframe-polygon-wireframe
34 | ```
35 |
36 |
37 | ## Examples
38 |
39 | [polygon-wireframe.html](https://diarmidmackenzie.github.io/aframe-components/component-usage/polygon-wireframe.html)
40 |
41 |
42 |
43 | ## Code
44 |
45 | [polygon-wireframe](https://github.com/diarmidmackenzie/aframe-components/blob/main/components/polygon-wireframe/index.js)
--------------------------------------------------------------------------------
/components/polygon-wireframe/image-20220816094651445.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/polygon-wireframe/image-20220816094651445.png
--------------------------------------------------------------------------------
/components/polygon-wireframe/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-polygon-wireframe",
3 | "version": "0.3.1",
4 | "description": "Render wireframes composed of polygons, rather than triangles.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/polygon-wireframe"
12 | },
13 | "keywords": [
14 | "A-Frame",
15 | "Laser Controls",
16 | "Manipulation",
17 | "VR",
18 | "Desktop"
19 | ],
20 | "bugs": {
21 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
22 | },
23 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/polygon-wireframe#readme",
24 | "author": "Diarmid Mackenzie",
25 | "license": "MIT"
26 | }
27 |
--------------------------------------------------------------------------------
/components/polygon-wireframe/test/hidden-line-options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
33 |
34 |
35 |
38 |
39 |
40 |
44 |
45 |
46 |
49 |
50 |
54 |
55 |
56 |
59 |
60 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
74 | view code
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/components/raycast-target/README.md:
--------------------------------------------------------------------------------
1 | # raycast-target
2 |
3 | ## Overview
4 |
5 | A very simple utility component that is used to enable proxy raycasting.
6 |
7 | Proxy raycasting is a pattern where the entity used for raycasting is different from the entity that is selected or manipulated by raycasting. It enables performance improvements when raycasting against entities with complex geometry by allowing raycasting computations to be performed against an entity with simpler geometry, which can be substantially more efficient.
8 |
9 | The entity with simpler geometry could be a low-poly mesh that approximates the entity's geometry. Or in cases where precision raycasting is not required, it could be as simple as a bounding cube or sphere.
10 |
11 |
12 |
13 | ## Schema
14 |
15 | `raycast-target` has a single property schema
16 |
17 | The property is a selector for the target for which this entity is acting as a raycast proxy. If no value is specified, the entity will be set up as a raycast proxy for itself (i.e. no proxying takes place).
18 |
19 |
20 |
21 | ## Usage
22 |
23 | `raycast-target` exposes the target entity on the `target` property
24 |
25 | Here's some sample code that extracts a raycast target if available, and defaults to the entity itself if not.
26 |
27 | ```
28 | getRaycastTarget(el) {
29 | if (el.components['raycast-target']) {
30 | return el.components['raycast-target'].target
31 | }
32 | else {
33 | return el
34 | }
35 | },
36 | ```
37 |
38 |
39 |
40 | ## Installation
41 |
42 | Via CDN
43 | ```
44 |
45 | ```
46 |
47 | Or via [npm](https://www.npmjs.com/package/aframe-raycast-target)
48 |
49 | ```
50 | npm install aframe-raycast-target
51 | ```
52 |
53 |
54 | ## Components supporting Proxy Raycasting
55 |
56 | The following high-level components support proxy raycasting using `raycast-target`.
57 |
58 | - [laser-manipulation](https://diarmidmackenzie.github.io/aframe-components/docs/laser-manipulation.html)
59 |
60 | - [mouse-manipulation](https://diarmidmackenzie.github.io/aframe-components/docs/mouse-manipulation.html)
61 |
62 |
63 |
64 | ## Examples
65 |
66 | To follow...
67 |
68 |
69 |
70 | ## Code
71 |
72 | [raycast-target](https://github.com/diarmidmackenzie/aframe-components/blob/main/components/raycast-target/index.js)
--------------------------------------------------------------------------------
/components/raycast-target/index.js:
--------------------------------------------------------------------------------
1 |
2 | // Component used to mark an entity for raycasting, and optionally provide
3 | // another entity as a target (e.g. useful when raycasting against a low-poly mesh, rather than the target itself)
4 | //
5 | // Note that setting a target here doesn't change which entity will generate raycast / cursor events.
6 | // Applications written using cursor/raycaster need to be written to check for this configurattion and act on it.
7 |
8 | AFRAME.registerComponent('raycast-target', {
9 | schema: {type: 'selector'},
10 |
11 | init() {
12 | this.target = this.data ? this.data : this.el
13 | }
14 | })
15 |
--------------------------------------------------------------------------------
/components/raycast-target/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-raycast-target",
3 | "version": "0.1.0",
4 | "description": "Simple utility component that is used to enable proxy raycasting.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/raycast-target"
12 | },
13 | "keywords": [
14 | "A-Frame",
15 | "Raycasting",
16 | "Proxy"
17 | ],
18 | "bugs": {
19 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
20 | },
21 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/raycast-target#readme",
22 | "author": "Diarmid Mackenzie",
23 | "license": "MIT"
24 | }
25 |
--------------------------------------------------------------------------------
/components/raycaster-thresholds/README.md:
--------------------------------------------------------------------------------
1 | # raycaster-thresholds
2 |
3 | ## Overview
4 |
5 | A component that enables configuration of the proximity thresholds for raycasting against lines and points.
6 |
7 | This is useful because the default thresholds for raycasting against lines and points is 1m, which is far too large for many applications. See [this A-Frame issue](https://github.com/aframevr/aframe/issues/5072).
8 |
9 |
10 |
11 | ## Schema
12 |
13 | | Property | Description | Default |
14 | | -------- | ------------------------------------------------------------ | ------- |
15 | | line | The accuracy threshold (in meters) to use when raycasting against lines | 0.01 |
16 | | points | The accuracy threshold (in meters) to use when raycasting against points | 0.01 |
17 |
18 |
19 |
20 | ## Installation
21 |
22 | Via CDN
23 | ```
24 |
25 | ```
26 |
27 | Or via [npm](https://www.npmjs.com/package/aframe-raycaster-thresholds)
28 |
29 | ```
30 | npm install aframe-raycaster-thresholds
31 | ```
32 |
33 | ## Usage
34 |
35 | To use thresholds of 1cm rather than 1m, just set on a Entity that uses raycasting, like this:
36 |
37 | ```
38 |
39 | ```
40 |
41 | Or to specify specific non-default thresholds (for example):
42 |
43 | ```
44 |
46 | ```
47 |
48 |
49 |
50 | ## Examples
51 |
52 | [raycaster-thresholds.html](https://diarmidmackenzie.github.io/aframe-components/component-usage/raycaster-thresholds.html)
53 |
54 |
55 |
56 | ## Code
57 |
58 | [raycaster-thresholds](https://github.com/diarmidmackenzie/aframe-components/blob/main/components/raycaster-thresholds/index.js)
--------------------------------------------------------------------------------
/components/raycaster-thresholds/index.js:
--------------------------------------------------------------------------------
1 |
2 | AFRAME.registerComponent('raycaster-thresholds', {
3 |
4 | dependencies: ['raycaster'],
5 |
6 | schema: {
7 | line: {type: 'number', default: 0.01},
8 | points: {type: 'number', default: 0.01},
9 | },
10 |
11 | init() {
12 | this.oldLine = this.el.components.raycaster.raycaster.params.Line.threshold
13 | this.oldPoints = this.el.components.raycaster.raycaster.params.Points.threshold
14 |
15 | this.el.components.raycaster.raycaster.params.Line.threshold = this.data.line
16 | this.el.components.raycaster.raycaster.params.Points.threshold = this.data.points
17 | },
18 |
19 | remove() {
20 | this.el.components.raycaster.raycaster.params.Line.threshold = this.oldLine
21 | this.el.components.raycaster.raycaster.params.Points.threshold = this.oldPoints
22 | }
23 | })
--------------------------------------------------------------------------------
/components/raycaster-thresholds/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-raycaster-thresholds",
3 | "version": "0.1.0",
4 | "description": "Enables configuration of the proximity thresholds for raycasting against lines and points.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/raycaster-thresholds"
12 | },
13 | "keywords": [
14 | "A-Frame",
15 | "Raycasting",
16 | "Proxy"
17 | ],
18 | "bugs": {
19 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
20 | },
21 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/raycaster-thresholds#readme",
22 | "author": "Diarmid Mackenzie",
23 | "license": "MIT"
24 | }
25 |
--------------------------------------------------------------------------------
/components/scale-on-hover.js:
--------------------------------------------------------------------------------
1 | AFRAME.registerComponent("scale-on-hover", {
2 |
3 | init() {
4 | this.el.setAttribute("raycastable")
5 | },
6 |
7 | events: {
8 | 'mouseenter': function (evt) {
9 | this.el.removeAttribute("animation__scale")
10 | this.el.setAttribute("animation__scale", "property:scale; to: 1.2 1.2 1.2; dur: 300")
11 | },
12 | 'mouseleave': function (evt) {
13 | this.el.removeAttribute("animation__scale")
14 | this.el.setAttribute("animation__scale", "property:scale; to: 1 1 1; dur: 300")
15 | }
16 | }
17 | })
--------------------------------------------------------------------------------
/components/screen-position/README.md:
--------------------------------------------------------------------------------
1 | # screen-position
2 |
3 | ## Overview
4 |
5 | Components to track and report the 2D screen position of an A-Frame entity.
6 |
7 |
8 |
9 | ### screen-position
10 |
11 | This component makes the current screen position of an A-Frame entity (as per the active camera) available via a function
12 |
13 | `this.el.components['screen-position'].getScreenPosition(pos)`
14 |
15 | The parameter `pos` should contain a pre-allocated [`THREE.Vector2`](https://threejs.org/docs/index.html?q=vector2#api/en/math/Vector2).
16 |
17 | The x & y values are populated with the x & y co-ordinates on the current screen of the center of the entity.
18 |
19 |
20 |
21 | ### output-screen-position
22 |
23 | This is a component primarily intended for demonstration purposes. It can be added to an entity with the `screen-position` component, and outputs the screen position data in one of two ways:
24 |
25 | - As text, by writing to the `innerHTML` of a specified element
26 | - As screen position data, by writing to the `style.top` and `style.left` attributes of an element with absolute position.
27 |
28 |
29 |
30 | ## Schema
31 |
32 | | Property | Description | Default |
33 | | -------- | ------------------------------------------------------------ | ------- |
34 | | text | selector for an HTML element to write the x, y screen co-ordinates of the entity to, once every frame | |
35 | | tracker | selector for an HTML element with absolute position, whose 2D position will be updated once every frame to match the 2D position of the entity. | |
36 |
37 |
38 |
39 | ## Installation
40 |
41 | Via CDN
42 | ```
43 |
44 | ```
45 |
46 | Or via [npm](https://www.npmjs.com/package/aframe-screen-position)
47 |
48 | ```
49 | npm install aframe-screen-position
50 | ```
51 |
52 | ## Examples
53 |
54 | [screen-position.html](https://diarmidmackenzie.github.io/aframe-components/component-usage/screen-position.html)
55 |
56 |
57 |
58 | ## Code
59 |
60 | [screen-position](https://github.com/diarmidmackenzie/aframe-components/blob/main/components/screen-position/index.js)
--------------------------------------------------------------------------------
/components/screen-position/index.js:
--------------------------------------------------------------------------------
1 | AFRAME.registerComponent('screen-position', {
2 |
3 | init() {
4 | this.vec3 = new THREE.Vector3()
5 | this.getScreenPosition = this.getScreenPosition.bind(this)
6 | },
7 |
8 | getScreenPosition(pos) {
9 |
10 | this.el.object3D.getWorldPosition(this.vec3)
11 |
12 | const camera = this.el.sceneEl.camera
13 | this.vec3.project(camera)
14 |
15 | const bounds = document.body.getBoundingClientRect();
16 |
17 | pos.x = bounds.width * (this.vec3.x + 1) / 2
18 | pos.y = bounds.height - bounds.height * (this.vec3.y + 1) / 2
19 | return pos
20 | }
21 | });
22 |
23 | AFRAME.registerComponent('output-screen-position', {
24 |
25 | schema: {
26 | text: { type: 'selector'},
27 | tracker: { type: 'selector'}
28 | },
29 |
30 | init() {
31 | this.pos = new THREE.Vector2()
32 | this.getScreenPosition = this.el.components['screen-position'].getScreenPosition
33 | },
34 |
35 | tick() {
36 |
37 | this.getScreenPosition(this.pos)
38 |
39 | if (this.data.text) {
40 | this.data.text.innerHTML = `x: ${this.pos.x.toFixed(0)}, y: ${this.pos.y.toFixed(0)}`
41 | }
42 |
43 | if (this.data.tracker) {
44 |
45 | const tracker = this.data.tracker
46 |
47 | const rect = tracker.getBoundingClientRect()
48 | tracker.style.top = `${this.pos.y - ( rect.height / 2 )}px`
49 | tracker.style.left = `${this.pos.x - ( rect.width / 2 )}px`
50 | }
51 | }
52 | });
53 |
--------------------------------------------------------------------------------
/components/screen-position/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-screen-position",
3 | "version": "0.1.0",
4 | "description": "Components to track and report the 2D screen position of an A-Frame entity.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/screen-position"
12 | },
13 | "keywords": [
14 | "A-Frame",
15 | "Screen",
16 | "Position"
17 | ],
18 | "bugs": {
19 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
20 | },
21 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/screen-position#readme",
22 | "author": "Diarmid Mackenzie",
23 | "license": "MIT"
24 | }
25 |
--------------------------------------------------------------------------------
/components/stats-panel/image-20221106161718921.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/stats-panel/image-20221106161718921.png
--------------------------------------------------------------------------------
/components/stats-panel/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-stats-panel",
3 | "version": "0.2.3",
4 | "description": "A-Frame statistics panel for additional statistics, in the style of A-Frame stats",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "A-Frame",
11 | "statistics",
12 | "stats"
13 | ],
14 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/stats-panel#readme",
15 | "author": "Diarmid Mackenzie",
16 | "license": "MIT"
17 | }
18 |
--------------------------------------------------------------------------------
/components/thumbstick-states/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-thumbstick-states",
3 | "version": "0.1.0",
4 | "description": "Simplify implementation of thumbstick-based controls in A-Frame.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/diarmidmackenzie/aframe-components/tree/main/components/thumbstick-states"
12 | },
13 | "keywords": [
14 | "A-Frame",
15 | "Controller",
16 | "Thumbstick"
17 | ],
18 | "bugs": {
19 | "url": "https://github.com/diarmidmackenzie/aframe-components/issues"
20 | },
21 | "homepage": "https://diarmidmackenzie.github.io/aframe-components/components/thumbstick-states#readme",
22 | "author": "Diarmid Mackenzie",
23 | "license": "MIT"
24 | }
25 |
--------------------------------------------------------------------------------
/components/xr-room-physics/dist/xr-room-physics.min.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /**
2 | * @license
3 | * Copyright 2010-2023 Three.js Authors
4 | * SPDX-License-Identifier: MIT
5 | */
6 |
--------------------------------------------------------------------------------
/components/xr-room-physics/image-20230702084154726.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/xr-room-physics/image-20230702084154726.png
--------------------------------------------------------------------------------
/components/xr-room-physics/image-20230702090037281.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/xr-room-physics/image-20230702090037281.png
--------------------------------------------------------------------------------
/components/xr-room-physics/image-20230702091131736.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/xr-room-physics/image-20230702091131736.png
--------------------------------------------------------------------------------
/components/xr-room-physics/image-20230702092025851.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/xr-room-physics/image-20230702092025851.png
--------------------------------------------------------------------------------
/components/xr-room-physics/image-20230702092318339.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/xr-room-physics/image-20230702092318339.png
--------------------------------------------------------------------------------
/components/xr-room-physics/image-20230702100955317.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/components/xr-room-physics/image-20230702100955317.png
--------------------------------------------------------------------------------
/components/xr-room-physics/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aframe-xr-room-physics",
3 | "version": "0.0.1",
4 | "description": "Add physics objects for reported XR room layout",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "npm run dist",
8 | "deploy": "npm run build && netlify deploy --prod --dir=.",
9 | "dist": "npm run dist:min && npm run dist:max",
10 | "dist:max": "webpack",
11 | "dist:min": "cross-env NODE_ENV=production webpack",
12 | "prepublish": "npm run dist",
13 | "start": "cross-env webpack serve"
14 | },
15 | "keywords": [
16 | "aframe",
17 | "physics",
18 | "xr",
19 | "room",
20 | "planes"
21 | ],
22 | "author": "Diarmid Mackenzie",
23 | "license": "MIT",
24 | "dependencies": {
25 | "ratk": "^0.1.1"
26 | },
27 | "devDependencies": {
28 | "cross-env": "^7.0.3",
29 | "webpack": "^5.75.0",
30 | "webpack-cli": "^5.0.1",
31 | "webpack-dev-server": "^4.15.1"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/components/xr-room-physics/test/ammo-desktop-room.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Configure Room Planes in Ammo Physics Engine
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
Test with a single desktop-emulated plane.
18 |
19 |
22 | view code
23 |
24 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/components/xr-room-physics/test/ammo-desktop-room2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Configure Room Planes in Ammo Physics Engine
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
Test with two desktop-emulated planes: walls. Space to shoot balls.
18 |
19 |
22 | view code
23 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
36 |
37 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/components/xr-room-physics/test/ammo-desktop-room3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Configure Room Planes in Ammo Physics Engine
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
Test with two desktop-emulated planes: wall and floor. Space to shoot balls.
18 |
19 |
22 | view code
23 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
36 |
37 |
38 |
39 |
41 |
42 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/components/xr-room-physics/test/ammo-room.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Configure Room Planes in Ammo Physics Engine
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
Configured XR Planes automatically created as static bodies in Ammo Physics.
19 |
20 |
23 | view code
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/components/xr-room-physics/test/ammo-shape-test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Test generation of Ammo Physics Shape from 2 x parallel planes
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Generate Ammo Physics Shape from prism (ExtrudeGeometry)
16 |
17 |
20 | view code
21 |
22 |
23 |
24 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/components/xr-room-physics/test/cannon-room.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Configure Room Planes in Cannon Physics Engine
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Configured XR Planes automatically created as static bodies in Cannon Physics.
17 |
18 |
21 | view code
22 |
23 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/components/xr-room-physics/test/cannon-shape-test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Test generation of Cannon Physics Shape from 2 x parallel planes
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Generate Cannon Physics Shape from prism (ExtrudeGeometry)
15 |
16 |
19 | view code
20 |
21 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/components/xr-room-physics/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Test pages for xr-room-physics
5 | Testing in VR, with a room layout pre-configured on your device
6 |
11 | Testing on Desktop, with simulated room layout
12 |
13 | Full test: Convex & concave corners; Desktop simulation of VR controllers; Toggle debug
14 |
19 | Simpler tests (these all use Ammo physics)
20 |
26 |
--------------------------------------------------------------------------------
/components/xr-room-physics/test/physx-room.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Configure Room Planes in PhysX Physics Engine
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Configured XR Planes automatically created as static bodies in PhysX Physics.
17 |
18 |
21 | view code
22 |
23 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/components/xr-room-physics/test/physx-shape-test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Test generation of PhysX Physics Shape from 2 x parallel planes
7 |
8 |
9 |
10 |
11 |
12 |
37 |
38 |
39 |
40 |
41 |
Generate PhysX Physics Shape from prism (ExtrudeGeometry)s
42 |
43 |
46 | view code
47 |
48 |
49 |
50 |
54 |
55 |
56 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/components/xr-room-physics/test/test-geometries.js:
--------------------------------------------------------------------------------
1 | AFRAME.registerComponent('two-planes', {
2 |
3 | schema: {
4 | engine: { type: 'string'}
5 | }
6 | ,
7 | init() {
8 | const mesh = new THREE.Group()
9 | this.el.setObject3D('mesh', mesh)
10 | const planeGeometry = new THREE.PlaneGeometry()
11 | const material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} );
12 | const frontPlane = new THREE.Mesh(planeGeometry, material)
13 | const rearPlane = new THREE.Mesh(planeGeometry, material)
14 | mesh.add(frontPlane)
15 | mesh.add(rearPlane)
16 | rearPlane.position.z -= 0.5
17 |
18 | if (this.data.engine === 'ammo') {
19 | mesh.position.z += 0.25
20 | }
21 |
22 | }
23 | })
24 |
25 | AFRAME.registerComponent('prism', {
26 |
27 | schema: {
28 | engine: { type: 'string'}
29 | },
30 |
31 | init() {
32 |
33 | const polygon = [
34 | {x: -1, z: -1},
35 | {x: -1, z: 1},
36 | {x: 1, z: 1},
37 | {x: 1, z: -1}
38 | ]
39 |
40 | const planeShape = new THREE.Shape()
41 | polygon.forEach((point, i) => {
42 | if (i == 0) {
43 | planeShape.moveTo(point.x, point.z);
44 | } else {
45 | planeShape.lineTo(point.x, point.z);
46 | }
47 | });
48 | const geometry = new THREE.ExtrudeGeometry(planeShape, {depth: 0.3, bevelEnabled: false});
49 | geometry.rotateX(-Math.PI / 2);
50 | geometry.center();
51 |
52 | const material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} );
53 | const mesh = new THREE.Mesh(geometry, material)
54 | this.el.setObject3D('mesh', mesh)
55 | }
56 | })
--------------------------------------------------------------------------------
/components/xr-room-physics/test/toggle-debug.js:
--------------------------------------------------------------------------------
1 | AFRAME.registerComponent('toggle-debug', {
2 |
3 | init() {
4 | this.debug = false;
5 | this.toggleDebug = this.toggleDebug.bind(this)
6 | this.keyUp = this.keyUp.bind(this)
7 | this.el.addEventListener('abuttondown', this.toggleDebug)
8 | this.el.addEventListener('xbuttondown', this.toggleDebug)
9 | window.addEventListener('keyup', this.keyUp)
10 | },
11 |
12 | toggleDebug() {
13 |
14 | this.debug = !this.debug
15 | this.el.sceneEl.setAttribute('xr-room-physics', { debug: this.debug })
16 | },
17 |
18 | keyUp(e) {
19 | if (e.code === 'KeyQ') {
20 | this.toggleDebug()
21 | }
22 | }
23 | });
--------------------------------------------------------------------------------
/components/xr-room-physics/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | output: {
6 | libraryTarget: 'umd',
7 | path: path.resolve(__dirname, 'dist'),
8 | publicPath: '/dist/',
9 | filename:
10 | process.env.NODE_ENV === 'production'
11 | ? 'xr-room-physics.min.js'
12 | : 'xr-room-physics.js'
13 | },
14 | externals: {
15 | // Stubs out `import ... from 'three'` so it returns `import ... from window.THREE` effectively using THREE global variable that is defined by AFRAME.
16 | three: 'THREE'
17 | },
18 | devtool: 'source-map',
19 | mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
20 | devServer: {
21 | port: process.env.PORT || 5000,
22 | hot: false,
23 | liveReload: true,
24 | server: {
25 | type: 'https'
26 | },
27 | static: {
28 | directory: path.resolve(__dirname + '../../..')
29 | }
30 | },
31 | resolve: {
32 | alias: {
33 | three: 'super-three'
34 | }
35 | }
36 | };
--------------------------------------------------------------------------------
/compositions/wrapped-present/README.md:
--------------------------------------------------------------------------------
1 | # wrapped-present
2 | 3D animation giving someone a picture as a present.
3 |
4 |
5 | This can be customized with the following options as URL parameters.
6 |
7 | | Parameter | Value | Example | Default |
8 | | ------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------- |
9 | | gift-url | The URL of an image to include. Must be URL-encoded. | https%3A%2F%2Fcdn.aframe.io%2Fexamples %2Fui%2FkarigurashiPoster.jpg | ./assets/sample-image.png |
10 | | box-color | The color to use for the gift box, as a hex string | #00ff00 (for green) | red (#ff0000) |
11 | | ribbon-color | The color to use for ribbon on the gift box, as a hex string. Note that metallic & roughness settings are automatically applied to this to make the ribbon shiny. | #0000ff (for blue) | gold (#ffd700) |
12 | | message | The message that appears at the top of the screen. This is displayed as a single line - long messages will be hard to read on mobile devices. Spaces need to be URL-encoded (%20) | Good%20%Luck | "Happy Birthday!" |
13 |
14 |
15 |
16 | Example:
17 |
18 | https://diarmidmackenzie.github.io/aframe-components/compositions/wrapped-present/?gift-url=https%3A%2F%2Fcdn.aframe.io%2Fexamples%2Fui%2FkarigurashiPoster.jpg&box-color=00ff00&ribbon-color=0000ff&message=Good%20%Luck%21
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/compositions/wrapped-present/assets/sample-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diarmidmackenzie/aframe-components/1dfa2f24b93dd68ff1f5fbaec558e28310db484c/compositions/wrapped-present/assets/sample-image.png
--------------------------------------------------------------------------------
/compositions/wrapped-present/lib/TextGeometry.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Text = 3D Text
3 | *
4 | * parameters = {
5 | * font: , // font
6 | *
7 | * size: , // size of the text
8 | * height: , // thickness to extrude text
9 | * curveSegments: , // number of points on the curves
10 | *
11 | * bevelEnabled: , // turn on bevel
12 | * bevelThickness: , // how deep into text bevel goes
13 | * bevelSize: , // how far from text outline (including bevelOffset) is bevel
14 | * bevelOffset: // how far from text outline does bevel start
15 | * }
16 | */
17 |
18 |
19 | const ExtrudeGeometry = THREE.ExtrudeGeometry;
20 |
21 |
22 | class TextGeometry extends ExtrudeGeometry {
23 |
24 | constructor( text, parameters = {} ) {
25 |
26 | const font = parameters.font;
27 |
28 | if ( font === undefined ) {
29 |
30 | super(); // generate default extrude geometry
31 |
32 | } else {
33 |
34 | const shapes = font.generateShapes( text, parameters.size );
35 |
36 | // translate parameters to ExtrudeGeometry API
37 |
38 | parameters.depth = parameters.height !== undefined ? parameters.height : 50;
39 |
40 | // defaults
41 |
42 | if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
43 | if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
44 | if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
45 |
46 | super( shapes, parameters );
47 |
48 | }
49 |
50 | this.type = 'TextGeometry';
51 |
52 | }
53 |
54 | }
55 |
56 |
57 | THREE.TextGeometry = TextGeometry;
58 | //export { TextGeometry };
--------------------------------------------------------------------------------
/compositions/wrapped-present/src/apply-url-params.js:
--------------------------------------------------------------------------------
1 | // This is run when the page is loaded, to customize the scene based on URL parameters.
2 | // Assumes CONFIG global variable is alredy declared.
3 |
4 | const queryString = window.location.search;
5 | const urlParams = new URLSearchParams(queryString);
6 |
7 | const giftUrl = urlParams.get('gift-url')
8 | const boxColor = urlParams.get('box-color')
9 | const ribbonColor = urlParams.get('ribbon-color')
10 | const message = urlParams.get('message')
11 |
12 | if (boxColor) {
13 | CONFIG.boxColor = "#" + boxColor
14 | }
15 |
16 | if (ribbonColor) {
17 | CONFIG.ribbonColor = "#" + ribbonColor
18 | }
19 |
20 | if (giftUrl) {
21 | CONFIG.giftUrl = giftUrl;
22 | }
23 |
24 | if (message) {
25 | CONFIG.message = message;
26 | }
27 |
--------------------------------------------------------------------------------
/docs/utility-components.md:
--------------------------------------------------------------------------------
1 | ## Utility Components
2 |
3 | A selection of simple utility components, used in various examples
4 |
5 |
6 |
7 | ### scale-on-hover
8 |
9 | This component scales an entity by 20% on the `mouseenter` event, and shrinks it back to normal size on the `mouseleave` event
10 |
11 | Used in various examples, including:
12 |
13 | - [polygon-wireframe.html](https://diarmidmackenzie.github.io/aframe-components/component-usage/polygon-wireframe.html)
14 |
15 | Code: [scale-on-hover.js](https://github.com/diarmidmackenzie/aframe-components/blob/main/components/scale-on-hover.js)
16 |
17 | Install:
18 |
19 |
20 |
21 |
22 |
23 | ### hide-on-hover
24 |
25 | This component hides an entity on the `mouseenter` event, and shows it again on the `mouseleave` event
26 |
27 | Used in various examples, including:
28 |
29 | - [raycaster-thresholds.html](https://diarmidmackenzie.github.io/aframe-components/component-usage/raycaster-thresholds.html)
30 |
31 | Code: [hide-on-hover.js](https://github.com/diarmidmackenzie/aframe-components/blob/main/components/hide-on-hover.js)
32 |
33 | Install:
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 |
2 | .code-link {
3 | position: fixed;
4 | right: 50px;
5 | top: 50px;
6 | width: 70px;
7 | height: 70px;
8 | border-radius: 50%;
9 | display: flex;
10 | background: white;
11 | justify-content: center;
12 | align-items: center;
13 | font-size: 20px;
14 | text-decoration: none;
15 | text-align: center;
16 | color: black;
17 | font-family: courier;
18 | font-weight: bold;
19 | z-index: 10;
20 | }
21 |
22 | .text-overlay {
23 | background: black;
24 | color: white;
25 | width: 60%;
26 | position: absolute;
27 | top: 10px;
28 | right: 150px;
29 | z-index: 10;
30 | font-size: 20px;
31 | font-family: arial
32 | }
33 |
34 | .gui {
35 | position: absolute;
36 | top: 150px;
37 | right: 10px;
38 | }
39 |
40 | .buttons {
41 | position: absolute;
42 | top: 150px;
43 | right: 10px;
44 | display: flex;
45 | flex-direction: column;
46 | gap: 10px;
47 | z-index: 10;
48 | }
--------------------------------------------------------------------------------