├── .gitignore ├── API.md ├── CLA.md ├── CONTRIBUTING.md ├── CopyrightNotice.md ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── LICENSE.txt ├── README.md ├── _config-develop.yml ├── _config-master.yml ├── _config-test.yml ├── dist ├── argon-aframe.js └── argon-aframe.min.js ├── examples ├── _headers ├── basic │ └── index.html ├── build.js ├── geoposition │ └── index.html ├── index.html ├── main.js ├── panorama │ ├── index.html │ └── panoramas │ │ ├── aqui.jpg │ │ ├── cent.jpg │ │ ├── high.jpg │ │ ├── pied.jpg │ │ └── woc.jpg ├── resources │ ├── cesium │ │ └── Assets │ │ │ └── IAU2006_XYS │ │ │ ├── IAU2006_XYS_0.json │ │ │ ├── IAU2006_XYS_1.json │ │ │ ├── IAU2006_XYS_10.json │ │ │ ├── IAU2006_XYS_11.json │ │ │ ├── IAU2006_XYS_12.json │ │ │ ├── IAU2006_XYS_13.json │ │ │ ├── IAU2006_XYS_14.json │ │ │ ├── IAU2006_XYS_15.json │ │ │ ├── IAU2006_XYS_16.json │ │ │ ├── IAU2006_XYS_17.json │ │ │ ├── IAU2006_XYS_18.json │ │ │ ├── IAU2006_XYS_19.json │ │ │ ├── IAU2006_XYS_2.json │ │ │ ├── IAU2006_XYS_20.json │ │ │ ├── IAU2006_XYS_21.json │ │ │ ├── IAU2006_XYS_22.json │ │ │ ├── IAU2006_XYS_23.json │ │ │ ├── IAU2006_XYS_24.json │ │ │ ├── IAU2006_XYS_25.json │ │ │ ├── IAU2006_XYS_26.json │ │ │ ├── IAU2006_XYS_27.json │ │ │ ├── IAU2006_XYS_3.json │ │ │ ├── IAU2006_XYS_4.json │ │ │ ├── IAU2006_XYS_5.json │ │ │ ├── IAU2006_XYS_6.json │ │ │ ├── IAU2006_XYS_7.json │ │ │ ├── IAU2006_XYS_8.json │ │ │ └── IAU2006_XYS_9.json │ ├── css │ │ ├── font-awesome.css │ │ └── font-awesome.min.css │ ├── datasets │ │ ├── StonesAndChips.dat │ │ └── StonesAndChips.xml │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 │ ├── js │ │ └── aframe-look-at-component.js │ ├── models │ │ └── tree1 │ │ │ ├── tex │ │ │ └── shadow-circle.png │ │ │ └── tree1.dae │ ├── splash.css │ ├── style.css │ └── textures │ │ └── buzz-pin.png ├── vuforia-aframe-logo │ ├── app.css │ ├── app.js │ ├── index.html │ └── key.txt └── vuforia │ ├── app.css │ ├── app.js │ ├── index.html │ └── key.txt ├── package.json ├── src ├── ar-components.js ├── ar-referenceframe.js ├── ar-scene.js ├── ar-vuforia.js ├── arframe.css ├── css-object.js ├── index.js ├── panorama-reality.js ├── shadow-material.js └── stage-geolocation.js └── tests ├── __init.test.js ├── helpers.js ├── index.test.js └── karma.conf.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | gh-pages 3 | _site -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | # Argon-AFrame Documentation 2 | 3 | This package provides a collection of entities and components for integrating Argon and AFrame. 4 | 5 | # Entities 6 | 7 | ## AR Scene 8 | 9 | An ar-scene is represented by the `` element, which is used instead of the 10 | regular `` element. The ar-scene is the global root 11 | object, and all [entities][entity] are contained within the scene. 12 | 13 | The scene inherits from the [`Entity`][entity] class so it inherits all of its 14 | properties, its methods, the ability to attach components, and the behavior to 15 | wait for all of its child nodes (e.g., `` and ``) to load 16 | before kicking off the render loop. 17 | 18 | It behaves similarly to the `` except that it uses `argon.js` as it's rendering 19 | framework, instead of WebVR. 20 | 21 | Entities within an ar-scene are positioned in Argon's local coordinate frame, which 22 | is arbitrary and can change over time as the user moves. Therefore, any entity 23 | should be attached to some Argon frame of reference (see the `referenceframe` 24 | component, and the `` and `` primitives below.) 25 | 26 | ### Example 27 | 28 | ```html 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | ``` 39 | 40 | ### Properties 41 | 42 | | Name | Description | 43 | |---------------|---------------------------------------------------------------------------| 44 | | behaviors | Array of components with tick methods that will be run on every frame. | 45 | | camera | Active three.js camera. Set from argon's camera each frame. | 46 | | isArgon | `true` since this is an argon scene. | 47 | | isScene | `true` since this is a scene object. | 48 | | isMobile | Whether or not environment is detected to be mobile. | 49 | | object3D | [`THREE.Scene`][scene] object. | 50 | | renderer | Active `THREE.WebGLRenderer`. | 51 | | cssRenderer | Active `THREE.CSS3DArgonRenderer` (if CSS3DArgonRenderer.js included) | 52 | | hudRenderer | Active `THREE.CSS3DArgonHUD` (if CSS3DArgonHUD.js included) | 53 | | renderStarted | Whether scene is rendering. | 54 | | argonApp | The Argon object, non-null when initialized. | 55 | | systems | Instantiated [systems][systems]. | 56 | | time | Global uptime of scene in seconds. | 57 | 58 | ### Methods 59 | 60 | | Name | Description | 61 | |---------|------------------------------------------------------------------------------------------------------------------------| 62 | | reload | Revert the scene to its original state. | 63 | 64 | ### Events 65 | 66 | | Name | Description | 67 | |--------------|-------------------------------------| 68 | | enter-vr | User has entered the Argon app's stereo viewer mode. | 69 | | exit-vr | User has exited the Argon app's stereo viewer mode. | 70 | | loaded | All nodes have loaded. | 71 | | renderstart | Render loop has started. | 72 | | argon-initialized | Argon has been initialized, including the rendering system | 73 | 74 | ### Scene Components 75 | 76 | Components can be attached to the scene as well as entities: 77 | 78 | ```html 79 | 80 | ``` 81 | 82 | A-Frame ships with a few components to configure the scene, although many of them are not useful 83 | for `` (e.g., keyboard-shortcuts, vr-mode-ui) because they rely on the `` 84 | renderer implementation. Experimentation will tell you if any particular component works. 85 | 86 | AR-specific components are discussesd below. 87 | 88 | ### Running Content Scripts on the Scene 89 | 90 | When running JavaScript on the scene, wait for it to finish loading first: 91 | 92 | ```js 93 | var scene = document.querySelector('ar-scene'); 94 | 95 | if (scene.hasLoaded) { 96 | run(); 97 | } else { 98 | scene.addEventListener('loaded', run); 99 | } 100 | 101 | function run () { 102 | var entity = scene.querySelector('ar-entity'); 103 | entity.setAttribute('material', 'color', 'red'); 104 | } 105 | ``` 106 | 107 | # Systems 108 | 109 | We define one system, `vuforia`, to manage the Vuforia tracking system. 110 | 111 | # Components 112 | 113 | ## Reference Frame 114 | 115 | The `referenceframe` component allows the position and/or orientation of an entity 116 | to be specified using one of Argon's frames of reference. These reference frames 117 | may be pre-set by the system (e.g., the `ar.user` frame represents the user), defined 118 | by a custom Argon reality, defined on-the-fly by the Vuforia tracking system (for 119 | each of the trackable targets) or defined by the programmer. 120 | 121 | Reference frames are specified using [Cesium Entities](http://cesiumjs.org), with the 122 | addition that Argon's Entities can be specified in relation to other entities, not just 123 | the `FIXED` and `INERTIAL` reference frames used by Cesium. Each reference frame 124 | has a name: `FIXED, `INERTIAL` or the `name` of the Entity. The typical use of 125 | a referenceframe component would look like this: 126 | 127 | ```html 128 | 129 | 130 | ``` 131 | 132 | As a convenience, the `referenceframe` component allows a geospatial coordinate to be 133 | specified using longitude and latitude. Frame's created this way are immediately converted 134 | to Cesium `FIXED` coordinates (which are specified in meters relative to the center of 135 | the earth). To do this, the `lla` property is set, and the parent is forced to `FIXED`. 136 | 137 | ```html 138 | 139 | 140 | ``` 141 | 142 | If a `referenceframe` component is attached to an entity that is not at the root of 143 | the ``, the parent transforms are ignored and the entity is still positioned 144 | as specified by the `referenceframe`. This allows entities to be grouped together for 145 | semantic or other organizational reasons, but positioned correctly. 146 | 147 | ### Properties 148 | 149 | | Property | Description | Default Value | 150 | |------------|---------------------------------------------------------------------------------------------------------------------------------|---------------| 151 | | parent | The reference frame that this entity should be positioned relative to. | FIXED | 152 | | lla | The logitude, latitude and (optional) altitude of the entity. | ignored unless set | 153 | | userotation | Should the entity rotation be set from this reference frame. | true | 154 | | useposition | Should the entity position be set from this reference frame. | true | 155 | 156 | ## Vuforia Key 157 | 158 | The `vuforiakey` component can be added to the `` entity to specify the Vuforia 159 | license key, if vuforia is needed. The property of the component is a reference to a DOM element 160 | that is either a `` or some other DOM element. If it's an asset item, the 161 | key will be stored in a separate file on the server and the path specified as a property of the 162 | asset item. The element is a DOM element, the key will be stored directly in the HTML file. 163 | 164 | ```html 165 | 166 | 167 | 168 | 169 | 170 | ``` 171 | Specifying a key causes vuforia to be immediately initialized with that key. 172 | 173 | ### Properties 174 | 175 | The `vuforiakey` component takes one property. 176 | 177 | | Description | Default Value | 178 | |------------|---------------------------------------------------------------------------------------------------------------------------------|---------------| 179 | | The DOM element specifying the key. | A DOM element reference | 180 | 181 | ### Events 182 | 183 | When a key is specified, Argon will attempt to initialize vuforia with the key. The 184 | following events may be emitted. 185 | 186 | | Name | Description | 187 | |--------------|-------------------------------------| 188 | | argon-vuforia-not-available | This platform does not support vuforia. | 189 | | argon-vuforia-initialized | Vuforia successfully initialized with this key. | 190 | | argon-vuforia-initialization-failed | Vuforia not initialized, see the event.detail.error for why. | 191 | 192 | ## Vuforia Datasets 193 | 194 | The `vuforiadataset` component is added to the `` entity to specify the location 195 | of a Vuforia dataset. Argon will attempt to immediately download the dataset (after vuforia 196 | is successfully initialized with the key provided above). 197 | 198 | Multiple components can be specified with the multiple component syntax 199 | (`vuforiadataset__` plus a name). The name extension (after the `__`) becomes the identity 200 | of that dataset, and is used to create the names of the vuforia targets. The name extension 201 | must be lower case. For example, in this example: 202 | 203 | ```html 204 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | ``` 215 | 216 | the dataset has the identity `stonesandchips`, and so it's targets are available as 217 | reference frames `vuforia.stonesandchips.` (where, in this dataset, the 218 | targets are `stones` and `chips`.) If no dataset name is specified, the name `default_dataset` 219 | is used. 220 | 221 | If the `active` property is true, Argon will attempt to load the dataset into the Vuforia 222 | tracking system. 223 | 224 | ### Properties 225 | 226 | | Property | Description | Default Value | 227 | |------------|---------------------------------------------------------------------------------------------------------------------------------|---------------| 228 | | src | The URL of the dataset. | must be specified | 229 | | active | Is this dataset active. | true | 230 | 231 | ### Events 232 | 233 | When a dataset component is attached to the ``, Argon will attempt to download it 234 | and possibly activate it, which will trigger one or more events. 235 | 236 | | Name | Description | 237 | |--------------|-------------------------------------| 238 | | argon-vuforia-dataset-downloaded | Dataset was successfully downloaded. | 239 | | argon-vuforia-dataset-download-failed | Dataset not downloaded, see the event.detail.error for why. | 240 | | argon-vuforia-dataset-loaded | The dataset was successfully loaded into Vuforia. event.detail.trackables has an object of trackables for this dataset | 241 | | argon-vuforia-dataset-load-failed | Dataset not loaded, see the event.detail.error for why. | 242 | 243 | ## CSS Object 244 | 245 | The `` supports an optional CSS renderer, that has been designed to work with 246 | Argon's stereo viewer mode. The CSS content is positioned in front of the WebGL content 247 | (since the web browsers do not allow CSS and WebGL content to be rendered with a shared 248 | 3D depth bufffer). 249 | 250 | To add an HTML/CSS element to the 3D scene, the `css-object` component is used. It takes 251 | one or two CSS DOM references as it's properties, specifying the DOM elements to position in 252 | in 3D. If only one DOM element is provided, it will be `clone()`ed when Argon displays 253 | the element in stereo (since one DOM element can only be displayed in one place.) If a second 254 | element is provided, it will be used for the right view in stereo mode. 255 | 256 | The CSS elements are sized such at 1 units (1px in this example) is 1 meter, so the elements 257 | will probably have to be scaled appropriately. Since the web create the visual detail of a 258 | DOM element based on it's size, with a 100 unit element having ten times the resolution as 259 | a 10 unit element, you should size and scale your DOM elements to balance detail vs rendering 260 | cost (higher resolution elements yield higher resolution textures and are slower to render). 261 | 262 | ```css 263 | .boxface { 264 | opacity: 0.5; 265 | width: 90px; 266 | height: 90px; 267 | font-size: 25px; 268 | text-align: center; 269 | color: black; 270 | background: rgba(127,255,255,0.85); 271 | outline: 5px solid rgba(12,25,25,1.0); 272 | border: 0px; 273 | margin-bottom: 0px; 274 | padding: 0px 0px; 275 | } 276 | ``` 277 | 278 | ```html 279 | 283 | 284 | 285 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | ``` 296 | 297 | ### Properties 298 | 299 | | Property | Description | Default Value | 300 | |------------|---------------------------------------------------------------------------------------------------------------------------------|---------------| 301 | | div | The HTML element reference for the div. | must be specified | 302 | | div2 | The optional element element reference for the right stereo div. | null | 303 | 304 | # Custom Realities 305 | 306 | The `desiredreality` component is added to the `` entity to specify that a custom 307 | reality should be used. Argon will attempt to immediately install the custom reality. 308 | 309 | The properties of the component specify a name for the reality (that will appear in Argon4's 310 | reality chooser) and a URL for reality HTML file. 311 | 312 | ```html 313 | 314 | 315 | ``` 316 | 317 | Removing the attribute reverts to the default reality for the browser (NOTE: a known bug in argon.js prevents this from working, 318 | it will be fixed soon.) 319 | 320 | ### Properties 321 | 322 | The `desiredreality` component takes two properties. 323 | 324 | | Property | Description | Default Value | 325 | |------------|---------------------------------------------------------------------------------------------------------------------------------|---------------| 326 | | src | The URL of the reality. | must be specified | 327 | | name | A human readable name for this reality. | "default" | 328 | 329 | ## Panorama Reality 330 | 331 | The `panorama` component is added to the `` entity to specify a geopositioned panoramic image for the custom 332 | panorama reality (the panorama reality implements the "ael.gatech.panorama" reality protocol). 333 | 334 | Multiple components can be specified with the multiple component syntax 335 | (`panorama__` plus a name). The name extension (after the `__`) becomes the identity 336 | of that panorama, and is used to show the panorama by emitting a "showpanorama" event on 337 | the ``. For example, in this example: 338 | 339 | ```html 340 | 342 | 343 | ``` 344 | the panorama has the identity `aqui`, and so it can be shown in the panoramic reality by emiting an event: 345 | ``` 346 | var arScene = document.querySelector('ar-scene'); 347 | var menu = document.getElementById('menu'); 348 | 349 | var button = document.createElement('button'); 350 | button.textContent = "Aquarium"; 351 | menu.appendChild(button); 352 | // when a button is tapped, have the reality fade in the corresponding panorama 353 | button.addEventListener('click', function () { 354 | arScene.sceneEl.emit('showpanorama', { name: "aqui" }); 355 | }); 356 | ``` 357 | 358 | If the `initial` property is true, argon.js will attempt to load the panorama when the 359 | panorama reality is activated. 360 | 361 | ### Properties 362 | 363 | | Property | Description | Default Value | 364 | |------------|---------------------------------------------------------------------------------------------------------------------------------|---------------| 365 | | src | The URL of the panoramic image. | must be specified | 366 | | initial | Is this panorama shown as the first panorama. | false | 367 | | lla | The logitude, latitude and (optional) altitude of the entity. | required | 368 | | offsetdegrees | The yaw orientation offset, to align the panorama with north | 0 | 369 | | easing | Tween.js easing function for transitioning to this panorama | "Quadratic.InOut" | 370 | | duration | duration of the transition in milliseconds | 500 | 371 | 372 | ## Fixed Size 373 | 374 | A common need in geospatial AR is to size elements (such as labels) a constant size no 375 | matter where in 3D they appear. The `fixedsize` component does that. It takes one 376 | property, representing how big 1m in the entity should be in CSS pixels on the screen. The object is then scaled to that size each frame taking the distance 377 | from the camera into account. 378 | 379 | ```html 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | ``` 392 | 393 | In this example, the `#buzzpin` plane would be approximately 80 pixels tall on the screen. 394 | 395 | ### Properties 396 | 397 | | Description | Default Value | 398 | |---------------------------------------------------------------------------------------------------------------------------------|---------------| 399 | | The scale applied to the element if it was 1 meter from the camera. | 1 | 400 | 401 | 402 | ## Distance Trigger 403 | 404 | A common need in AR and VR is to know when the viewer is within a certain distance of some location in the world. The `trigger` component can be attached to an entity, and when the camera is within a certain distance (specified by the `radius` attribute) the component will emit an event (specified by the `event` attribute). 405 | 406 | ```html 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | ``` 416 | 417 | In this example, when the user (camera) is within 100 meters of the specified LLA, the event will be emitted. Similarly, when the user (camera) moves further than 100 meters away, the event will be emitted again. The event detail can be used to decide if it was an enter or exit event. 418 | 419 | Multiple triggers can be attached to an entity. If `trigger__name` is attached, the event emitted will name `name` in the event detail `name` property. 420 | 421 | ### Properties 422 | 423 | | Property | Description | Default Value | 424 | |-----------|----------------------------------------------------------------------------------------------------------------------|---------------| 425 | |raduis|The distance of the trigger point from the entity to the camera. | 1 | 426 | |event| The name of the event to emit.| "trigger" | 427 | |initial|Emit an event at the start based on the initial distance|false| 428 | 429 | ### Events 430 | 431 | When a trigger is fired, it will emit the following event. 432 | 433 | | Name | Description | 434 | |--------------|-------------------------------------| 435 | | `eventname` | A trigger event containing event detail {name: string, inside: boolean, distanceSquared: number} | 436 | 437 | ## Visibility Tracking 438 | 439 | Argon's reference frames can be defined or undefined over time. For example, a visual target 440 | being tracked by Vuforia will become lost if the user is not pointing the camera at the the 441 | target. Similarly, until Argon receives the first GPS report, the `ar.user` reference frame 442 | is undefined. 443 | 444 | The `trackvisibility` component will set the `object3D.visible` property based on the 445 | status of the reference frame used by the scene. If the entity does not have a `referenceframe` 446 | compoent, this component does nothing. 447 | 448 | The component has one property, a boolean, that enables or disables it. If the property is 449 | enabled, it sets/resets the `object3D.visible` property as the status of the reference frame 450 | changes, otherwise it does nothing. 451 | 452 | A common use would be to have the entity and it's children only be visible when the 453 | reference frame it is attached to is known. We can modify the vuforia snippet above to 454 | behave this way by adding a `trackvisibility` component, and initializing it's `visible` 455 | component to false. 456 | 457 | ```html 458 | 460 | 461 | 462 | 463 | 464 | 466 | 467 | 468 | 469 | ``` 470 | 471 | ### Properties 472 | 473 | | Description | Default Value | 474 | |---------------------------------------------------------------------------------------------------------------------------------|---------------| 475 | | If this component is active or not, and changes the object3D.visible value. | true | 476 | 477 | # Primitives 478 | 479 | We define a set of primitives for some common AR use cases. 480 | 481 | ## AR Camera 482 | 483 | An Argon-specific camera is created with the `` tag. If one is not in your 484 | scene, one will be created for you. The camera entity has a `camera` component on it, as 485 | well as a `referenceframe="parent: ar.user"` component to attach the component to the 486 | user's reference frame. If you would like content to be positioned relative to the 487 | user and move with them, you should make it a child of this entity. 488 | 489 | ## Geopose 490 | 491 | The `` primitive creates an entity with a `referenceframe` component that 492 | defines the position and/or rotation of the entity by an LLA (longitude, lattitude, altitude). 493 | The `userotation` and `useposition` properties can be set to true (the default) to have 494 | this entity set it's rotation and/or position from the referenceframe. Often, the position 495 | is used but the rotation may be left to be specified in the local coordinates. 496 | 497 | ## Frame of Reference 498 | 499 | The `` primitive creates an entity with a `referenceframe` component that 500 | defines the position and/or rotation of the entity relative to some know Argon frame of 501 | reference. `ar.user` is a frame that represents the user (other frames may be added 502 | in the future). The Vuforia tracker specifies other frames of reference that may be used. 503 | The `userotation` and `useposition` properties can be set to true (the default) to have 504 | this entity set it's rotation and/or position from the referenceframe. -------------------------------------------------------------------------------- /CLA.md: -------------------------------------------------------------------------------- 1 | ## Georgia Tech Research Corporation 2 | ### Individual Contributor License Agreement ("Agreement") 3 | 4 | #### (*CLA can be signed electronically [using this form](https://docs.google.com/forms/d/1wl5Rg7ishq6nsfbMVoif6322NOzhjdyryHvxmiCQITc/viewform?c=0&w=1&usp=mail_form_link)*) 5 | 6 | Thank you for your interest in Georgia Tech Research Corporation (“GTRC”) software. In order to clarify the intellectual property license granted with Contributions from any person or entity, GTRC must have a Contributor License Agreement ("CLA") on file that has been signed by each Contributor, indicating agreement to the license terms below. 7 | 8 | This license is for your protection as a Contributor as well as the protection of GTRC and its users; it does not change your rights to use your own Contributions for any other purpose. 9 | 10 | If you have not already done so, please complete and sign this CLA. **You may sign this CLA electronically [using this form](https://docs.google.com/forms/d/1wl5Rg7ishq6nsfbMVoif6322NOzhjdyryHvxmiCQITc/viewform?c=0&w=1&usp=mail_form_link)**, or you may print, then scan and email a pdf file of this Agreement to industry@gatech.edu. If necessary, send an original signed Agreement to Georgia Tech Research Corporation, Attn: Director of Licensing, 505 10th Street NW, Atlanta, Georgia 30332-0415, U.S.A. 11 | 12 | Please read this document carefully before signing and keep a copy for your records. 13 | 14 | Full name: ______________________________________________________ 15 | 16 | Mailing Address: ________________________________________________ 17 | 18 | Mailing Address (cont'd): _______________________________________ 19 | 20 | Country: ______________________________________________________ 21 | 22 | Telephone: ______________________________________________________ 23 | 24 | E-Mail: ______________________________________________________ 25 | 26 | Github id: ______________________________________________________ 27 | 28 | 29 | 30 | 31 | You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GTRC. In return, GTRC shall not use Your Contributions in a way that is contrary to the public benefit or inconsistent with its nonprofit status and bylaws in effect at the time of the Contribution. Except for the license granted herein to GTRC and recipients of software distributed by GTRC, You reserve all right, title, and interest in and to Your Contributions. 32 | 33 | 1. Definitions. 34 | "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GTRC. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 35 | "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GTRC for inclusion in, or documentation of, any of the products owned or managed by GTRC (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GTRC or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GTRC for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." 36 | 37 | 2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to GTRC and to recipients of software distributed by GTRC a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works. 38 | 39 | 3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to GTRC and to recipients of software distributed by GTRC a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed. 40 | 41 | 4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to GTRC, or that your employer has executed a separate license agreement with GTRC. 42 | 43 | 5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions. 44 | 45 | 6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. 46 | 47 | 7. Should You wish to submit work that is not Your original creation, You may submit it to GTRC separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as 48 | "Submitted on behalf of a third-party: [named here]". 49 | 50 | 8. You agree to notify GTRC of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect. 51 | 52 | Please sign: __________________________________ Date: ________________ 53 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Argon-AFrame 2 | 3 | :+1::tada: First off, thanks for taking the time to contribute! :tada::+1: 4 | 5 | #### Table of Contents 6 | 7 | [How can I help?](#how-can-i-help) 8 | * [Submitting an Issue](#submitting-an-issue) 9 | * [Opening a Pull Request](#opening-a-pull-request) 10 | 11 | [:sparkles:Style:sparkles:](#style-guidelines) 12 | * [Branching Scheme](#our-branching-model) 13 | * [Typescript](#typescript-style) 14 | 15 | [Tests](#testing) 16 | 17 | ## How can I help? 18 | 19 | You can help in so many ways! 20 | Whether it's asking questions on our slack or on StackOverflow or even contributing code, we love any help we can get! 21 | 22 | ### Submitting an Issue 23 | 24 | If you think you've found a bug, first search the issues. If an issue already exists, please add a comment expressing your interest and any additional information. This helps us prioritize issues. 25 | 26 | If a related issue does not exist, submit a new one. Please be concise and include as much of the following information as is relevant: 27 | * Minimum amount of sample code or steps to demonstrate or reproduce the issue 28 | * Screenshot or video capture if appropriate. 29 | * Your device operating system and version, the Argon Browser version, and the argon.js version. Are they all up-to-date? Is the issue specific to one of them? 30 | * Did this work in a previous version? 31 | * Ideas for how to fix or workaround the issue. Also mention if you are willing to help fix it. If so, we can often provide guidance and the issue may get fixed more quickly with your help. 32 | 33 | ### Opening a Pull Request 34 | 35 | In general, you should make your pull request against the `develop` branch. 36 | You can use the following prefixes in your branch name to make the purpose clear: 37 | * `fix/` 38 | * `feat/` 39 | 40 | Pull request tips 41 | * If your pull request fixes an existing issue, include a link to the issue in the description (like this: [#1]). 42 | * If your pull request needs additional work, include a [task list](https://github.com/blog/1375%0A-task-lists-in-gfm-issues-pulls-comments). 43 | * Once you are done making new commits to address feedback, add a comment to the pull request such as `"this is ready"` since GitHub doesn't notify us about commits. 44 | 45 | 46 | ## Style Guidelines 47 | 48 | The general style guidelines are as follows: 49 | 50 | * We use 4 spaces to indent **all** source files 51 | * No trailing spaces 52 | 53 | ### Our Branching Model 54 | 55 | We follow a pretty simple branching model. 56 | 57 | Our primary working branh is the `develop` branch. Once in a while, the `develop` branch is 58 | tagged with a new release version and merged into the master branch. 59 | 60 | ## Testing 61 | 62 | In general, all our tests should run by executing `npm test`. 63 | -------------------------------------------------------------------------------- /CopyrightNotice.md: -------------------------------------------------------------------------------- 1 | ## Copyright 2016 Georgia Tech Research Corporation 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # Hello! This is where you manage which Jekyll version is used to run. 2 | # When you want to use a different version, change it below, save the 3 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 4 | # 5 | # bundle exec jekyll serve 6 | # 7 | # This will help ensure the proper Jekyll version is running. 8 | # Happy Jekylling! 9 | source 'https://rubygems.org' 10 | gem "jekyll", "3.4.3" 11 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.5.1) 5 | public_suffix (~> 2.0, >= 2.0.2) 6 | colorator (1.1.0) 7 | ffi (1.9.18) 8 | forwardable-extended (2.6.0) 9 | jekyll (3.4.3) 10 | addressable (~> 2.4) 11 | colorator (~> 1.0) 12 | jekyll-sass-converter (~> 1.0) 13 | jekyll-watch (~> 1.1) 14 | kramdown (~> 1.3) 15 | liquid (~> 3.0) 16 | mercenary (~> 0.3.3) 17 | pathutil (~> 0.9) 18 | rouge (~> 1.7) 19 | safe_yaml (~> 1.0) 20 | jekyll-sass-converter (1.5.0) 21 | sass (~> 3.4) 22 | jekyll-watch (1.5.0) 23 | listen (~> 3.0, < 3.1) 24 | kramdown (1.13.2) 25 | liquid (3.0.6) 26 | listen (3.0.8) 27 | rb-fsevent (~> 0.9, >= 0.9.4) 28 | rb-inotify (~> 0.9, >= 0.9.7) 29 | mercenary (0.3.6) 30 | pathutil (0.14.0) 31 | forwardable-extended (~> 2.6) 32 | public_suffix (2.0.5) 33 | rb-fsevent (0.9.8) 34 | rb-inotify (0.9.8) 35 | ffi (>= 0.5.0) 36 | rouge (1.11.1) 37 | safe_yaml (1.0.4) 38 | sass (3.4.23) 39 | 40 | PLATFORMS 41 | ruby 42 | 43 | DEPENDENCIES 44 | jekyll (= 3.4.3) 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright © 2016 Blair MacIntyre. 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # argon-aframe 2 | 3 | A collection of components, entities and systems to integrate [A-Frame](https://aframe.io) with [argon.js](http://argonjs.io/), so augmented reality content for the Argon web browser can be created with A-Frame. 4 | 5 | ## A note about using https for development 6 | 7 | More and more, modern web browsers demand that you use https:// instead of http://. You cannot, for example, use the web location APIs, or access video via WebRTC, over http connections on many browsers. If you want to do development using https and node.js use the _devssl_ target (used by doing `npm run devssl`). 8 | 9 | ## Documentation 10 | 11 | To see documentation of the collection of Entities and Components that link Argon and AFrame, see the [API Documentation](API.md). 12 | 13 | ## Builds 14 | 15 | To use the latest stable build of Argon-AFrame, include [`argon-aframe.min.js`](https://rawgit.com/argonjs/argon-aframe/master/dist/argon-aframe.js): 16 | 17 | ```js 18 | 19 | 20 | 21 | ``` 22 | 23 | To check out the stable and master builds, see the [`dist/` folder](dist/). 24 | 25 | ## Local Development 26 | 27 | ```sh 28 | git clone https://github.com/argonjs/argon-aframe.git # Clone the repository. 29 | cd argon-aframe && npm install # Install dependencies. 30 | npm run devsite # update build.js and genereate a local development site in _sites 31 | npm run dev # Start the local development server. 32 | ``` 33 | 34 | And open in your browser **[http://localhost:8001](http://localhost:8001)**. 35 | 36 | When you change the HTML files, you need to regenerate _site with `npm run devsite`. 37 | 38 | ### Generating Builds 39 | 40 | ```sh 41 | npm run dist 42 | ``` 43 | 44 | ## Questions 45 | 46 | For questions and support, [ask on one of our support channels](https://www.argonjs.io/#develop). 47 | 48 | ## Stay in Touch 49 | 50 | - To hang out with the community, join the argonjs slack ([see the slack-join link in our developer support links]](https://www.argonjs.io/#develop)). 51 | - [Follow @argonjs on Twitter](https://twitter.com/argonjs). 52 | 53 | ## Contributing 54 | 55 | Get involved! Check out the [Contributing Guide](CONTRIBUTING.md) for how to get started. 56 | 57 | ## License 58 | 59 | This program is free software and is distributed under an [Apache License](LICENSE). 60 | -------------------------------------------------------------------------------- /_config-develop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | port: 1237 3 | host: 0.0.0.0 4 | safe: false 5 | 6 | ### site serving configuration ### 7 | source: examples 8 | include: [_headers] 9 | timezone: null 10 | lsi: false 11 | markdown: kramdown 12 | 13 | keywords: "argon, aframe, augmented reality, web, javascript" 14 | 15 | argonjs: "https://rawgit.com/argonjs/argon/develop/dist/argon.js" 16 | aframejs: "https://aframe.io/releases/0.5.0/aframe.min.js" 17 | samples: "https://samples-develop.argonjs.io" 18 | argonaframejs: "../build.js" 19 | 20 | # argonjs: "https://unpkg.com/@argonjs/argon@1.1/dist/argon.min.js" 21 | # aframejs: "https://aframe.io/releases/0.5.0/aframe.min.js" 22 | # samples: "https://samples.argonjs.io" 23 | # argonaframejs: "https://rawgit.com/argonjs/argon-aframe/master/dist/argon-aframe.js" -------------------------------------------------------------------------------- /_config-master.yml: -------------------------------------------------------------------------------- 1 | --- 2 | port: 1237 3 | host: 0.0.0.0 4 | safe: false 5 | 6 | ### site serving configuration ### 7 | source: examples 8 | include: [_headers] 9 | timezone: null 10 | lsi: false 11 | markdown: kramdown 12 | 13 | keywords: "argon, aframe, augmented reality, web, javascript" 14 | 15 | # argonjs: "https://rawgit.com/argonjs/argon/develop/dist/argon.js" 16 | # aframejs: "https://aframe.io/releases/0.5.0/aframe.min.js" 17 | # samples: "https://samples-develop.argonjs.io" 18 | # argonaframejs: "../build.js" 19 | 20 | argonjs: "https://unpkg.com/@argonjs/argon@^1.2/dist/argon.js" 21 | aframejs: "https://aframe.io/releases/0.5.0/aframe.min.js" 22 | samples: "https://samples.argonjs.io" 23 | argonaframejs: "https://rawgit.com/argonjs/argon-aframe/master/dist/argon-aframe.js" -------------------------------------------------------------------------------- /_config-test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | port: 1237 3 | host: 0.0.0.0 4 | safe: false 5 | 6 | ### site serving configuration ### 7 | source: examples 8 | include: [_headers] 9 | timezone: null 10 | lsi: false 11 | markdown: kramdown 12 | 13 | keywords: "argon, aframe, augmented reality, web, javascript" 14 | 15 | argonjs: "https://rawgit.com/argonjs/argon/refactor-y-up/dist/argon.js" 16 | aframejs: "https://aframe.io/releases/0.5.0/aframe.min.js" 17 | samples: "https://samples-yup.netlify.com" 18 | argonaframejs: "../build.js" 19 | 20 | # argonjs: "https://unpkg.com/@argonjs/argon@1.1/dist/argon.min.js" 21 | # aframejs: "https://aframe.io/releases/0.5.0/aframe.min.js" 22 | # samples: "https://samples.argonjs.io" 23 | # argonaframejs: "https://rawgit.com/argonjs/argon-aframe/master/dist/argon-aframe.js" -------------------------------------------------------------------------------- /examples/_headers: -------------------------------------------------------------------------------- 1 | /panorama/panoramas/* 2 | Access-Control-Allow-Origin: "*" -------------------------------------------------------------------------------- /examples/basic/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | 5 | Hello, World! Argon + A-Frame 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 46 | 47 | 48 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | ' 71 | 72 | 73 | 74 | 78 | 79 | 80 | 81 | 82 | 96 | 97 | 106 | 107 | -------------------------------------------------------------------------------- /examples/geoposition/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | 5 | Geolocated content with Argon + A-Frame 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 50 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 98 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A-Frame Argon Components 5 | 6 | 33 | 34 | 35 |

Argon + A-Frame Examples

36 | 37 |

The A-Frame javascript library lets you create WebVR applications 38 | using custom DOM elements, allowing 3D content to be manipulated similarly to 2D HTML elements.

39 | 40 |

We have adapted A-Frame to work with Argon, creating a new ar-scene element and a number 41 | of entities and components to support AR. The documentation and source are on the github page.

42 | 43 | 50 |
51 |
52 | Fork me on GitHub 53 |
54 |
55 |

Hosting of this site provided by Netlify

56 | 57 | 66 | 67 | -------------------------------------------------------------------------------- /examples/main.js: -------------------------------------------------------------------------------- 1 | require('../src/ar-scene.js'); 2 | require('../src/ar-components.js'); 3 | require('../src/ar-referenceframe.js'); 4 | require('../src/css-object.js'); 5 | require('../src/ar-vuforia.js'); 6 | require('../src/panorama-reality.js'); -------------------------------------------------------------------------------- /examples/panorama/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | 5 | Panorama Reality with Argon + A-Frame 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 47 | 48 | 49 | 53 | 54 |

My Travel Blog

55 |
56 |
57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 |
75 |
76 |

77 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam venenatis volutpat diam, sodales lobortis leo lacinia quis. Donec laoreet purus placerat tristique auctor. In faucibus ullamcorper dolor, eu scelerisque lectus interdum quis. Nulla magna mi, gravida vel tellus sollicitudin, finibus pretium erat. Aliquam dignissim lorem sed blandit pretium. Pellentesque sollicitudin lacinia aliquet. Pellentesque pharetra nunc id mollis laoreet. Maecenas laoreet diam nec sapien iaculis, id viverra dui luctus. 78 |

79 |

80 | Nullam risus magna, condimentum scelerisque elementum vel, porttitor non diam. Nullam quis arcu eu velit facilisis rutrum nec ac neque. Fusce sollicitudin ullamcorper dapibus. Quisque volutpat leo eget imperdiet luctus. Aliquam pharetra sapien nibh, in luctus elit accumsan a. Praesent lacinia tincidunt pretium. Curabitur quis nulla ut arcu tincidunt commodo. Donec nec fermentum neque, sit amet pulvinar tortor. Sed in quam ante. Nam malesuada nisl nec velit tristique, sed sagittis massa cursus. Mauris sit amet egestas lectus. Cras a nulla enim. Curabitur leo libero, porttitor at justo vel, sagittis euismod lorem. Praesent ullamcorper sed ante vel congue. Proin eget augue in erat euismod aliquet. 81 |

82 |

83 | In quis erat non nunc euismod efficitur. Maecenas vitae dolor et ligula interdum aliquet sit amet in nibh. Pellentesque sit amet justo et leo elementum malesuada at ac nisi. Sed bibendum dui a dignissim ultricies. Suspendisse eget eleifend metus, quis viverra mauris. Nullam pulvinar lacinia sodales. Aliquam commodo faucibus ante sed congue. Donec faucibus risus sit amet viverra ultrices. Proin tellus orci, tincidunt eu egestas et, vulputate quis nisi. Sed vitae varius eros. 84 |

85 |

86 | Praesent pulvinar lorem sed tellus auctor consequat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In efficitur, risus sit amet scelerisque imperdiet, ante mauris molestie dolor, at finibus ex arcu a ex. Donec ligula nulla, ornare in lectus maximus, blandit sollicitudin sapien. Vivamus vel luctus orci, pellentesque volutpat metus. Quisque ultrices lacinia vestibulum. Donec nec tristique turpis. 87 |

88 |

89 | Duis gravida, enim quis ornare blandit, tortor metus dignissim ex, dapibus tincidunt erat urna vel enim. Donec mattis luctus neque et aliquet. Fusce at velit quam. Praesent vitae ligula tristique, tristique libero nec, viverra elit. Nulla hendrerit fringilla varius. Integer libero justo, tincidunt ac feugiat vitae, vehicula sed quam. Nam nibh ipsum, viverra ut pretium sed, pretium sed dolor. Integer semper tellus tincidunt, vestibulum lectus nec, vulputate purus. 90 |

91 |
92 | 93 | 148 | 149 | 158 | 159 | -------------------------------------------------------------------------------- /examples/panorama/panoramas/aqui.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/panorama/panoramas/aqui.jpg -------------------------------------------------------------------------------- /examples/panorama/panoramas/cent.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/panorama/panoramas/cent.jpg -------------------------------------------------------------------------------- /examples/panorama/panoramas/high.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/panorama/panoramas/high.jpg -------------------------------------------------------------------------------- /examples/panorama/panoramas/pied.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/panorama/panoramas/pied.jpg -------------------------------------------------------------------------------- /examples/panorama/panoramas/woc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/panorama/panoramas/woc.jpg -------------------------------------------------------------------------------- /examples/resources/datasets/StonesAndChips.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/resources/datasets/StonesAndChips.dat -------------------------------------------------------------------------------- /examples/resources/datasets/StonesAndChips.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/resources/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/resources/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /examples/resources/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/resources/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /examples/resources/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/resources/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /examples/resources/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/resources/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /examples/resources/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/resources/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /examples/resources/js/aframe-look-at-component.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) 10 | /******/ return installedModules[moduleId].exports; 11 | 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ exports: {}, 15 | /******/ id: moduleId, 16 | /******/ loaded: false 17 | /******/ }; 18 | 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | 22 | /******/ // Flag the module as loaded 23 | /******/ module.loaded = true; 24 | 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | 29 | 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | 36 | /******/ // __webpack_public_path__ 37 | /******/ __webpack_require__.p = ""; 38 | 39 | /******/ // Load entry module and return exports 40 | /******/ return __webpack_require__(0); 41 | /******/ }) 42 | /************************************************************************/ 43 | /******/ ([ 44 | /* 0 */ 45 | /***/ function(module, exports) { 46 | 47 | var debug = AFRAME.utils.debug; 48 | var coordinates = AFRAME.utils.coordinates; 49 | 50 | var warn = debug('components:look-at:warn'); 51 | var isCoordinate = coordinates.isCoordinate; 52 | 53 | delete AFRAME.components['look-at']; 54 | 55 | /** 56 | * Look-at component. 57 | * 58 | * Modifies rotation to either track another entity OR do a one-time turn towards a position 59 | * vector. 60 | * 61 | * If tracking an object via setting the component value via a selector, look-at will register 62 | * a behavior to the scene to update rotation on every tick. 63 | */ 64 | AFRAME.registerComponent('look-at', { 65 | schema: { 66 | src: { 67 | default: '', 68 | 69 | parse: function (value) { 70 | // A static position to look at. 71 | if (isCoordinate(value) || typeof value === 'object') { 72 | return coordinates.parse(value); 73 | } 74 | // A selector to a target entity. 75 | return value; 76 | }, 77 | 78 | stringify: function (data) { 79 | if (typeof data === 'object') { 80 | return coordinates.stringify(data); 81 | } 82 | return data; 83 | }, 84 | }, 85 | checkSrcEveryFrame: { 86 | default: false, 87 | }, 88 | updateWorldTransform: { 89 | default: false, 90 | } 91 | }, 92 | 93 | init: function () { 94 | this.target3D = null; 95 | this.vector = new THREE.Vector3(); 96 | }, 97 | 98 | /** 99 | * If tracking an object, this will be called on every tick. 100 | * If looking at a position vector, this will only be called once (until further updates). 101 | */ 102 | update: function () { 103 | var self = this; 104 | var target = self.data.src; 105 | var object3D = self.el.object3D; 106 | var targetEl; 107 | 108 | // No longer looking at anything (i.e., look-at=""). 109 | if (!target || (typeof target === 'object' && !Object.keys(target).length)) { 110 | return self.remove(); 111 | } 112 | 113 | // Look at a position. 114 | if (typeof target === 'object') { 115 | return object3D.lookAt(new THREE.Vector3(target.x, target.y, target.z)); 116 | } 117 | 118 | return this.updateTarget(target); 119 | }, 120 | 121 | updateTarget: function (target) { 122 | var self = this; 123 | 124 | // Assume target is a string. 125 | // Query for the element, grab its object3D, then register a behavior on the scene to 126 | // track the target on every tick. 127 | targetEl = this.el.sceneEl.querySelector(target); 128 | if (!targetEl) { 129 | warn('"' + target + '" does not point to a valid entity to look-at'); 130 | return; 131 | } 132 | if (!targetEl.hasLoaded) { 133 | return targetEl.addEventListener('loaded', function () { 134 | self.beginTracking(targetEl); 135 | }); 136 | } 137 | return self.beginTracking(targetEl); 138 | }, 139 | 140 | tick: function (t) { 141 | var self = this; 142 | var target = self.data.target; 143 | var object3D = self.el.object3D; 144 | var targetEl; 145 | 146 | // Track target object position. Depends on parent object keeping 147 | // global transforms up to state with updateMatrixWorld(). 148 | // In practice, this is handled by the renderer, but will result in 149 | // 150 | 151 | if (typeof self.data.target === 'string' && self.data.checkSrcEveryFrame) { 152 | targetEl = self.el.sceneEl.querySelector(target); 153 | if (!targetEl) { 154 | warn('"' + target + '" does not point to a valid entity to look-at'); 155 | this.target3D = null; 156 | return; 157 | } 158 | if (!targetEl.hasLoaded) { 159 | return targetEl.addEventListener('loaded', function () { 160 | self.beginTracking(targetEl); 161 | }); 162 | } else { 163 | self.beginTracking(targetEl); 164 | } 165 | } 166 | 167 | if (this.target3D) { 168 | this.vector.setFromMatrixPosition(this.target3D.matrixWorld); 169 | if (object3D.parent) { 170 | if (this.data.updateWorldTransform) { 171 | object3D.parent.updateMatrixWorld(); 172 | } 173 | object3D.parent.worldToLocal(this.vector); 174 | } 175 | return object3D.lookAt(this.vector); 176 | } 177 | }, 178 | 179 | beginTracking: function (targetEl) { 180 | this.target3D = targetEl.object3D; 181 | } 182 | }); 183 | 184 | /** 185 | * Billboard component. 186 | * 187 | * Modifies rotation to track the current camera, keeping the entity facing it 188 | * 189 | */ 190 | AFRAME.registerComponent('billboard', { 191 | init: function () { 192 | this.vector = new THREE.Vector3(); 193 | }, 194 | 195 | tick: function (t) { 196 | var self = this; 197 | var target = self.el.sceneEl.camera; 198 | var object3D = self.el.object3D; 199 | 200 | // make sure camera is set 201 | if (target) { 202 | target.updateMatrixWorld(); 203 | this.vector.setFromMatrixPosition(target.matrixWorld); 204 | if (object3D.parent) { 205 | object3D.parent.updateMatrixWorld(); 206 | object3D.parent.worldToLocal(this.vector); 207 | } 208 | return object3D.lookAt(this.vector); 209 | } 210 | } 211 | }); 212 | 213 | 214 | /***/ } 215 | /******/ ]); -------------------------------------------------------------------------------- /examples/resources/models/tree1/tex/shadow-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/resources/models/tree1/tex/shadow-circle.png -------------------------------------------------------------------------------- /examples/resources/models/tree1/tree1.dae: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CINEMA4D 15.064 COLLADA Exporter 6 | 7 | 2015-08-28T05:40:04Z 8 | 2015-08-28T05:40:04Z 9 | 10 | Y_UP 11 | 12 | 13 | 14 | tex/shadow-circle.png 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 0.8 0.8 0.8 1 24 | 25 | 26 | 0.2 0.2 0.2 1 27 | 28 | 29 | 0.5 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 0.0627451 0.396078 0.513725 1 41 | 42 | 43 | 0.2 0.2 0.2 1 44 | 45 | 46 | 0.5 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 0.0235294 0.564706 0.607843 1 58 | 59 | 60 | 0.2 0.2 0.2 1 61 | 62 | 63 | 0.5 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 0.164706 0.72549 0.701961 1 75 | 76 | 77 | 0.2 0.2 0.2 1 78 | 79 | 80 | 0.5 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 0.654902 0.47451 0.415686 1 92 | 93 | 94 | 0.2 0.2 0.2 1 95 | 96 | 97 | 0.5 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | ID13 108 | 109 | 110 | 111 | 112 | ID14 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 1 1 1 1 122 | 123 | 124 | 0.88 125 | 126 | 127 | 1 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -40 -80.5 40 40 -80.5 40 40 -80.5 -40 -40 -80.5 -40 -40 -77.5711 47.0711 40 -77.5711 47.0711 45 -77.5711 45 47.0711 -77.5711 40 47.0711 -77.5711 -40 45 -77.5711 -45 40 -77.5711 -47.0711 -40 -77.5711 -47.0711 -45 -77.5711 -45 -47.0711 -77.5711 -40 -47.0711 -77.5711 40 -45 -77.5711 45 -40 -70.5 50 40 -70.5 50 47.0711 -70.5 47.0711 50 -70.5 40 50 -70.5 -40 47.0711 -70.5 -47.0711 40 -70.5 -50 -40 -70.5 -50 -47.0711 -70.5 -47.0711 -50 -70.5 -40 -50 -70.5 40 -47.0711 -70.5 47.0711 -40 70.5 50 40 70.5 50 47.0711 70.5 47.0711 50 70.5 40 50 70.5 -40 47.0711 70.5 -47.0711 40 70.5 -50 -40 70.5 -50 -47.0711 70.5 -47.0711 -50 70.5 -40 -50 70.5 40 -47.0711 70.5 47.0711 -40 77.5711 47.0711 40 77.5711 47.0711 45 77.5711 45 47.0711 77.5711 40 47.0711 77.5711 -40 45 77.5711 -45 40 77.5711 -47.0711 -40 77.5711 -47.0711 -45 77.5711 -45 -47.0711 77.5711 -40 -47.0711 77.5711 40 -45 77.5711 45 -40 80.5 40 40 80.5 40 40 80.5 -40 -40 80.5 -40 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -0.0785214 -0.921027 0.381502 0.0785214 -0.921027 0.381502 0 -0.382683 0.92388 0 0 1 0 0.382683 0.92388 -0.0785214 0.921027 0.381502 0.0785214 0.921027 0.381502 0.156558 -0.912487 0.377964 0.357407 -0.357407 0.862856 0.382683 0 0.92388 0.357407 0.357407 0.862856 0.156558 0.912487 0.377964 0.381502 -0.921027 0.0785214 0.377964 -0.912487 0.156558 0.862856 -0.357407 0.357407 0.92388 0 0.382683 0.862856 0.357407 0.357407 0.377964 0.912487 0.156558 0.381502 0.921027 0.0785214 0.381502 -0.921027 -0.0785214 0.92388 -0.382683 -0 1 0 -0 0.92388 0.382683 -0 0.381502 0.921027 -0.0785214 0.377964 -0.912487 -0.156558 0.862856 -0.357407 -0.357407 0.92388 0 -0.382683 0.862856 0.357407 -0.357407 0.377964 0.912487 -0.156558 0.0785214 -0.921027 -0.381502 0.156558 -0.912487 -0.377964 0.357407 -0.357407 -0.862856 0.382683 0 -0.92388 0.357407 0.357407 -0.862856 0.156558 0.912487 -0.377964 0.0785214 0.921027 -0.381502 -0.0785214 -0.921027 -0.381502 0 -0.382683 -0.92388 0 0 -1 0 0.382683 -0.92388 -0.0785214 0.921027 -0.381502 -0.156558 -0.912487 -0.377964 -0.357407 -0.357407 -0.862856 -0.382683 0 -0.92388 -0.357407 0.357407 -0.862856 -0.156558 0.912487 -0.377964 -0.381502 -0.921027 -0.0785214 -0.377964 -0.912487 -0.156558 -0.862856 -0.357407 -0.357407 -0.92388 0 -0.382683 -0.862856 0.357407 -0.357407 -0.377964 0.912487 -0.156558 -0.381502 0.921027 -0.0785214 -0.381502 -0.921027 0.0785214 -0.92388 -0.382683 -0 -1 0 -0 -0.92388 0.382683 -0 -0.381502 0.921027 0.0785214 -0.377964 -0.912487 0.156558 -0.862856 -0.357407 0.357407 -0.92388 0 0.382683 -0.862856 0.357407 0.357407 -0.377964 0.912487 0.156558 -0.156558 -0.912487 0.377964 -0.357407 -0.357407 0.862856 -0.382683 0 0.92388 -0.357407 0.357407 0.862856 -0.156558 0.912487 0.377964 0 1 -0 0 -1 -0 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 0 0 0 0.0455526 0.835876 0.0455526 0.835876 0 0 0.0911051 0.835876 0.0911051 0 0.908895 0.835876 0.908895 0 0.954447 0.835876 0.954447 0 1 0.835876 1 0.876907 0 0.917938 0.0455526 0.917938 0.0911051 0.917938 0.908895 0.917938 0.954447 0.876907 1 0.958969 0 1 0.0455526 1 0.0911051 1 0.908895 1 0.954447 0.958969 1 1 1 1 0 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 4 4 4 3 4 4 4 3 3 4 4 4 3 4 4 194 |

1 1 3 5 1 2 4 0 1 0 0 0 5 2 2 17 2 5 16 2 4 4 2 1 17 3 5 29 3 7 28 3 6 16 3 4 29 4 7 41 4 9 40 4 8 28 4 6 41 6 9 53 6 11 52 5 10 40 5 8 6 7 13 5 1 2 1 1 12 6 8 13 18 8 14 17 8 5 5 8 2 18 9 14 30 9 15 29 9 7 17 9 5 30 10 15 42 10 16 41 10 9 29 10 7 42 11 16 53 6 17 41 6 9 7 12 19 6 13 13 1 12 18 7 14 19 19 14 20 18 14 14 6 14 13 19 15 20 31 15 21 30 15 15 18 15 14 31 16 21 43 16 22 42 16 16 30 16 15 43 18 22 53 18 23 42 17 16 2 19 3 8 19 2 7 12 1 1 12 0 8 20 2 20 20 5 19 20 4 7 20 1 20 21 5 32 21 7 31 21 6 19 21 4 32 22 7 44 22 9 43 22 8 31 22 6 44 23 9 54 23 11 53 18 10 43 18 8 9 24 13 8 19 2 2 19 12 9 25 13 21 25 14 20 25 5 8 25 2 21 26 14 33 26 15 32 26 7 20 26 5 33 27 15 45 27 16 44 27 9 32 27 7 45 28 16 54 23 17 44 23 9 10 29 19 9 30 13 2 29 18 10 31 19 22 31 20 21 31 14 9 31 13 22 32 20 34 32 21 33 32 15 21 32 14 34 33 21 46 33 22 45 33 16 33 33 15 46 35 22 54 35 23 45 34 16 3 36 3 11 36 2 10 29 1 2 29 0 11 37 2 23 37 5 22 37 4 10 37 1 23 38 5 35 38 7 34 38 6 22 38 4 35 39 7 47 39 9 46 39 8 34 39 6 47 40 9 55 40 11 54 35 10 46 35 8 12 41 13 11 36 2 3 36 12 12 42 13 24 42 14 23 42 5 11 42 2 24 43 14 36 43 15 35 43 7 23 43 5 36 44 15 48 44 16 47 44 9 35 44 7 48 45 16 55 40 17 47 40 9 13 46 19 12 47 13 3 46 18 13 48 19 25 48 20 24 48 14 12 48 13 25 49 20 37 49 21 36 49 15 24 49 14 37 50 21 49 50 22 48 50 16 36 50 15 49 52 22 55 52 23 48 51 16 0 53 3 14 53 2 13 46 1 3 46 0 14 54 2 26 54 5 25 54 4 13 54 1 26 55 5 38 55 7 37 55 6 25 55 4 38 56 7 50 56 9 49 56 8 37 56 6 50 57 9 52 57 11 55 52 10 49 52 8 15 58 13 14 53 2 0 53 12 15 59 13 27 59 14 26 59 5 14 59 2 27 60 14 39 60 15 38 60 7 26 60 5 39 61 15 51 61 16 50 61 9 38 61 7 51 62 16 52 57 17 50 57 9 4 0 19 15 63 13 0 0 18 4 64 19 16 64 20 27 64 14 15 64 13 16 65 20 28 65 21 39 65 15 27 65 14 28 66 21 40 66 22 51 66 16 39 66 15 40 5 22 52 5 23 51 67 16 53 68 25 54 68 24 55 68 10 52 68 0 3 69 0 2 69 25 1 69 24 0 69 10

195 |
196 |
197 |
198 | 199 | 200 | 201 | 0 -50 0 0 50 0 10 -50 -0 10 -50 -0 10 50 -0 10 50 -0 8.66025 -50 -5 8.66025 -50 -5 8.66025 50 -5 8.66025 50 -5 5 -50 -8.66025 5 -50 -8.66025 5 50 -8.66025 5 50 -8.66025 6.12323e-16 -50 -10 6.12323e-16 -50 -10 6.12323e-16 50 -10 6.12323e-16 50 -10 -5 -50 -8.66025 -5 -50 -8.66025 -5 50 -8.66025 -5 50 -8.66025 -8.66025 -50 -5 -8.66025 -50 -5 -8.66025 50 -5 -8.66025 50 -5 -10 -50 -1.22465e-15 -10 -50 -1.22465e-15 -10 50 -1.22465e-15 -10 50 -1.22465e-15 -8.66025 -50 5 -8.66025 -50 5 -8.66025 50 5 -8.66025 50 5 -5 -50 8.66025 -5 -50 8.66025 -5 50 8.66025 -5 50 8.66025 -1.83697e-15 -50 10 -1.83697e-15 -50 10 -1.83697e-15 50 10 -1.83697e-15 50 10 5 -50 8.66025 5 -50 8.66025 5 50 8.66025 5 50 8.66025 8.66025 -50 5 8.66025 -50 5 8.66025 50 5 8.66025 50 5 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 0 -1 -0 1 0 -0 0.866026 0 -0.5 0 1 -0 0.5 0 -0.866026 0 0 -1 -0.5 0 -0.866026 -0.866026 0 -0.5 -1 0 -0 -0.866026 0 0.5 -0.5 0 0.866026 0 0 1 0.5 0 0.866026 0.866026 0 0.5 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 0.5 0.5 0 0.5 0.0669873 0.75 0 0 0 1 0.0833333 1 0.0833333 0 1 0.5 0.933013 0.75 0.25 0.933013 0.166667 1 0.166667 0 0.75 0.933013 0.5 1 0.25 1 0.25 0 0.333333 1 0.333333 0 0.416667 1 0.416667 0 0.5 0 0.933013 0.25 0.583333 1 0.583333 0 0.0669873 0.25 0.75 0.0669873 0.666667 1 0.666667 0 0.25 0.0669873 0.75 1 0.75 0 0.833333 1 0.833333 0 0.916667 1 0.916667 0 1 1 1 0 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 237 |

6 0 2 2 0 1 0 0 0 7 2 6 8 2 5 4 1 4 3 1 3 9 3 8 1 3 0 5 3 7 10 0 9 6 0 2 0 0 0 11 4 11 12 4 10 8 2 5 7 2 6 13 3 12 1 3 0 9 3 8 14 0 13 10 0 9 0 0 0 15 5 15 16 5 14 12 4 10 11 4 11 17 3 13 1 3 0 13 3 12 18 0 12 14 0 13 0 0 0 19 6 17 20 6 16 16 5 14 15 5 15 21 3 9 1 3 0 17 3 13 22 0 8 18 0 12 0 0 0 23 7 19 24 7 18 20 6 16 19 6 17 25 3 2 1 3 0 21 3 9 26 0 7 22 0 8 0 0 0 27 8 20 28 8 13 24 7 18 23 7 19 29 3 1 1 3 0 25 3 2 30 0 21 26 0 7 0 0 0 31 9 23 32 9 22 28 8 13 27 8 20 33 3 24 1 3 0 29 3 1 34 0 25 30 0 21 0 0 0 35 10 27 36 10 26 32 9 22 31 9 23 37 3 28 1 3 0 33 3 24 38 0 20 34 0 25 0 0 0 39 11 30 40 11 29 36 10 26 35 10 27 41 3 20 1 3 0 37 3 28 42 0 28 38 0 20 0 0 0 43 12 32 44 12 31 40 11 29 39 11 30 45 3 25 1 3 0 41 3 20 46 0 24 42 0 28 0 0 0 47 13 34 48 13 33 44 12 31 43 12 32 49 3 21 1 3 0 45 3 25 2 0 1 46 0 24 0 0 0 3 1 36 4 1 35 48 13 33 47 13 34 5 3 7 1 3 0 49 3 21

238 |
239 |
240 |
241 | 242 | 243 | 244 | -50 0 50 50 0 50 -50 0 -50 50 0 -50 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 0 1 -0 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 0 0 0 1 1 1 1 0 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 4 280 |

1 0 3 3 0 2 2 0 1 0 0 0

281 |
282 |
283 |
284 |
285 | 286 | 287 | 288 | 0 0 -0 289 | 0 1 0 -0 290 | 1 0 0 0 291 | 0 0 1 -0 292 | 1 1 1 293 | 294 | 0 180 -0 295 | 0 1 0 -0 296 | 1 0 0 0 297 | 0 0 1 -0 298 | 1 1 1 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 0 50 -0 311 | 0 1 0 -0 312 | 1 0 0 0 313 | 0 0 1 -0 314 | 1 1 1 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 0 0 -0 327 | 0 1 0 -0 328 | 1 0 0 0 329 | 0 0 1 -0 330 | 1 1 1 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 |
348 | -------------------------------------------------------------------------------- /examples/resources/splash.css: -------------------------------------------------------------------------------- 1 | /* 2 | from https://ihatetomatoes.net/demos/css3-preloader-transition/ 3 | */ 4 | 5 | h1 { 6 | height: 80%; 7 | margin: 0; 8 | font-size: 32px; 9 | font-family: 'Open Sans', sans-serif; 10 | margin-bottom: 3px; 11 | color: #EEEEEE; 12 | } 13 | 14 | body { 15 | margin: 0; 16 | } 17 | 18 | h2 { 19 | height: 20%; 20 | margin: 0; 21 | font-family: 'Open Sans', sans-serif; 22 | font-size: 16px; 23 | margin-bottom: 3px; 24 | color: #EEEEEE; 25 | } 26 | 27 | .splashtext { 28 | position: fixed; 29 | top: 10%; 30 | left: 10%; 31 | width: 80%; 32 | height: 80%; 33 | background: transparent; 34 | text-align: center; 35 | z-index: 1010; 36 | } 37 | 38 | .loaded .splashtext { 39 | visibility: hidden; 40 | color: transparent; 41 | -webkit-transition: all 0.3s ease-out; 42 | transition: all 0.3s ease-out; 43 | } 44 | 45 | #loader-wrapper { 46 | position: fixed; 47 | top: 0; 48 | left: 0; 49 | width: 100%; 50 | height: 100%; 51 | z-index: 1000; 52 | } 53 | #loader { 54 | display: block; 55 | position: relative; 56 | background: transparent; 57 | left: 50%; 58 | top: 50%; 59 | width: 150px; 60 | height: 150px; 61 | margin: -75px 0 0 -75px; 62 | border-radius: 50%; 63 | border: 3px solid transparent; 64 | border-top-color: #3498db; 65 | 66 | -webkit-animation: spin 2s linear infinite; /* Chrome, Opera 15+, Safari 5+ */ 67 | animation: spin 2s linear infinite; /* Chrome, Firefox 16+, IE 10+, Opera */ 68 | 69 | z-index: 1001; 70 | } 71 | #loader:before { 72 | content: ""; 73 | position: absolute; 74 | top: 5px; 75 | left: 5px; 76 | right: 5px; 77 | bottom: 5px; 78 | border-radius: 50%; 79 | border: 3px solid transparent; 80 | border-top-color: #e74c3c; 81 | 82 | -webkit-animation: spin 3s linear infinite; /* Chrome, Opera 15+, Safari 5+ */ 83 | animation: spin 3s linear infinite; /* Chrome, Firefox 16+, IE 10+, Opera */ 84 | } 85 | #loader:after { 86 | content: ""; 87 | position: absolute; 88 | top: 15px; 89 | left: 15px; 90 | right: 15px; 91 | bottom: 15px; 92 | border-radius: 50%; 93 | border: 3px solid transparent; 94 | border-top-color: #f9c922; 95 | 96 | -webkit-animation: spin 1.5s linear infinite; /* Chrome, Opera 15+, Safari 5+ */ 97 | animation: spin 1.5s linear infinite; /* Chrome, Firefox 16+, IE 10+, Opera */ 98 | } 99 | 100 | @-webkit-keyframes spin { 101 | 0% { 102 | -webkit-transform: rotate(0deg); /* Chrome, Opera 15+, Safari 3.1+ */ 103 | -ms-transform: rotate(0deg); /* IE 9 */ 104 | transform: rotate(0deg); /* Firefox 16+, IE 10+, Opera */ 105 | } 106 | 100% { 107 | -webkit-transform: rotate(360deg); /* Chrome, Opera 15+, Safari 3.1+ */ 108 | -ms-transform: rotate(360deg); /* IE 9 */ 109 | transform: rotate(360deg); /* Firefox 16+, IE 10+, Opera */ 110 | } 111 | } 112 | @keyframes spin { 113 | 0% { 114 | -webkit-transform: rotate(0deg); /* Chrome, Opera 15+, Safari 3.1+ */ 115 | -ms-transform: rotate(0deg); /* IE 9 */ 116 | transform: rotate(0deg); /* Firefox 16+, IE 10+, Opera */ 117 | } 118 | 100% { 119 | -webkit-transform: rotate(360deg); /* Chrome, Opera 15+, Safari 3.1+ */ 120 | -ms-transform: rotate(360deg); /* IE 9 */ 121 | transform: rotate(360deg); /* Firefox 16+, IE 10+, Opera */ 122 | } 123 | } 124 | 125 | #loader-wrapper .loader-section { 126 | position: fixed; 127 | top: 0; 128 | width: 51%; 129 | height: 100%; 130 | background: #222222; 131 | z-index: 1000; 132 | -webkit-transform: translateX(0); /* Chrome, Opera 15+, Safari 3.1+ */ 133 | -ms-transform: translateX(0); /* IE 9 */ 134 | transform: translateX(0); /* Firefox 16+, IE 10+, Opera */ 135 | } 136 | 137 | #loader-wrapper .loader-section.section-left { 138 | left: 0; 139 | } 140 | 141 | #loader-wrapper .loader-section.section-right { 142 | right: 0; 143 | } 144 | 145 | /* Loaded */ 146 | #loader-wrapper.loaded .loader-section.section-left { 147 | -webkit-transform: translateX(-100%); /* Chrome, Opera 15+, Safari 3.1+ */ 148 | -ms-transform: translateX(-100%); /* IE 9 */ 149 | transform: translateX(-100%); /* Firefox 16+, IE 10+, Opera */ 150 | -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000); 151 | transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000); 152 | } 153 | 154 | #loader-wrapper.loaded .loader-section.section-right { 155 | -webkit-transform: translateX(100%); /* Chrome, Opera 15+, Safari 3.1+ */ 156 | -ms-transform: translateX(100%); /* IE 9 */ 157 | transform: translateX(100%); /* Firefox 16+, IE 10+, Opera */ 158 | 159 | -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000); 160 | transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000); 161 | } 162 | 163 | .loaded #loader { 164 | visibility: hidden; 165 | opacity: 0; 166 | background: transparent; 167 | 168 | -webkit-transition: all 0.3s ease-out; 169 | transition: all 0.3s ease-out; 170 | } 171 | 172 | .loaded #fooloader-wrapper { 173 | visibility: hidden; 174 | opacity: 0; 175 | background: transparent; 176 | 177 | -webkit-transition: all 0.1s 1s ease-out; 178 | transition: all 0.1s 1s ease-out; 179 | } 180 | 181 | #loader-wrapper.loaded { 182 | -webkit-transform: translateY(-200%); 183 | -ms-transform: translateY(-200%); 184 | transform: translateY(-200%); 185 | 186 | 187 | -webkit-transition: all 0.3s 1s ease-out; 188 | transition: all 0.3s 1s ease-out; 189 | } -------------------------------------------------------------------------------- /examples/resources/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Arial; 3 | } 4 | 5 | a { 6 | color: #ffffff; 7 | } 8 | 9 | .menu { 10 | position: absolute; 11 | bottom: 0; 12 | width: 100%; 13 | text-align: center; 14 | pointer-events: auto; 15 | } 16 | 17 | .label { 18 | opacity: 0.5; 19 | font-size: 20px; 20 | text-align: center; 21 | color: black; 22 | background: rgba(127,255,255,0.85); 23 | outline: 5px solid rgba(12,25,25,1.0); 24 | border: 0px; 25 | margin-bottom: 0px; 26 | padding: 0px 0px; 27 | } 28 | 29 | .pin { 30 | font-size: 100px; 31 | text-align: center; 32 | color:indianred; 33 | background: transparent; 34 | border: 0px; 35 | margin-bottom: 0px; 36 | padding: 0px 0px; 37 | } 38 | 39 | .boxface { 40 | opacity: 0.5; 41 | width: 90px; 42 | height: 90px; 43 | font-size: 25px; 44 | text-align: center; 45 | color: black; 46 | background: rgba(127,255,255,0.85); 47 | outline: 5px solid rgba(12,25,25,1.0); 48 | border: 0px; 49 | margin-bottom: 0px; 50 | padding: 0px 0px; 51 | } 52 | 53 | button { 54 | opacity: 0.5; 55 | text-align: center; 56 | color: black; 57 | background: rgba(127,255,255,0.85); 58 | outline: 5px solid rgba(12,25,25,1.0); 59 | border: 0px; 60 | margin-bottom: 0px; 61 | font-size: 11; 62 | border: 0px; 63 | padding: 5px 10px; 64 | cursor: pointer; 65 | margin: 10px; 66 | } 67 | button:hover { 68 | color: rgba(127,255,255,0.85); 69 | background: black; 70 | } 71 | -------------------------------------------------------------------------------- /examples/resources/textures/buzz-pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argonjs/argon-aframe/162ece1976a859cb6383144a6be8d8448d0e5bc0/examples/resources/textures/buzz-pin.png -------------------------------------------------------------------------------- /examples/vuforia-aframe-logo/app.css: -------------------------------------------------------------------------------- 1 | .bottomScreen { 2 | position: absolute; 3 | bottom: 10px; 4 | margin: 9, auto; 5 | left: 25%; 6 | width: 50%; 7 | text-align: center; 8 | color: rgb(127,255,255); 9 | background: rgba(10,10,10,0.75); 10 | outline: 3px solid rgba(127,255,255,0.5); 11 | border: 0px; 12 | padding: 15px; 13 | display: inline-block; 14 | font-size: 24px; 15 | font-family: 'Open Sans', sans-serif; 16 | } 17 | 18 | .viewerMode.bottomScreen { 19 | font-size: 8px; 20 | bottom:120px; 21 | padding:2px; 22 | } 23 | 24 | .hide.bottomScreen { 25 | display: none; 26 | } -------------------------------------------------------------------------------- /examples/vuforia-aframe-logo/app.js: -------------------------------------------------------------------------------- 1 | 2 | // this is all about the load/splash screen 3 | var arScene = document.querySelector('ar-scene'); 4 | var statusMsg = document.querySelector('#status'); 5 | var loader = document.querySelector('#loader-wrapper'); 6 | statusMsg.innerHTML = "loading argon and aframe..."; 7 | var frame = document.querySelector("#frame"); 8 | var content = document.querySelector("#content"); 9 | 10 | var hudElem = document.querySelector("#lookattarget"); 11 | var hudElem2 = hudElem.cloneNode( true ); 12 | hudElem2.id = hudElem.id + "2"; 13 | 14 | var contentRoot = document.querySelector('#logoscene'); 15 | var animations = document.querySelectorAll('#logoscene a-animation'); 16 | contentRoot.pause(); 17 | 18 | arScene.addEventListener('argon-initialized', function(evt) { 19 | statusMsg.innerHTML = "argon initialized, starting vuforia..."; 20 | }); 21 | arScene.addEventListener('argon-vuforia-initialized', function(evt) { 22 | statusMsg.innerHTML = "vuforia initialized, downloading dataset..."; 23 | }); 24 | arScene.addEventListener('argon-vuforia-initialization-failed', function(evt) { 25 | statusMsg.innerHTML = "vuforia failed to initialize: " + evt.detail.error.message; 26 | }); 27 | 28 | arScene.addEventListener('argon-vuforia-dataset-loaded', function(evt) { 29 | statusMsg.innerHTML = "done"; 30 | loader.classList.add('loaded'); 31 | 32 | // hudElem.style.display = 'inline-block'; // start hidden 33 | arScene.hud.appendChild(hudElem, hudElem2); 34 | 35 | frame.addEventListener('referenceframe-statuschanged', function(evt) { 36 | if (evt.detail.found) { 37 | hudElem.classList.add("hide"); 38 | hudElem2.classList.add("hide"); 39 | // hudElem.style.display = 'none'; // hide when target seen 40 | // hudElem2.style.display = 'none'; // hide when target seen 41 | 42 | contentRoot.pause(); 43 | contentRoot.setAttribute("visible", false); 44 | contentRoot.play(); 45 | 46 | } else { 47 | hudElem.classList.remove("hide"); 48 | hudElem2.classList.remove("hide"); 49 | // hudElem.style.display = 'inline-block'; // show when target lost 50 | // hudElem2.style.display = 'inline-block'; // hide when target seen 51 | contentRoot.pause(); 52 | } 53 | }); 54 | 55 | arScene.addEventListener('target_trigger', function(evt) { 56 | console.log("TRIGGER: " + (evt.detail.inside ? "ENTERED" : "EXITED")); 57 | }); 58 | }); 59 | arScene.addEventListener('argon-vuforia-dataset-load-failed', function(evt) { 60 | statusMsg.innerHTML = "vuforia failed to load: " + evt.detail.error.message; 61 | }); 62 | 63 | arScene.addEventListener('argon-vuforia-not-available', function(evt) { 64 | frame.setAttribute("trackvisibility", false); 65 | frame.setAttribute("visible", true); 66 | frame.setAttribute("parent", "ar.stage"); 67 | // content.setAttribute("rotation", {x: -90, y: 0, z: 0}); 68 | content.setAttribute("position", {x: 0, y: 0, z: -5}); 69 | content.setAttribute("scale", {x: 20, y: 20, z: 20}); 70 | 71 | contentRoot.setAttribute("rotation", { x: 0, y: -90, z:0 }); 72 | 73 | hudElem.innerHTML = "No Vuforia. Showing scene that would be on the target." 74 | hudElem2.innerHTML = "No Vuforia. Showing scene that would be on the target." 75 | arScene.hud.appendChild(hudElem, hudElem2); 76 | 77 | statusMsg.innerHTML = "done"; 78 | loader.classList.add('loaded'); 79 | contentRoot.play(); 80 | }); 81 | 82 | arScene.addEventListener('enter-vr', function (evt) { 83 | hudElem.classList.add("viewerMode"); 84 | hudElem2.classList.add("viewerMode"); 85 | }); 86 | arScene.addEventListener('exit-vr', function (evt) { 87 | hudElem.classList.remove("viewerMode"); 88 | hudElem2.classList.remove("viewerMode"); 89 | }); 90 | 91 | -------------------------------------------------------------------------------- /examples/vuforia-aframe-logo/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | 5 | Vuforia and AFrame Logo with Argon + A-Frame 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 25 |
26 |
27 |

AFrame + Argon + Vuforia

28 |

loading scripts...

29 |
30 | 31 |
32 |
33 |
34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 216 | 217 | 218 | 219 |
220 | 221 | 222 | 231 | 232 | -------------------------------------------------------------------------------- /examples/vuforia-aframe-logo/key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | Version: OpenPGP.js v2.3.2 3 | Comment: http://openpgpjs.org 4 | 5 | wcFMA+gV6pi+O8zeARAAssqSfRHFNoDTNaEdU7i6rVRjht5U4fHnwihcmiOR 6 | u15f5zQrYlT+g8xDM69uz0r2PlcoD6DWllgFhokkDmm6775Yg9I7YcguUTLF 7 | V6t+wCp/IgSRl665KXmmHxEd/cXlcL6c9vIFT/heEOgK2hpsPXGfLl1BJKHc 8 | CqFZ3I3uSCqoM2eDymNSWaiF0Ci6fp5LB7i1oVgB9ujI0b2SSf2NHUa0JfP9 9 | GPSgveAc2GTysUCqk3dkgcH272Fzf4ldG48EoM48B7e0FLuEqx9V5nHxP3lh 10 | 9VRcAzA3S3LaujA+Kz9/JUOckyL9T/HON/h1iDDmsrScL4PaGWX5EX0yuvBw 11 | FtWDauLbzAn5BSV+pw7dOmpbSGFAKKUnfhj9d1c5TVeaMkcBhxlkt7j7WvxS 12 | uuURU3lrH8ytnQqPJzw2YSmxdeHSsAjAWnCRJSaUBlAMj0QsXkPGmMwN8EFS 13 | 9bbkJETuJoVDFfD472iGJi4NJXQ/0Cc4062J5AuYb71QeU8d9nixXlIDXW5U 14 | fxo9/JpnZRSmWB9R6A2H3+e5dShWDxZF/xVpHNQWi3fQaSKWscQSvUJ83BBP 15 | ltCvDo+gpD6tTt+3SnAThLuhl38ud7i1B8e0dOCKpuYeSG0rXQPY53n2+mGK 16 | P1s0e0R7D5jztijwXvGPf45z232cztWsZWvuD2x42DXBwU0DAGn1enGTza0Q 17 | B/j9y72hJrXx/TdOq85QDMBAA+Ocm9MSGylOqMOb9ozC+DVhhVx7doqS3xV9 18 | h3jLf6V+OF6VIPHQBxAzH5svlktEOcTtjrjQxnUMmNuHbNQmZlA7uYsAqUpF 19 | nWqPtJeHMi2F/gYYI/ApK3NGxzJe21dAf2cdp26wf/PoLusotCQH1YVpuR+V 20 | 18Mb8hMpPlB1j5SXnBlv98LxiOGlG6/lQWxpMzkMSZZTxMxa1pCsYNJKK9Bg 21 | pFUyp4x0W4bQL1mRlqaO04cfoErfHqQzboS2b7WRrNy7YJ9rcBbmpbSc+GEY 22 | T7ZUPs66EHgdp6uWYPbM1/oajHQBSPALiV65k06XlR4H+QG1ClkSIkbguKnu 23 | mbpgF7wF5bAfjVVK/ST000Dzr09sgfm4wlIHRcezOzUgjIDVAQE63PznhzfZ 24 | PEwOKC9ex9t9G+HjvhxICYFoxJLcHJ8ytTWEguNFqSIRTKWTgvAycvTFkJA/ 25 | pasmzov3Nouak8sE28r2NRpWbmI7muLvHfPWgy/rVczF+E1sOkbwtsdOgmym 26 | yC9yB2IB3fhpLgU28cuI26+cx5IIke0jUgftvza8Oqa0gFZzvu8LaR/RsUdp 27 | 9/CRpiYFvvamNmCDIxxYKtAFCOkEni/5ht4poI2ZxHeWtjwZ2GBqby7BqpUu 28 | xLXgv+3XpVq1sSUVurKbntDXUy3BwUwDju235GExYfIBEADMsiKpgf0sGKeW 29 | a5uzMKZgnMm1MoRFBJNsjmBZrbsMxn6lf2ry3XM1xw/w15lepn4X/EMDLeRw 30 | 1m3vw4JL7dLY6e2oOllWyscCs+qE8Cwwx9x6q/gAMfwyrqMQ5EH8psIrRKZM 31 | eZwGEnSIuUXtJu3ShyqZUqfbpXhr+TxUEXY7n7NuCRJeM70PWPZB5IC1h3Bp 32 | kgxMRP4zHN2VG4PlcX2fLjpYsx1BHtR2T1biYxbk1AZ26s97XEMH7t9oe+8b 33 | G+QZc500MmPOd+62UZmnOf/Dul9q/H/0+IlWlWSUTTZFtlL+LwR56t28xqca 34 | FjUW8TXv6zYUvY7kk5Mlf2iWPA11wJuHaL5DnGaOoNgFVzicNQKy3SfeuYyp 35 | rSwClM37jRKw+ZNGQDPSAhtrwYZxtndCw/jieqdxIbFG9Td+BunpJNE+KICN 36 | jmnvG5JrzdueKAyTGqxNOtQnNDJYcg+p5rZVZHGQMN/22n2aiRpWhVAdJIXE 37 | YgpsFH6R01N3Y55RFNrhusOhuWodj0XuS1EhknU47XyIpNVSZhWG/e+vXMHb 38 | sN5cO0V7iCFrSxKXg6AwVneoWJC5anT9IabIcgAz07SjdjceC2MlW0vdjPks 39 | FNygBlP9fTIjBGRzg5QQCh/LyyFUTr1rYRbF+4k5kBQ3MtD2a/lS3Sk1MK/+ 40 | Es9PfWaAoNLB+QGqSi1qtIhds22zelOtc2MGFxgwb/iNZOUccauv6OXThvDD 41 | gzpn7gZi0+N7pOwx9lJM9QgC4hTMlo268vhNd/MMIPMeyp5n5D8p8ewAutZm 42 | AcIJkP3h2tUG1V/RvVLF22F+ilh3h++7TeSfHdTdv6ArwDJXdQunHCp3020f 43 | vhT6XG0ND+UMFtrptJe7+NoRpNg9oZo6kvwDzhPdIa2OlVjXmr25ueC8FlET 44 | cYdFbIisK+std7/XMlkE5wlGkf9G0RoHsxXqB2Nsj8l3qF5UNyWD+/2Wh+L9 45 | CDjUbY1FxwlVJ4UZ7lz+8jWHO5jYY99adPoATpUaWYxm9oPxz/QR4kvgvLjl 46 | 9Ti8379Y8qihzqsRmf6YLYyggknlt9Uyl2HjA+1zcwbDnb3I6g/XjTFUPy1D 47 | xZqqSEuCNDLh7m1+GDA3KXQnLIqOdcxOVzyFCDtKI9c6b0D0ezNkxUjgkoIp 48 | mxSSLDjzmHuPLsQVwqxP4KNU1gT7mXTnhlhsG2Vll/WZD+tuzGK8h9anf6/p 49 | 4pCk61Dhj1hmb9msTaK4FGhmBMtJ6kQ4SzGOfFKG5IElAHidYgd0iz7AqEzX 50 | GttDkcHGM9iPIYUBY2r/538M/kxeVx5fBiWEkmWz5FMzqPRs3GZWYiAb2tnp 51 | WSDXW3B1mwznwcCkyUP6OP/c6FFmb6Rag/ZaItVAvVjmA7tXICLJPhYIs9hE 52 | I6zJSVZ81YtKg9Nb6Rx49qf18pQ1SWZNGrZrWaTJTLu4cu4c5v/czY5kyT0Y 53 | 8RqNUlI5hwWU8G9LpJ5jv8dssrgcweTG/PEbCkzqz0R6W6VgDUyqo6WSGgoS 54 | B9or791lGcDazNT6CJ4/2Z1wBd4BSHkhSwfcPovGOleZFE24gLiG6puHyVjk 55 | WEIir2WXzhypwLkG/dn+ZJW1ezOvTb4gVVILHrWhNh8= 56 | =LoZg 57 | -----END PGP MESSAGE----- -------------------------------------------------------------------------------- /examples/vuforia/app.css: -------------------------------------------------------------------------------- 1 | .bottomScreen { 2 | position: absolute; 3 | bottom: 10px; 4 | margin: 9, auto; 5 | left: 25%; 6 | width: 50%; 7 | text-align: center; 8 | color: rgb(127,255,255); 9 | background: rgba(10,10,10,0.75); 10 | outline: 3px solid rgba(127,255,255,0.5); 11 | border: 0px; 12 | padding: 15px; 13 | display: inline-block; 14 | font-size: 24px; 15 | font-family: 'Open Sans', sans-serif; 16 | } 17 | 18 | .viewerMode.bottomScreen { 19 | font-size: 8px; 20 | bottom:120px; 21 | padding:2px; 22 | } 23 | 24 | .hide.bottomScreen { 25 | display: none; 26 | } -------------------------------------------------------------------------------- /examples/vuforia/app.js: -------------------------------------------------------------------------------- 1 | 2 | // this is all about the load/splash screen 3 | var arScene = document.querySelector('ar-scene'); 4 | var statusMsg = document.querySelector('#status'); 5 | var loader = document.querySelector('#loader-wrapper'); 6 | statusMsg.innerHTML = "loading argon and aframe..."; 7 | var frame = document.querySelector("#frame"); 8 | var scene = document.querySelector('#stuff'); 9 | var content = document.querySelector('#content'); 10 | 11 | var hudElem = document.querySelector("#lookattarget"); 12 | var hudElem2 = hudElem.cloneNode( true ); 13 | hudElem2.id = hudElem.id + "2"; 14 | 15 | arScene.addEventListener('argon-initialized', function(evt) { 16 | statusMsg.innerHTML = "argon initialized, starting vuforia..."; 17 | }); 18 | arScene.addEventListener('argon-vuforia-initialized', function(evt) { 19 | statusMsg.innerHTML = "vuforia initialized, downloading dataset..."; 20 | }); 21 | arScene.addEventListener('argon-vuforia-initialization-failed', function(evt) { 22 | statusMsg.innerHTML = "vuforia failed to initialize: " + evt.detail.error.message; 23 | }); 24 | 25 | arScene.addEventListener('argon-vuforia-dataset-loaded', function(evt) { 26 | statusMsg.innerHTML = "done"; 27 | loader.classList.add('loaded'); 28 | 29 | // hudElem.style.display = 'inline-block'; // start hidden 30 | arScene.hud.appendChild(hudElem, hudElem2); 31 | 32 | frame.addEventListener('referenceframe-statuschanged', function(evt) { 33 | if (evt.detail.found) { 34 | hudElem.classList.add("hide"); 35 | hudElem2.classList.add("hide"); 36 | // hudElem.style.display = 'none'; // hide when target seen 37 | // hudElem2.style.display = 'none'; // hide when target seen 38 | } else { 39 | hudElem.classList.remove("hide"); 40 | hudElem2.classList.remove("hide"); 41 | // hudElem.style.display = 'inline-block'; // show when target lost 42 | // hudElem2.style.display = 'inline-block'; // hide when target seen 43 | } 44 | }); 45 | }); 46 | arScene.addEventListener('argon-vuforia-dataset-load-failed', function(evt) { 47 | statusMsg.innerHTML = "vuforia failed to load: " + evt.detail.error.message; 48 | }); 49 | 50 | arScene.addEventListener('argon-vuforia-not-available', function(evt) { 51 | frame.setAttribute("trackvisibility", false); 52 | frame.setAttribute("visible", true); 53 | frame.setAttribute("parent", "ar.stage") 54 | content.setAttribute("rotation", {x: -90, y: 0, z: 0}); 55 | content.setAttribute("position", {x: 0, y: 0, z: 0}); 56 | content.setAttribute("scale", {x: 20, y: 20, z: 20}); 57 | 58 | hudElem.innerHTML = "No Vuforia. Showing scene that would be on the target." 59 | hudElem2.innerHTML = "No Vuforia. Showing scene that would be on the target." 60 | //hudElem.style.display = 'inline-block'; // show when target lost 61 | arScene.hud.appendChild(hudElem, hudElem2); 62 | 63 | statusMsg.innerHTML = "done"; 64 | loader.classList.add('loaded'); 65 | }); 66 | 67 | arScene.addEventListener('enter-vr', function (evt) { 68 | hudElem.classList.add("viewerMode"); 69 | hudElem2.classList.add("viewerMode"); 70 | }); 71 | arScene.addEventListener('exit-vr', function (evt) { 72 | hudElem.classList.remove("viewerMode"); 73 | hudElem2.classList.remove("viewerMode"); 74 | }); 75 | 76 | for (var i = 0; i < 12; i++) { 77 | var obj = document.createElement('a-entity'); 78 | obj.setAttribute('geometry', { 79 | primitive: 'torusKnot', 80 | radius: Math.random() * 10, 81 | radiusTubular: Math.random() * .75, 82 | p: Math.round(Math.random() * 10), 83 | q: Math.round(Math.random() * 10) 84 | }); 85 | obj.setAttribute('material', { 86 | color: getRandColor(), 87 | metalness: Math.random(), 88 | roughness: Math.random() 89 | }); 90 | obj.setAttribute('position', { 91 | x: getRandCoord(), 92 | y: getRandCoord(), 93 | z: getRandCoord()/2 + 13 94 | }); 95 | scene.appendChild(obj); 96 | } 97 | 98 | function getRandColor () { 99 | var letters = '0123456789ABCDEF'.split(''); 100 | var color = '#'; 101 | for (var i = 0; i < 6; i++) { 102 | color += letters[Math.floor(Math.random() * 16)]; 103 | } 104 | return color; 105 | } 106 | 107 | function getRandCoord () { 108 | var coord = Math.random() * 20; 109 | return Math.random() < .5 ? coord + 5 : coord * -1 - 5; 110 | } -------------------------------------------------------------------------------- /examples/vuforia/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | 5 | Vuforia Image Tracking with Argon + A-Frame 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 26 |
27 |
28 |

AFrame + Argon + Vuforia

29 |

loading scripts...

30 |
31 | 32 |
33 |
34 |
35 |
36 | 37 | 38 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 57 | 58 | 59 | 60 | 61 | 62 | 64 | 65 | 66 | 67 | 68 | 69 | 70 |
71 | 72 | 73 | 82 | 83 | -------------------------------------------------------------------------------- /examples/vuforia/key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | Version: OpenPGP.js v2.3.2 3 | Comment: http://openpgpjs.org 4 | 5 | wcFMA+gV6pi+O8zeARAAssqSfRHFNoDTNaEdU7i6rVRjht5U4fHnwihcmiOR 6 | u15f5zQrYlT+g8xDM69uz0r2PlcoD6DWllgFhokkDmm6775Yg9I7YcguUTLF 7 | V6t+wCp/IgSRl665KXmmHxEd/cXlcL6c9vIFT/heEOgK2hpsPXGfLl1BJKHc 8 | CqFZ3I3uSCqoM2eDymNSWaiF0Ci6fp5LB7i1oVgB9ujI0b2SSf2NHUa0JfP9 9 | GPSgveAc2GTysUCqk3dkgcH272Fzf4ldG48EoM48B7e0FLuEqx9V5nHxP3lh 10 | 9VRcAzA3S3LaujA+Kz9/JUOckyL9T/HON/h1iDDmsrScL4PaGWX5EX0yuvBw 11 | FtWDauLbzAn5BSV+pw7dOmpbSGFAKKUnfhj9d1c5TVeaMkcBhxlkt7j7WvxS 12 | uuURU3lrH8ytnQqPJzw2YSmxdeHSsAjAWnCRJSaUBlAMj0QsXkPGmMwN8EFS 13 | 9bbkJETuJoVDFfD472iGJi4NJXQ/0Cc4062J5AuYb71QeU8d9nixXlIDXW5U 14 | fxo9/JpnZRSmWB9R6A2H3+e5dShWDxZF/xVpHNQWi3fQaSKWscQSvUJ83BBP 15 | ltCvDo+gpD6tTt+3SnAThLuhl38ud7i1B8e0dOCKpuYeSG0rXQPY53n2+mGK 16 | P1s0e0R7D5jztijwXvGPf45z232cztWsZWvuD2x42DXBwU0DAGn1enGTza0Q 17 | B/j9y72hJrXx/TdOq85QDMBAA+Ocm9MSGylOqMOb9ozC+DVhhVx7doqS3xV9 18 | h3jLf6V+OF6VIPHQBxAzH5svlktEOcTtjrjQxnUMmNuHbNQmZlA7uYsAqUpF 19 | nWqPtJeHMi2F/gYYI/ApK3NGxzJe21dAf2cdp26wf/PoLusotCQH1YVpuR+V 20 | 18Mb8hMpPlB1j5SXnBlv98LxiOGlG6/lQWxpMzkMSZZTxMxa1pCsYNJKK9Bg 21 | pFUyp4x0W4bQL1mRlqaO04cfoErfHqQzboS2b7WRrNy7YJ9rcBbmpbSc+GEY 22 | T7ZUPs66EHgdp6uWYPbM1/oajHQBSPALiV65k06XlR4H+QG1ClkSIkbguKnu 23 | mbpgF7wF5bAfjVVK/ST000Dzr09sgfm4wlIHRcezOzUgjIDVAQE63PznhzfZ 24 | PEwOKC9ex9t9G+HjvhxICYFoxJLcHJ8ytTWEguNFqSIRTKWTgvAycvTFkJA/ 25 | pasmzov3Nouak8sE28r2NRpWbmI7muLvHfPWgy/rVczF+E1sOkbwtsdOgmym 26 | yC9yB2IB3fhpLgU28cuI26+cx5IIke0jUgftvza8Oqa0gFZzvu8LaR/RsUdp 27 | 9/CRpiYFvvamNmCDIxxYKtAFCOkEni/5ht4poI2ZxHeWtjwZ2GBqby7BqpUu 28 | xLXgv+3XpVq1sSUVurKbntDXUy3BwUwDju235GExYfIBEADMsiKpgf0sGKeW 29 | a5uzMKZgnMm1MoRFBJNsjmBZrbsMxn6lf2ry3XM1xw/w15lepn4X/EMDLeRw 30 | 1m3vw4JL7dLY6e2oOllWyscCs+qE8Cwwx9x6q/gAMfwyrqMQ5EH8psIrRKZM 31 | eZwGEnSIuUXtJu3ShyqZUqfbpXhr+TxUEXY7n7NuCRJeM70PWPZB5IC1h3Bp 32 | kgxMRP4zHN2VG4PlcX2fLjpYsx1BHtR2T1biYxbk1AZ26s97XEMH7t9oe+8b 33 | G+QZc500MmPOd+62UZmnOf/Dul9q/H/0+IlWlWSUTTZFtlL+LwR56t28xqca 34 | FjUW8TXv6zYUvY7kk5Mlf2iWPA11wJuHaL5DnGaOoNgFVzicNQKy3SfeuYyp 35 | rSwClM37jRKw+ZNGQDPSAhtrwYZxtndCw/jieqdxIbFG9Td+BunpJNE+KICN 36 | jmnvG5JrzdueKAyTGqxNOtQnNDJYcg+p5rZVZHGQMN/22n2aiRpWhVAdJIXE 37 | YgpsFH6R01N3Y55RFNrhusOhuWodj0XuS1EhknU47XyIpNVSZhWG/e+vXMHb 38 | sN5cO0V7iCFrSxKXg6AwVneoWJC5anT9IabIcgAz07SjdjceC2MlW0vdjPks 39 | FNygBlP9fTIjBGRzg5QQCh/LyyFUTr1rYRbF+4k5kBQ3MtD2a/lS3Sk1MK/+ 40 | Es9PfWaAoNLB+QGqSi1qtIhds22zelOtc2MGFxgwb/iNZOUccauv6OXThvDD 41 | gzpn7gZi0+N7pOwx9lJM9QgC4hTMlo268vhNd/MMIPMeyp5n5D8p8ewAutZm 42 | AcIJkP3h2tUG1V/RvVLF22F+ilh3h++7TeSfHdTdv6ArwDJXdQunHCp3020f 43 | vhT6XG0ND+UMFtrptJe7+NoRpNg9oZo6kvwDzhPdIa2OlVjXmr25ueC8FlET 44 | cYdFbIisK+std7/XMlkE5wlGkf9G0RoHsxXqB2Nsj8l3qF5UNyWD+/2Wh+L9 45 | CDjUbY1FxwlVJ4UZ7lz+8jWHO5jYY99adPoATpUaWYxm9oPxz/QR4kvgvLjl 46 | 9Ti8379Y8qihzqsRmf6YLYyggknlt9Uyl2HjA+1zcwbDnb3I6g/XjTFUPy1D 47 | xZqqSEuCNDLh7m1+GDA3KXQnLIqOdcxOVzyFCDtKI9c6b0D0ezNkxUjgkoIp 48 | mxSSLDjzmHuPLsQVwqxP4KNU1gT7mXTnhlhsG2Vll/WZD+tuzGK8h9anf6/p 49 | 4pCk61Dhj1hmb9msTaK4FGhmBMtJ6kQ4SzGOfFKG5IElAHidYgd0iz7AqEzX 50 | GttDkcHGM9iPIYUBY2r/538M/kxeVx5fBiWEkmWz5FMzqPRs3GZWYiAb2tnp 51 | WSDXW3B1mwznwcCkyUP6OP/c6FFmb6Rag/ZaItVAvVjmA7tXICLJPhYIs9hE 52 | I6zJSVZ81YtKg9Nb6Rx49qf18pQ1SWZNGrZrWaTJTLu4cu4c5v/czY5kyT0Y 53 | 8RqNUlI5hwWU8G9LpJ5jv8dssrgcweTG/PEbCkzqz0R6W6VgDUyqo6WSGgoS 54 | B9or791lGcDazNT6CJ4/2Z1wBd4BSHkhSwfcPovGOleZFE24gLiG6puHyVjk 55 | WEIir2WXzhypwLkG/dn+ZJW1ezOvTb4gVVILHrWhNh8= 56 | =LoZg 57 | -----END PGP MESSAGE----- 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@argonjs/aframe-extensions", 3 | "version": "1.1.1", 4 | "description": "A-Frame integration with Argon.", 5 | "main": "src/index.js", 6 | "homepage": "https://aframe.argonjs.io/", 7 | "scripts": { 8 | "build": "browserify examples/main.js -o examples/build.js", 9 | "devsite": "npm run build && jekyll build --config _config-develop.yml", 10 | "testsite": "npm run build && jekyll build --config _config-test.yml", 11 | "dev": "budo _site/main.js:build.js --dir _site --port 8001 --live --open", 12 | "devssl": "budo _site/main.js:build.js --dir _site --port 8001 --live --open --ssl ", 13 | "dist": "webpack src/index.js dist/argon-aframe.js && webpack -p src/index.js dist/argon-aframe.min.js", 14 | "distsite": "jekyll build --config _config-master.yml", 15 | "postpublish": "npm run dist", 16 | "test": "karma start ./tests/karma.conf.js", 17 | "unboil": "node scripts/unboil.js" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/argonjs/argon-aframe.git" 22 | }, 23 | "keywords": [ 24 | "aframe", 25 | "argon", 26 | "argonjs", 27 | "argon-aframe", 28 | "argon-aframe-component", 29 | "argon-aframe-components", 30 | "aframe-argon-component", 31 | "aframe-argon-components", 32 | "aframe-argon", 33 | "layout", 34 | "aframe-ar", 35 | "ar" 36 | ], 37 | "author": "Blair MacIntyre ", 38 | "license": "Apache 2.0", 39 | "bugs": { 40 | "url": "https://github.com/argonjs/argon-aframe/issues" 41 | }, 42 | "dependencies": { 43 | "aframe": "^0.5.0", 44 | "@argonjs/argon": "^1.2.0-16" 45 | }, 46 | "devDependencies": { 47 | "browserify": "^12.0.1", 48 | "budo": "^9.2.1", 49 | "chai": "^3.4.1", 50 | "chai-shallow-deep-equal": "^1.3.0", 51 | "ghpages": "0.0.3", 52 | "json-loader": "^0.5.4", 53 | "karma": "^0.13.15", 54 | "karma-browserify": "^4.4.2", 55 | "karma-chai-shallow-deep-equal": "0.0.4", 56 | "karma-firefox-launcher": "^0.1.7", 57 | "karma-mocha": "^0.2.1", 58 | "karma-mocha-reporter": "^1.1.3", 59 | "karma-sinon-chai": "^1.1.0", 60 | "mocha": "^2.3.4", 61 | "webpack": "^1.12.9" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/ar-components.js: -------------------------------------------------------------------------------- 1 | var zeroScale = 0.00001; 2 | 3 | AFRAME.registerComponent('fixedsize', { 4 | schema: { 5 | default: 1 6 | }, 7 | 8 | init: function () { 9 | this.scale = 1; 10 | this.factor = 1; 11 | }, 12 | 13 | update: function () { 14 | var data = this.data; 15 | this.scale = data === 0 ? zeroScale : data; 16 | }, 17 | 18 | tick: function (t) { 19 | var object3D = this.el.object3D; 20 | var camera = this.el.sceneEl.camera; 21 | if (!camera) {return;} 22 | 23 | var cameraPos = camera.getWorldPosition(); 24 | var thisPos = object3D.getWorldPosition(); 25 | var distance = thisPos.distanceTo(cameraPos); 26 | 27 | // base the factor on the viewport height. 28 | // I think we need to use the renderviewport size, since we really care about what is rendered. 29 | // This means that when we're rendering on an HMD, and are using this to scale HTML content, the content might be 30 | // the wrong size 31 | var height = this.el.sceneEl.argonApp.view.renderHeight; 32 | this.factor = 2 * (this.scale / height); 33 | 34 | // let's get the fov scale factor from the camera 35 | fovScale = Math.tan(THREE.Math.degToRad(camera.fov) / 2) * 2; 36 | 37 | // if distance < near clipping plane, just use scale at the near plane. Don't go any bigger 38 | var factor = fovScale * (distance < camera.near ? camera.near * this.factor : distance * this.factor); 39 | object3D.scale.set(factor, factor, factor); 40 | } 41 | }); 42 | 43 | AFRAME.registerComponent('trackvisibility', { 44 | schema: { 45 | default: true 46 | }, 47 | 48 | init: function () { 49 | var self = this; 50 | this.el.addEventListener('referenceframe-statuschanged', function(evt) { 51 | self.updateVisibility(evt); 52 | }); 53 | }, 54 | 55 | updateVisibility: function (evt) { 56 | console.log("visibility changed: " + evt.detail.found) 57 | if (this.data && evt.detail.target === this.el) { 58 | this.el.object3D.visible = evt.detail.found; 59 | } 60 | }, 61 | 62 | update: function () { 63 | } 64 | }); 65 | 66 | AFRAME.registerComponent('physical', { 67 | schema: { 68 | default: true 69 | }, 70 | 71 | init: function () { 72 | }, 73 | 74 | // "mesh" could change and we won't be notified. Bummer 75 | update: function (oldData) { 76 | var mesh = this.el.getOrCreateObject3D("mesh"); 77 | if (mesh) { 78 | mesh.material.colorWrite = !this.data; // only update the depth 79 | mesh.renderOrder = this.data ? -2 : 0; // before everything else 80 | } 81 | } 82 | }); 83 | 84 | AFRAME.registerComponent('show-in', { 85 | schema: { 86 | ar: {default: false}, 87 | vr: {default: false}, 88 | "arhmd": { default: false}, 89 | "vrhmd": { default: false} 90 | }, 91 | 92 | init: function () { 93 | var self = this; 94 | this.el.sceneEl.addEventListener('enter-vr', function (evt) { self.updateVisibility(evt); }); 95 | this.el.sceneEl.addEventListener('exit-vr', function (evt) { self.updateVisibility(evt); }); 96 | this.el.sceneEl.addEventListener('enter-ar', function (evt) { self.updateVisibility(evt); }); 97 | this.el.sceneEl.addEventListener('exit-ar', function (evt) { self.updateVisibility(evt); }); 98 | self.updateVisibility(); 99 | }, 100 | 101 | updateVisibility: function () { 102 | var sceneEl = this.el.sceneEl; 103 | 104 | var armode = sceneEl.is('ar-mode'); 105 | var hmdmode = sceneEl.is('vr-mode'); 106 | 107 | var data = this.data; 108 | var visible = false; 109 | 110 | if (data.arhmd && armode && hmdmode) { visible = true;} 111 | if (data.vrhmd && !armode && hmdmode) { visible = true;} 112 | if (data.ar && armode) { visible = true;} 113 | if (data.vr && !armode) { visible = true;} 114 | 115 | this.el.object3D.visible = visible; 116 | }, 117 | 118 | update: function () { 119 | } 120 | }); 121 | 122 | AFRAME.registerComponent('desiredreality', { 123 | schema: { 124 | src: {type: 'src'}, 125 | name: {default: "Custom Reality"} 126 | }, 127 | 128 | init: function () { 129 | var el = this.el; 130 | 131 | if (!el.isArgon) { 132 | console.warn('vuforiadataset should be attached to an .'); 133 | } 134 | }, 135 | 136 | remove: function () { 137 | var el = this.el; 138 | if (el.isArgon) { 139 | el.argonApp.reality.setDesired(undefined); 140 | } 141 | }, 142 | 143 | update: function () { 144 | var el = this.el; 145 | var data = this.data; 146 | 147 | if (el.isArgon) { 148 | el.argonApp.reality.setDesired({ 149 | title: data.name, 150 | uri: Argon.resolveURL(data.src) 151 | }); 152 | } 153 | } 154 | }); 155 | 156 | AFRAME.registerComponent('enablehighaccuracy', { 157 | schema: { 158 | default: true 159 | }, 160 | 161 | init: function () { 162 | var el = this.el; 163 | 164 | if (!el.isArgon) { 165 | console.warn('enablehighaccuracy should be attached to an .'); 166 | } 167 | }, 168 | 169 | update: function () { 170 | var el = this.el; 171 | var data = this.data; 172 | 173 | // do nothing if it's not an argon scene entity 174 | if (el.isArgon) { 175 | // remember our current desired accuracy 176 | el.enableHighAccuracy = data; 177 | 178 | // re-request geolocation, so it uses the new accuracy 179 | el.subscribeGeolocation(); 180 | } 181 | } 182 | }); 183 | 184 | 185 | /* 186 | * create some lights based on the sun and moon 187 | */ 188 | AFRAME.registerComponent('sunmoon', { 189 | schema: { 190 | default: true 191 | }, 192 | 193 | init: function () { 194 | var el = this.el; 195 | 196 | if (!el.isArgon) { 197 | console.warn('sunmoon should be attached to an .'); 198 | } 199 | // requires that you've included 200 | if (THREE.SunMoonLights) { 201 | // this needs geoposed content, so subscribe to geolocation updates 202 | if (el.isArgon) { 203 | this.el.subscribeGeolocation(); 204 | } 205 | this.sunMoonLights = new THREE.SunMoonLights(); 206 | window.CESIUM_BASE_URL='https://samples-develop.argonjs.io/resources/cesium/'; 207 | } 208 | }, 209 | 210 | remove: function () { 211 | var el = this.el; 212 | if (el.isArgon && this.sunMoonLights) { 213 | this.sunMoonLights = null; 214 | this.el.removeObject3D('sunmoon'); 215 | } 216 | }, 217 | 218 | update: function () { 219 | var el = this.el; 220 | var data = this.data; 221 | 222 | if (el.isArgon) { 223 | if (data) { 224 | this.el.setObject3D('sunmoon', this.sunMoonLights.lights); 225 | } else { 226 | this.el.removeObject3D('sunmoon'); 227 | } 228 | } 229 | }, 230 | 231 | tick: function () { 232 | if (this.data && this.sunMoonLights) { 233 | var context = this.el.argonApp.context; 234 | this.sunMoonLights.update(context.time,context.defaultReferenceFrame); 235 | } 236 | } 237 | }); 238 | 239 | /** 240 | * based on https://github.com/Utopiah/aframe-triggerbox-component 241 | * 242 | * Usage will make a 10 unit 243 | * trigger region around the entity that emits the event mytrigger_entered once 244 | * the camera moves in and event mytrigger_exited once the camera leaves it. 245 | * 246 | * It can also be used on other entity e.g. an enemy or a bonus. 247 | * 248 | * inspired by https://github.com/atomicguy/aframe-fence-component/ 249 | * 250 | */ 251 | AFRAME.registerComponent('trigger', { 252 | multiple: true, 253 | schema: { 254 | radius: {default: 1}, 255 | event: {default: 'trigger'}, 256 | initial: {default: false} 257 | }, 258 | init: function() { 259 | // we don't know yet where we are 260 | this.teststateset = false; 261 | this.laststateinthetrigger = false; 262 | this.name = ""; 263 | }, 264 | update: function (oldData) { 265 | this.radiusSquared = this.data.radius * this.data.radius; 266 | this.name = this.id ? this.id : ""; 267 | }, 268 | tick: function() { 269 | // gathering all the data 270 | var data = this.data; 271 | var thisradiusSquared = this.radiusSquared; 272 | var triggereventname = data.event; 273 | var laststateset = this.laststateset; 274 | var laststateinthetrigger = this.laststateinthetrigger; 275 | var camera = this.el.sceneEl.camera; 276 | 277 | // camera might not be set immediately 278 | if (!camera) { return; } 279 | 280 | var cameraPosition = camera.position; 281 | //var position = this.el.getComputedAttribute('position'); 282 | // we don't want the attribute value, we want the "real" value 283 | var distanceSquared = this.el.object3D.position.distanceToSquared(cameraPosition); 284 | 285 | if (distanceSquared <= thisradiusSquared) { 286 | // we are in 287 | if ((!laststateset && data.initial) || (laststateset && !laststateinthetrigger)){ 288 | this.el.emit(triggereventname, {name: this.name, inside: true, initial: !laststateset, distanceSquared: distanceSquared}); 289 | } 290 | this.laststateinthetrigger = true; 291 | } else { 292 | // we are out 293 | if ((!laststateset && data.initial) || (laststateset && laststateinthetrigger)){ 294 | // we were not before 295 | this.el.emit(triggereventname, {name: this.name, inside: false, initial: !laststateset, distanceSquared: distanceSquared}); 296 | } 297 | this.laststateinthetrigger = false; 298 | } 299 | this.laststateset = true; 300 | }, 301 | 302 | }); 303 | 304 | -------------------------------------------------------------------------------- /src/ar-referenceframe.js: -------------------------------------------------------------------------------- 1 | var Cesium = Argon.Cesium; 2 | var Cartesian3 = Cesium.Cartesian3; 3 | var Cartographic = Cesium.Cartographic; 4 | var ConstantPositionProperty = Cesium.ConstantPositionProperty; 5 | var ReferenceFrame = Cesium.ReferenceFrame; 6 | var ReferenceEntity = Cesium.ReferenceEntity; 7 | var degToRad = THREE.Math.degToRad; 8 | 9 | // radius of earth is ~6200000, so this means "unset" 10 | var _ALTITUDE_UNSET = -7000000; 11 | 12 | /** 13 | * referenceframe component for A-Frame. 14 | * 15 | * Use an Argon reference frame as the coordinate system for the position and 16 | * orientation for this entity. The position and orientation components are 17 | * expressed relative to this frame. 18 | * 19 | * By default, it uses both the position and orientation of the reference frame 20 | * to define a coordinate frame for this entity, but either may be ignored, in which 21 | * case the identity will be used. This is useful, for example, if you wish to have 22 | * this entity follow the position of a referenceframe but be oriented in the 23 | * coordinates of its parent (typically scene coordinates). 24 | * 25 | * Known frames include ar.user, ar.device, ar.localENU, ar.localEUS, 26 | * ar.device.orientation, ar.device.geolocation, ar.device.display 27 | */ 28 | AFRAME.registerComponent('referenceframe', { 29 | schema: { 30 | lla: { type: 'vec3', default: {x: 0, y: 0, z: _ALTITUDE_UNSET}}, 31 | parent: { default: "FIXED" }, 32 | userotation: { default: true}, 33 | useposition: { default: true} 34 | }, 35 | 36 | /** 37 | * Nothing to do 38 | */ 39 | init: function () { 40 | var el = this.el; // entity 41 | var self = this; 42 | 43 | this.update = this.update.bind(this); 44 | 45 | if (!el.sceneEl) { 46 | console.warn('referenceFrame initialized but no sceneEl'); 47 | this.finishedInit = false; 48 | } else { 49 | this.finishedInit = true; 50 | } 51 | 52 | // this component only works with an Argon Scene 53 | // (sometimes, el.sceneEl is undefined when we get here. weird) 54 | if (el.sceneEl && !el.sceneEl.isArgon) { 55 | console.warn('referenceframe must be used on a child of a .'); 56 | } 57 | this.localRotationEuler = new THREE.Euler(0,0,0,'XYZ'); 58 | this.localPosition = { x: 0, y: 0, z: 0 }; 59 | this.localScale = { x: 1, y: 1, z: 1 }; 60 | this.knownFrame = false; 61 | el.addEventListener('componentchanged', this.updateLocalTransform.bind(this)); 62 | 63 | if (el.sceneEl) { 64 | el.sceneEl.addEventListener('argon-initialized', function() { 65 | self.update(self.data); 66 | }); 67 | } 68 | }, 69 | 70 | checkFinished: function () { 71 | if (!this.finishedInit) { 72 | this.finishedInit = true; 73 | this.update(this.data); 74 | } 75 | }, 76 | 77 | /** 78 | * Update 79 | */ 80 | update: function (oldData) { 81 | if (!this.el.sceneEl) { return; } 82 | 83 | var el = this.el; 84 | var sceneEl = el.sceneEl; 85 | var argonApp = sceneEl.argonApp; 86 | var data = this.data; 87 | 88 | var lp = el.getAttribute('position'); 89 | if (lp) { 90 | this.localPosition.x = lp.x; 91 | this.localPosition.y = lp.y; 92 | this.localPosition.z = lp.z; 93 | } else { 94 | this.localPosition.x = 0; 95 | this.localPosition.y = 0; 96 | this.localPosition.z = 0; 97 | } 98 | 99 | var lo = el.getAttribute('rotation'); 100 | if (lo) { 101 | this.localRotationEuler.x = degToRad(lo.x); 102 | this.localRotationEuler.y = degToRad(lo.y); 103 | this.localRotationEuler.z = degToRad(lo.z); 104 | } else { 105 | this.localRotationEuler.x = 0; 106 | this.localRotationEuler.y = 0; 107 | this.localRotationEuler.z = 0; 108 | } 109 | 110 | var ls = el.getAttribute('scale'); 111 | if (ls) { 112 | this.localScale.x = ls.x; 113 | this.localScale.y = ls.y; 114 | this.localScale.z = ls.z; 115 | } else { 116 | this.localScale.x = 1; 117 | this.localScale.y = 1; 118 | this.localScale.z = 1; 119 | } 120 | if (!argonApp) { 121 | return; 122 | } 123 | 124 | if (data.parent == "FIXED") { 125 | // this app uses geoposed content, so subscribe to geolocation updates 126 | sceneEl.subscribeGeolocation(); 127 | } 128 | 129 | // parentEntity is either FIXED or another Entity or ReferenceEntity 130 | var parentEntity = this.getParentEntity(data.parent); 131 | 132 | var cesiumPosition = null; 133 | if (this.attrValue.hasOwnProperty('lla')) { 134 | if (data.parent !== 'FIXED') { 135 | console.warn("Using 'lla' with a 'parent' other than 'FIXED' is invalid. Ignoring parent value."); 136 | data.parent = 'FIXED'; 137 | } 138 | //cesiumPosition = Cartesian3.fromDegrees(data.lla.x, data.lla.y, data.lla.z); 139 | if (data.lla.z === _ALTITUDE_UNSET) { 140 | 141 | cesiumPosition = Cartographic.fromDegrees(data.lla.x, data.lla.y); 142 | var self = this; 143 | 144 | var promise = Argon.updateHeightFromTerrain(cesiumPosition); 145 | 146 | if (!promise) { 147 | console.log("failed to get height! "); 148 | } else { 149 | promise.then(function() { 150 | console.log("found height for " + data.lla.x + ", " + data.lla.y + " => " + cesiumPosition.height); 151 | if (cesiumPosition.height) { 152 | self.data.lla.z = cesiumPosition.height; 153 | } 154 | self.update(self.data); 155 | }).catch(function(e) { 156 | console.log(e); 157 | }); 158 | } 159 | console.log("initial height for " + data.lla.x + ", " + data.lla.y + " => " + cesiumPosition.height); 160 | } else { 161 | console.log("had a valid altitude: " + data.lla.z) 162 | cesiumPosition = Cartographic.fromDegrees(data.lla.x, data.lla.y, data.lla.z); 163 | } 164 | 165 | var newEntity = argonApp.entity.createFixed(cesiumPosition, Argon.eastUpSouthToFixedFrame); 166 | if (el.id !== '') { 167 | newEntity._id = el.id; 168 | } 169 | 170 | // The first time here, we'll use the new cesium Entity. 171 | // If the id has changed, we'll also use the new entity with the new id. 172 | // Otherwise, we just update the entity's position. 173 | if (this.cesiumEntity == null || (el.id !== "" && el.id !== this.cesiumEntity.id)) { 174 | this.cesiumEntity = newEntity; 175 | } else { 176 | this.cesiumEntity.position = newEntity.position; 177 | this.cesiumEntity.orientation = newEntity.orientation; 178 | } 179 | 180 | } else { 181 | // The first time here, we'll create a cesium Entity. If the id has changed, 182 | // we'll recreate a new entity with the new id. 183 | // Otherwise, we just update the entity's position. 184 | if (this.cesiumEntity == null || (el.id !== "" && el.id !== this.cesiumEntity.id)) { 185 | var options = { 186 | position: new ConstantPositionProperty(Cartesian3.ZERO, parentEntity), 187 | orientation: Cesium.Quaternion.IDENTITY 188 | } 189 | if (el.id !== '') { 190 | options.id = el.id; 191 | } 192 | this.cesiumEntity = new Cesium.Entity(options); 193 | } else { 194 | // reset both, in case it was an LLA previously (weird, but valid) 195 | this.cesiumEntity.position.setValue(Cartesian3.ZERO, parentEntity); 196 | this.cesiumEntity.orientation.setValue(Cesium.Quaternion.IDENTITY); 197 | } 198 | } 199 | 200 | }, 201 | 202 | getParentEntity: function (parent) { 203 | var el = this.el; 204 | var self = this; 205 | var argonApp = this.el.sceneEl.argonApp; 206 | 207 | var parentEntity = null; 208 | 209 | if (parent === 'FIXED') { 210 | parentEntity = ReferenceFrame.FIXED; 211 | } else { 212 | var vuforia = el.sceneEl.systems["vuforia"]; 213 | if (vuforia) { 214 | var parts = parent.split("."); 215 | if (parts.length === 3 && parts[0] === "vuforia") { 216 | // see if it's already a known target entity 217 | console.log("looking for target '" + parent + "'"); 218 | 219 | parentEntity = vuforia.getTargetEntity(parts[1], parts[2]); 220 | 221 | // if not known, subscribe to it 222 | if (parentEntity === null) { 223 | console.log("not found, subscribing to target '" + parent + "'"); 224 | parentEntity = vuforia.subscribeToTarget(parts[1], parts[2]); 225 | } 226 | 227 | // if still not known, try again when our dataset is loaded 228 | if (parentEntity === null) { 229 | console.log("not loaded, waiting for dataset for target '" + parent + "'"); 230 | var name = parts[1]; 231 | el.sceneEl.addEventListener('argon-vuforia-dataset-loaded', function(evt) { 232 | console.log('dataset loaded.'); 233 | console.log("dataset name '" + evt.detail.target.name + "', our name '" + name + "'"); 234 | if (evt.detail.target.name === name) { 235 | self.update(self.data); 236 | } 237 | }); 238 | console.log("finished setting up to wait for dataset for target '" + parent + "'"); 239 | } 240 | } 241 | } 242 | 243 | // if it's a vuforia refernece frame, we might have found it above. Otherwise, look for 244 | // an entity with the parent ID 245 | if (!parentEntity) { 246 | parentEntity = argonApp.context.entities.getById(parent); 247 | } 248 | // If we didn't find the entity at all, create it 249 | if (!parentEntity) { 250 | parentEntity = new ReferenceEntity(argonApp.context.entities, parent); 251 | } 252 | } 253 | return parentEntity; 254 | }, 255 | 256 | convertReferenceFrame: function (newParent) { 257 | var el = this.el; // entity 258 | 259 | // can't do anything without a cesium entity 260 | if (!this.cesiumEntity) { 261 | console.warn("Tried to convertReferenceFrame on element '" + el.id + "' but no cesiumEntity initialized on that element"); 262 | return; 263 | } 264 | 265 | // eventually we'll convert the current reference frame to a new one, keeping the pose the same 266 | // but a bunch of changes are needed above to make this work 267 | 268 | }, 269 | 270 | updateLocalTransform: function (evt) { 271 | var data = evt.detail.newData; 272 | if (evt.target != this.el) { return; } 273 | 274 | if (evt.detail.name == 'rotation') { 275 | this.localRotationEuler.x = degToRad(data.x); 276 | this.localRotationEuler.y = degToRad(data.y); 277 | this.localRotationEuler.z = degToRad(data.z); 278 | } else if (evt.detail.name == 'position') { 279 | this.localPosition.x = data.x; 280 | this.localPosition.y = data.y; 281 | this.localPosition.z = data.z; 282 | } else if (evt.detail.name == 'scale') { 283 | this.localScale.x = data.x; 284 | this.localScale.y = data.y; 285 | this.localScale.z = data.z; 286 | } 287 | }, 288 | 289 | /** 290 | * update each time step. 291 | */ 292 | tick: function () { 293 | var m1 = new THREE.Matrix4(); 294 | 295 | return function(t) { 296 | this.checkFinished(); 297 | 298 | var data = this.data; // parameters 299 | var el = this.el; // entity 300 | var object3D = el.object3D; 301 | var matrix = object3D.matrix; 302 | var argonApp = el.sceneEl.argonApp; 303 | var isNestedEl = !el.parentEl.isScene; 304 | 305 | if (!argonApp) { return }; 306 | 307 | if (this.cesiumEntity) { 308 | var entityPos = argonApp.context.getEntityPose(this.cesiumEntity); 309 | if (entityPos.poseStatus & Argon.PoseStatus.KNOWN) { 310 | this.knownFrame = true; 311 | if (data.userotation) { 312 | object3D.quaternion.copy(entityPos.orientation); 313 | } else if (isNestedEl) { 314 | object3D.rotation.copy(this.localRotationEuler); 315 | object3D.rotation.order = 'YXZ'; 316 | } 317 | if (data.useposition) { 318 | object3D.position.copy(entityPos.position); 319 | } else if (isNestedEl) { 320 | object3D.position.copy(this.localPosition); 321 | } 322 | if (entityPos.poseStatus & Argon.PoseStatus.FOUND) { 323 | console.log("reference frame changed to FOUND"); 324 | el.emit('referenceframe-statuschanged', { 325 | target: this.el, 326 | found: true 327 | }); 328 | } 329 | 330 | // if this isn't a child of the scene, move it to world coordinates 331 | if (!el.parentEl.isScene) { 332 | object3D.scale.set(1,1,1); 333 | el.parentEl.object3D.updateMatrixWorld(); 334 | m1.getInverse(el.parentEl.object3D.matrixWorld); 335 | matrix.premultiply(m1); 336 | matrix.decompose(object3D.position, object3D.quaternion, object3D.scale ); 337 | object3D.updateMatrixWorld(); 338 | } 339 | } else { 340 | this.knownFrame = false; 341 | if (entityPos.poseStatus & Argon.PoseStatus.LOST) { 342 | console.log("reference frame changed to LOST"); 343 | el.emit('referenceframe-statuschanged', { 344 | target: this.el, 345 | found: false 346 | }); 347 | } 348 | } 349 | } 350 | }; 351 | }() 352 | }); 353 | 354 | AFRAME.registerPrimitive('ar-geopose', { 355 | defaultComponents: { 356 | referenceframe: {} 357 | }, 358 | 359 | mappings: { 360 | lla: 'referenceframe.lla', 361 | userotation: 'referenceframe.userotation', 362 | useposition: 'referenceframe.useposition' 363 | } 364 | }); 365 | 366 | AFRAME.registerPrimitive('ar-frame', { 367 | defaultComponents: { 368 | referenceframe: {} 369 | }, 370 | 371 | mappings: { 372 | parent: 'referenceframe.parent', 373 | userotation: 'referenceframe.userotation', 374 | useposition: 'referenceframe.useposition' 375 | } 376 | }); 377 | -------------------------------------------------------------------------------- /src/ar-vuforia.js: -------------------------------------------------------------------------------- 1 | AFRAME.registerSystem('vuforia', { 2 | init: function () { 3 | this.key = ""; 4 | this.api = null; 5 | this.datasetMap = {}; 6 | this.available = false; 7 | 8 | this.sceneEl.addEventListener('argon-initialized', this.startVuforia.bind(this)); 9 | }, 10 | 11 | setKey: function (key) { 12 | this.key = key; 13 | 14 | if (this.sceneEl.argonApp) { 15 | this.startVuforia(); 16 | } 17 | }, 18 | 19 | startVuforia: function() { 20 | var self = this; 21 | var sceneEl = this.sceneEl; 22 | var argonApp = sceneEl.argonApp; 23 | 24 | // need argon 25 | if (!argonApp) { return; } 26 | 27 | // if there is no vuforia API, bye bye 28 | if (!argonApp.vuforia) { return; } 29 | 30 | // if already initialized, bye bye 31 | if (this.api) { return; } 32 | 33 | // can't initialize if we don't have the key yet 34 | if (this.key === "") { return; } 35 | 36 | // try to initialize 37 | argonApp.vuforia.isAvailable().then(function(available) { 38 | if (self.available) { 39 | // this code has already run, through to telling argon to initialize vuforia! 40 | return; 41 | } 42 | 43 | // vuforia not available on this platform 44 | if (!available) { 45 | self.available = false; 46 | console.warn('vuforia not available on this platform.'); 47 | 48 | // in case an application wants to take action when vuforia isn't supported 49 | sceneEl.emit('argon-vuforia-not-available', { 50 | target: sceneEl 51 | }); 52 | return; 53 | } 54 | 55 | // vuforia is available! 56 | self.available = true; 57 | 58 | // try to initialize with our key 59 | argonApp.vuforia.init({ 60 | //licenseKey: self.key 61 | encryptedLicenseData: self.key 62 | }).then(function(api) { 63 | // worked! Save the API 64 | self.api = api; 65 | 66 | console.log("vuforia initialized!") 67 | 68 | // re-call createOrUpdateDataset to create datasets already requested 69 | Object.keys(self.datasetMap).forEach(function(key,index) { 70 | var dataset = self.datasetMap[key]; 71 | console.log("re-initializing dataset " + key + " as active=" + dataset.active); 72 | self.createOrUpdateDataset(dataset.component, key, dataset.url, dataset.active) 73 | }); 74 | 75 | // tell everyone the good news 76 | sceneEl.emit('argon-vuforia-initialized', { 77 | target: sceneEl 78 | }); 79 | }).catch(function(err) { 80 | console.log("vuforia failed to initialize: " + err.message); 81 | 82 | sceneEl.emit('argon-vuforia-initialization-failed', { 83 | target: sceneEl, 84 | error: err 85 | }); 86 | }); 87 | }); 88 | }, 89 | 90 | // create an empty dataset 91 | createEmptyDatasetObject: function () { 92 | return { 93 | component: null, 94 | api: null, 95 | url: null, 96 | fetched: false, 97 | loaded: false, 98 | active: false, 99 | targets: {}, 100 | trackables: null, 101 | initInProgress: false 102 | }; 103 | }, 104 | 105 | // create a new dataset or update one currently created. 106 | createOrUpdateDataset: function (component, name, url, active) { 107 | var self = this; 108 | var api = this.api; 109 | var dataset = this.datasetMap[name]; 110 | 111 | // if dataset exists, and matches the previous element, it's because targets were registered before the 112 | // dataset was set up, which is fine. Otherwise, its a duplicate dataset name, which isn't allowed! 113 | if (dataset) { 114 | if (dataset.component) { 115 | if (dataset.component != component) { 116 | console.warn('vuforia.createOrUpdateDataset called multiple times for id=' + name + ', ignoring extra datasets'); 117 | return; 118 | } 119 | if (dataset.url != url) { 120 | console.warn("can't change the url for a vuforia dataset once it's created. Ignoring new URL '" + url + "' for dataset '" + name + "'") 121 | return; 122 | } 123 | } else { 124 | // first time this has been called, the dataset is there 125 | // because of calls to set up targets, etc. 126 | dataset.component = component; 127 | dataset.url = url; 128 | } 129 | } else { 130 | // set up the mapping if not there 131 | dataset = this.datasetMap[name] = this.createEmptyDatasetObject(); 132 | dataset.component = component; 133 | dataset.url = url; 134 | } 135 | 136 | dataset.active = active; 137 | 138 | console.log("creating dataset " + name + " active=" + active ); 139 | 140 | // if vuforia has not yet initialized, return. 141 | if (!api) { 142 | return; 143 | } 144 | 145 | if (dataset.initInProgress) { 146 | // just update the active flag, will get dealt with when fetch is done 147 | dataset.active = active; 148 | return; 149 | } 150 | 151 | // if the api is initialized, deal with the active state 152 | if (dataset.api) { 153 | dataset.active = active; 154 | 155 | // if already fetched, update the active state 156 | if (fetched) { 157 | self.setDatasetActive(name, dataset.active); 158 | } 159 | return; 160 | } 161 | 162 | console.log("objectTracker.createDataSet " + name ); 163 | 164 | dataset.initInProgress = true; 165 | // should have both vuforia and argon initialized by now 166 | api.objectTracker.createDataSet(url).then(function (data) { 167 | console.log("created dataset " + name ); 168 | 169 | dataset.initInProgress = false; 170 | dataset.api = data; 171 | data.fetch().then(function () { 172 | 173 | console.log("fetched dataset " + name ); 174 | 175 | dataset.fetched = true; 176 | 177 | console.log("now, re-activate dataset " + name + " active=" + dataset.active ); 178 | self.setDatasetActive(name, dataset.active); 179 | dataset.component.datasetLoaded = true; 180 | console.log("re-activated dataset " + name + " active=" + dataset.active ); 181 | 182 | // tell everyone the good news 183 | self.sceneEl.emit('argon-vuforia-dataset-downloaded', { 184 | target: dataset.component 185 | }); 186 | }).catch(function(err) { 187 | console.log("couldn't download dataset: " + err.message); 188 | 189 | sceneEl.emit('argon-vuforia-dataset-download-failed', { 190 | target: sceneEl, 191 | error: err 192 | }); 193 | }); 194 | }); 195 | }, 196 | 197 | setDatasetActive: function (name, active) { 198 | var self = this; 199 | var api = this.api; 200 | var dataset = this.datasetMap[name]; 201 | 202 | console.log("make dataset " + name + " active=" +active ); 203 | 204 | if (!api) { 205 | if (dataset) { 206 | dataset.active = active; 207 | return; 208 | } else { 209 | throw new Error('vuforia.setDatsetActive call before dataset initialized'); 210 | } 211 | } 212 | 213 | if (!dataset) { 214 | throw new Error('ar-vuforia-dataset "' + name + '" should have been created before being activated'); 215 | } 216 | 217 | console.log("really making dataset " + name + " active=" +active ); 218 | 219 | if (!dataset.loaded && active) { 220 | console.log("loading dataset " + name + " active=" +active ); 221 | dataset.api.load().then(function () { 222 | console.log("loaded dataset " + name + " active=" +active ); 223 | if (dataset.loaded) { return; } 224 | 225 | dataset.loaded = true; 226 | dataset.fetched = true; 227 | dataset.trackables = dataset.api.getTrackables(); 228 | if (active) { 229 | dataset.active = true; 230 | api.objectTracker.activateDataSet(dataset.api); 231 | } 232 | 233 | // re-call subscribeToTarget to subscribe the targets already requested 234 | Object.keys(dataset.targets).forEach(function(key,index) { 235 | console.log("re-subscribing to target " + name + "." + key ); 236 | self.subscribeToTarget(name, key, true); 237 | }); 238 | 239 | // tell everyone the good news. Include the trackables. 240 | self.sceneEl.emit('argon-vuforia-dataset-loaded', { 241 | target: dataset.component, 242 | trackables: dataset.trackables 243 | }); 244 | console.log("dataset " + name + " loaded, ready to go"); 245 | }).catch(function(err) { 246 | console.log("couldn't load dataset: " + err.message); 247 | 248 | sceneEl.emit('argon-vuforia-dataset-load-failed', { 249 | target: sceneEl, 250 | error: err 251 | }); 252 | }); 253 | } else { 254 | if (dataset.active != active) { 255 | dataset.active = active; 256 | if (active) { 257 | api.objectTracker.activateDataSet(dataset.api); 258 | } else { 259 | api.objectTracker.deactivateDataSet(dataset.api); 260 | } 261 | } 262 | } 263 | }, 264 | 265 | subscribeToTarget: function (name, target, postLoad) { 266 | var api = this.api; 267 | var dataset = this.datasetMap[name]; 268 | 269 | // set up the mapping if not there 270 | if (!dataset) { 271 | dataset = this.datasetMap[name] = this.createEmptyDatasetObject(); 272 | } 273 | 274 | // either create a new target entry and set the count, or add the count to an existing one 275 | var targetItem = dataset.targets[target]; 276 | if (!targetItem) { 277 | dataset.targets[target] = 1; 278 | } else if (!postLoad) { 279 | dataset.targets[target] += 1; 280 | } 281 | console.log("subscribe to " + name + "." + target) 282 | 283 | if (!api) { return null; } 284 | 285 | if (dataset.loaded) { 286 | var tracker = dataset.trackables[target]; 287 | console.log("dataset loaded, subscribe to " + name + "." + target) 288 | if (tracker && tracker.id) { 289 | console.log("subscribed to " + name + "." + target + " as " + tracker.id) 290 | return this.sceneEl.argonApp.context.subscribeToEntityById(tracker.id); 291 | } else { 292 | console.warn("can't subscribe to target '" + target + "' does not exist in dataset '" + name + "'"); 293 | return null; 294 | } 295 | } 296 | // not loaded yet 297 | return null; 298 | }, 299 | 300 | getTargetEntity: function (name, target) { 301 | var api = this.api; 302 | var dataset = this.datasetMap[name]; 303 | 304 | console.log("getTargetEntity " + name + "." + target) 305 | 306 | // set up the mapping if not there 307 | if (!api || !dataset || !dataset.loaded) { 308 | return null; 309 | } 310 | 311 | // check if we've subscribed. If we haven't, bail out, because we need to 312 | var targetItem = dataset.targets[target]; 313 | if (!targetItem) { 314 | return null; 315 | } 316 | 317 | var tracker = dataset.trackables[target]; 318 | console.log("everything loaded, get " + name + "." + target) 319 | if (tracker && tracker.id) { 320 | console.log("retrieved " + name + "." + target + " as " + tracker.id) 321 | return this.sceneEl.argonApp.context.entities.getById(tracker.id); 322 | } else { 323 | console.warn("can't get target '" + target + "', does not exist in dataset '" + name + "'"); 324 | } 325 | return null; 326 | } 327 | }); 328 | 329 | // the parameter to vuforia is a reference to a element. 330 | // If the element is an a-asset-item, the key should have been downloaded into its data property 331 | // Otherwise, assume the key is in the innerHTML (contents) of the element 332 | AFRAME.registerComponent('vuforiakey', { 333 | schema: { 334 | default: " " 335 | }, 336 | 337 | /** 338 | * Nothing to do 339 | */ 340 | init: function () { 341 | this.key = null; 342 | }, 343 | 344 | /** 345 | * Update: first time in, we initialize vuforia 346 | */ 347 | update: function (oldData) { 348 | var el = this.el; 349 | var sceneEl = this.el.sceneEl; 350 | var system = sceneEl.systems["vuforia"]; 351 | 352 | if (!el.isArgon) { 353 | console.warn('vuforia component can only be applied to '); 354 | return; 355 | } 356 | 357 | var keyAsset = el.querySelector(this.data); 358 | 359 | if (keyAsset) { 360 | if (keyAsset.isAssetItem) { 361 | this.key = keyAsset.data; 362 | system.setKey(keyAsset.data); 363 | } else { 364 | this.key = keyAsset.innerHTML; 365 | system.setKey(keyAsset.innerHTML); 366 | } 367 | } else { 368 | console.warn('vuforia component cannot find asset "' + this.data + '"'); 369 | return; 370 | } 371 | } 372 | }); 373 | 374 | AFRAME.registerComponent('vuforiadataset', { 375 | multiple: true, 376 | 377 | schema: { 378 | src: {type: 'src'}, 379 | active: {default: true} 380 | }, 381 | 382 | init: function () { 383 | var el = this.el; 384 | 385 | this.name = "default_dataset"; 386 | this.active = false; 387 | this.datasetLoaded = false; 388 | 389 | if (!el.isArgon) { 390 | console.warn('vuforiadataset should be attached to an .'); 391 | } 392 | }, 393 | 394 | remove: function () { 395 | if (this.active) { 396 | var sceneEl = this.el.sceneEl; 397 | var vuforia = sceneEl.systems["vuforia"]; 398 | vuforia.setDatasetActive(this.name, false); 399 | } 400 | // remove dataset from system, when argon supports that 401 | }, 402 | 403 | update: function (oldData) { 404 | var sceneEl = this.el.sceneEl; 405 | this.name = this.id ? this.id : "default_dataset"; 406 | 407 | var vuforia = sceneEl.systems["vuforia"]; 408 | vuforia.createOrUpdateDataset(this, this.name, this.data.src, this.data.active); 409 | } 410 | }); 411 | -------------------------------------------------------------------------------- /src/arframe.css: -------------------------------------------------------------------------------- 1 | ar-scene { 2 | display: block; 3 | position: relative; 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | ar-scene video, 9 | ar-scene img, 10 | ar-scene audio { 11 | display: none; 12 | } 13 | -------------------------------------------------------------------------------- /src/css-object.js: -------------------------------------------------------------------------------- 1 | AFRAME.registerComponent('css-object', { 2 | schema: { 3 | div: { default: '' }, 4 | div2: { default: ''} 5 | }, 6 | 7 | init: function () { 8 | this.div = null; 9 | this.div2 = null; 10 | }, 11 | 12 | update: function () { 13 | var data = this.data; 14 | if (data.div === "") { return; } 15 | 16 | this.div = document.querySelector(data.div); 17 | if (data.div2 !== "") { 18 | this.div2 = document.querySelector(data.div2); 19 | } 20 | if (this.div) { 21 | if (THREE.CSS3DObject) { 22 | if (this.div2 === null) { 23 | this.el.setObject3D('div', new THREE.CSS3DObject(this.div)); 24 | } else { 25 | this.el.setObject3D('div', new THREE.CSS3DObject([this.div, this.div2])); 26 | } 27 | } 28 | } 29 | }, 30 | 31 | remove: function () { 32 | if (!this.div) { return; } 33 | 34 | if (THREE.CSS3DObject) { 35 | this.el.removeObject3D('div'); 36 | } 37 | } 38 | }); 39 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | require('../src/ar-scene.js'); 2 | require('../src/ar-components.js'); 3 | require('../src/ar-referenceframe.js'); 4 | require('../src/css-object.js'); 5 | require('../src/ar-vuforia.js'); 6 | require('../src/panorama-reality.js'); -------------------------------------------------------------------------------- /src/panorama-reality.js: -------------------------------------------------------------------------------- 1 | AFRAME.registerComponent('panorama', { 2 | multiple: true, 3 | 4 | schema: { 5 | src: {type: 'src'}, 6 | lla: {type: 'vec3'}, 7 | initial: {default: false}, 8 | offsetdegrees: {default: 0}, 9 | easing: {default: "Quadratic.InOut"}, 10 | duration: {default: 500} 11 | }, 12 | 13 | init: function () { 14 | var el = this.el; 15 | 16 | this.name = "default"; 17 | this.active = false; 18 | this.panoRealitySession = undefined; 19 | this.panorama = undefined; 20 | this.showOptions = undefined; 21 | 22 | if (!el.isArgon) { 23 | console.warn('panorama should be attached to an .'); 24 | } else { 25 | el.argonApp.reality.connectEvent.addEventListener(this.realityWatcher.bind(this)); 26 | el.addEventListener("showpanorama", this.showPanorama.bind(this)); 27 | } 28 | }, 29 | 30 | update: function (oldData) { 31 | this.name = this.id ? this.id : "default"; 32 | 33 | this.panorama = { 34 | name: this.name, 35 | url: Argon.resolveURL(this.data.src), 36 | longitude: this.data.lla.x, 37 | latitude: this.data.lla.y, 38 | height: this.data.lla.z, 39 | offsetDegrees: this.data.offsetdegrees 40 | }; 41 | this.showOptions = { 42 | url: Argon.resolveURL(this.data.src), 43 | transition: { 44 | easing: this.data.easing, 45 | duration: this.data.duration 46 | } 47 | } 48 | }, 49 | 50 | realityWatcher: function(session) { 51 | // check if the connected supports our panorama protocol 52 | if (session.supportsProtocol('edu.gatech.ael.panorama')) { 53 | // save a reference to this session so our buttons can send messages 54 | this.panoRealitySession = session 55 | 56 | // load our panorama 57 | this.panoRealitySession.request('edu.gatech.ael.panorama.loadPanorama', this.panorama); 58 | 59 | if (this.data.initial) { 60 | // show yourself! 61 | this.el.emit("showpanorama", {name: this.name}); 62 | } 63 | 64 | var self = this; 65 | session.closeEvent.addEventListener(function(){ 66 | self.panoRealitySession = undefined; 67 | }) 68 | } 69 | }, 70 | 71 | showPanorama: function(evt) { 72 | if (evt.detail.name === this.name) { 73 | this.active = true; 74 | var self = this; 75 | 76 | if (this.panoRealitySession) { 77 | this.panoRealitySession.request('edu.gatech.ael.panorama.showPanorama', this.showOptions).then(function(){ 78 | console.log("showing panorama: " + self.name); 79 | 80 | self.el.emit('showpanorama-success', { 81 | name: self.name 82 | }); 83 | }).catch(function(err) { 84 | console.log("couldn't show panorama: " + err.message); 85 | 86 | self.el.emit('showpanorama-failed', { 87 | name: self.name, 88 | error: err 89 | }); 90 | }); 91 | } 92 | } else { 93 | this.active = false; 94 | } 95 | } 96 | }); 97 | -------------------------------------------------------------------------------- /src/shadow-material.js: -------------------------------------------------------------------------------- 1 | AFRAME.registerShader('shadow', { 2 | schema: { 3 | }, 4 | 5 | /** 6 | * Initializes the shader. 7 | * Adds a reference from the scene to this entity as the camera. 8 | */ 9 | init: function (data) { 10 | this.textureSrc = null; 11 | this.material = new THREE.ShadowMaterial(); 12 | AFRAME.utils.material.updateMap(this, data); 13 | }, 14 | 15 | update: function (data) { 16 | AFRAME.utils.material.updateMap(this, data); 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /src/stage-geolocation.js: -------------------------------------------------------------------------------- 1 | AFRAME.registerComponent('stagelocation', { 2 | schema: { 3 | type: 'vec3' 4 | }, 5 | 6 | init: function () { 7 | var el = this.el; 8 | 9 | this.geoRealitySession = undefined; 10 | 11 | if (!el.isArgon) { 12 | console.warn('stagelocation should be attached to an .'); 13 | } else { 14 | el.argonApp.reality.connectEvent.addEventListener(this.realityWatcher.bind(this)); 15 | } 16 | }, 17 | 18 | update: function (oldData) { 19 | this.geolocation = { 20 | geolocation: Argon.Cesium.Cartographics.fromDegrees(data.x, 21 | latitude: this.data.lla.y, 22 | height: this.data.lla.z, 23 | offsetDegrees: this.data.offsetdegrees 24 | }; 25 | this.showOptions = { 26 | url: Argon.resolveURL(this.data.src), 27 | transition: { 28 | easing: this.data.easing, 29 | duration: this.data.duration 30 | } 31 | } 32 | }, 33 | 34 | realityWatcher: function(session) { 35 | // check if the connected supports our panorama protocol 36 | if (session.supportsProtocol('edu.gatech.ael.panorama')) { 37 | // save a reference to this session so our buttons can send messages 38 | this.panoRealitySession = session 39 | 40 | // load our panorama 41 | this.panoRealitySession.request('edu.gatech.ael.panorama.loadPanorama', this.panorama); 42 | 43 | if (this.data.initial) { 44 | // show yourself! 45 | this.el.emit("showpanorama", {name: this.name}); 46 | } 47 | 48 | var self = this; 49 | session.closeEvent.addEventListener(function(){ 50 | self.panoRealitySession = undefined; 51 | }) 52 | } 53 | }, 54 | 55 | showPanorama: function(evt) { 56 | if (evt.detail.name === this.name) { 57 | this.active = true; 58 | var self = this; 59 | 60 | if (this.panoRealitySession) { 61 | this.panoRealitySession.request('edu.gatech.ael.panorama.showPanorama', this.showOptions).then(function(){ 62 | console.log("showing panorama: " + self.name); 63 | 64 | self.el.emit('showpanorama-success', { 65 | name: self.name 66 | }); 67 | }).catch(function(err) { 68 | console.log("couldn't show panorama: " + err.message); 69 | 70 | self.el.emit('showpanorama-failed', { 71 | name: self.name, 72 | error: err 73 | }); 74 | }); 75 | } 76 | } else { 77 | this.active = false; 78 | } 79 | } 80 | }); 81 | -------------------------------------------------------------------------------- /tests/__init.test.js: -------------------------------------------------------------------------------- 1 | /* global sinon, setup, teardown */ 2 | 3 | /** 4 | * __init.test.js is run before every test case. 5 | */ 6 | window.debug = true; 7 | 8 | var AScene = require('aframe-core').AScene; 9 | 10 | beforeEach(function () { 11 | this.sinon = sinon.sandbox.create(); 12 | // Stub to not create a WebGL context since Travis CI runs headless. 13 | this.sinon.stub(AScene.prototype, 'attachedCallback'); 14 | }); 15 | 16 | afterEach(function () { 17 | // Clean up any attached elements. 18 | ['a-assets', 'ar-scene'].forEach(function (tagName) { 19 | var els = document.querySelectorAll(tagName); 20 | for (var i = 0; i < els.length; i++) { 21 | els[i].parentNode.removeChild(els[i]); 22 | } 23 | }); 24 | AScene.scene = null; 25 | 26 | this.sinon.restore(); 27 | }); 28 | -------------------------------------------------------------------------------- /tests/helpers.js: -------------------------------------------------------------------------------- 1 | /* global suite */ 2 | 3 | /** 4 | * Helper method to create a scene, create an entity, add entity to scene, 5 | * add scene to document. 6 | * 7 | * @returns {object} An `` element. 8 | */ 9 | module.exports.entityFactory = function () { 10 | var scene = document.createElement('ar-scene'); 11 | var entity = document.createElement('a-entity'); 12 | scene.appendChild(entity); 13 | document.body.appendChild(scene); 14 | return entity; 15 | }; 16 | 17 | /** 18 | * Creates and attaches a mixin element (and an `` element if necessary). 19 | * 20 | * @param {string} id - ID of mixin. 21 | * @param {object} obj - Map of component names to attribute values. 22 | * @returns {object} An attached `` element. 23 | */ 24 | module.exports.mixinFactory = function (id, obj) { 25 | var mixinEl = document.createElement('a-mixin'); 26 | mixinEl.setAttribute('id', id); 27 | Object.keys(obj).forEach(function (componentName) { 28 | mixinEl.setAttribute(componentName, obj[componentName]); 29 | }); 30 | 31 | var assetsEl = document.querySelector('a-assets'); 32 | if (!assetsEl) { 33 | assetsEl = document.createElement('a-assets'); 34 | document.body.appendChild(assetsEl); 35 | } 36 | assetsEl.appendChild(mixinEl); 37 | 38 | return mixinEl; 39 | }; 40 | 41 | /** 42 | * Test that is only run locally and is skipped on CI. 43 | */ 44 | module.exports.getSkipCISuite = function () { 45 | if (window.__env__.TEST_ENV === 'ci') { 46 | return suite.skip; 47 | } else { 48 | return suite; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /tests/index.test.js: -------------------------------------------------------------------------------- 1 | var Aframe = require('aframe-core'); 2 | var example = require('../index.js').component; 3 | var entityFactory = require('./helpers').entityFactory; 4 | 5 | Aframe.registerComponent('example', example); 6 | 7 | describe('example', function () { 8 | beforeEach(function (done) { 9 | this.el = entityFactory(); 10 | this.el.addEventListener('loaded', function () { 11 | done(); 12 | }); 13 | }); 14 | 15 | describe('example property', function () { 16 | it('is good', function () { 17 | assert.equal(1, 1); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /tests/karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = function (config) { 3 | config.set({ 4 | basePath: '../', 5 | browserify: { 6 | paths: ['./'] 7 | }, 8 | browsers: ['firefox_latest'], 9 | customLaunchers: { 10 | firefox_latest: { 11 | base: 'FirefoxNightly', 12 | prefs: { /* empty */ } 13 | } 14 | }, 15 | client: { 16 | captureConsole: true, 17 | mocha: {ui: 'bdd'} 18 | }, 19 | envPreprocessor: [ 20 | 'TEST_ENV' 21 | ], 22 | files: [ 23 | 'tests/**/*.test.js', 24 | ], 25 | frameworks: ['mocha', 'sinon-chai', 'chai-shallow-deep-equal', 'browserify'], 26 | preprocessors: { 27 | 'tests/**/*.js': ['browserify'] 28 | }, 29 | reporters: ['mocha'] 30 | }); 31 | }; 32 | --------------------------------------------------------------------------------