Saltar al contenido
Marketplace

aframe-webxr

de freshtechbro

Declarative web framework for building browser-based 3D, VR, and AR experiences using HTML and entity-component architecture. Use this skill when creating WebXR applications, VR experiences, AR experiences, 360-degree media viewers, or immersive web content with minimal JavaScript. Triggers on tasks involving A-Frame, WebXR, VR development, AR development, entity-component-system, declarative 3D, or HTML-based 3D scenes. Built on Three.js with accessible HTML-first approach.

Esta skill incluye scripts que tu agente puede ejecutar. Ver qué archivos

Resumen

SKILL.mdLeída en 1da73fe

A-Frame WebXR Skill

When to Use This Skill

  • Build VR/AR experiences with minimal JavaScript
  • Create cross-platform WebXR applications (desktop, mobile, headset)
  • Prototype 3D scenes quickly with HTML primitives
  • Implement VR controller interactions
  • Add 3D content to web pages declaratively
  • Build 360° image/video experiences
  • Develop AR experiences with hit testing

Core Concepts

1. Entity-Component-System (ECS)

A-Frame uses an entity-component-system architecture where:

  • Entities are containers (like <div> in HTML)
  • Components add functionality/appearance to entities
  • Systems provide global functionality

<a-entity
  geometry="primitive: box; width: 2"
  material="color: red; metalness: 0.5"
  position="0 1.5 -3"
  rotation="0 45 0">
</a-entity>

Primitives are shortcuts for common entity + component combinations:


<a-box color="red" position="0 1.5 -3" rotation="0 45 0" width="2"></a-box>


<a-entity
  geometry="primitive: box; width: 2"
  material="color: red"
  position="0 1.5 -3"
  rotation="0 45 0">
</a-entity>
2. Scene Setup

Every A-Frame app starts with <a-scene>:

<!DOCTYPE html>
<html>
  <head>
    <script src="https://aframe.io/releases/1.7.1/aframe.min.js"></script>
  </head>
  <body>
    <a-scene>
      
      <a-box position="-1 0.5 -3" color="#4CC3D9"></a-box>
      <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
      <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>
  </body>
</html>

The scene automatically injects:

  • Default camera (position: 0 1.6 0)
  • Look controls (mouse drag)
  • WASD controls (keyboard movement)
3. Camera Systems

Default Camera (auto-injected if none specified):

<a-entity camera="active: true" look-controls wasd-controls position="0 1.6 0"></a-entity>

Custom Camera:

<a-camera position="0 2 5" look-controls wasd-controls="acceleration: 50"></a-camera>

Camera Rig (for independent movement and rotation):

<a-entity id="rig" position="0 0 0">
  
  <a-camera look-controls></a-camera>

  
</a-entity>

VR Camera Rig with Controllers:

<a-entity id="rig" position="0 0 0">
  
  <a-camera position="0 1.6 0"></a-camera>

  
  <a-entity
    hand-controls="hand: left"
    laser-controls="hand: left">
  </a-entity>

  
  <a-entity
    hand-controls="hand: right"
    laser-controls="hand: right">
  </a-entity>
</a-entity>
4. Lighting

Ambient Light (global illumination):

<a-entity light="type: ambient; color: #BBB; intensity: 0.5"></a-entity>

Directional Light (like sunlight):

<a-entity light="type: directional; color: #FFF; intensity: 0.8" position="1 2 1"></a-entity>

Point Light (radiates in all directions):

<a-entity light="type: point; color: #F00; intensity: 2; distance: 50" position="0 3 0"></a-entity>

Spot Light (cone-shaped beam):

<a-entity light="type: spot; angle: 45; intensity: 1.5" position="0 5 0" rotation="-90 0 0"></a-entity>
5. Materials and Textures

Standard Material:

<a-sphere
  material="color: #FF0000; metalness: 0.5; roughness: 0.3"
  position="0 1 -3">
</a-sphere>

Textured Material:

<a-assets>
  <img id="woodTexture" src="wood.jpg">
</a-assets>

<a-box material="src: #woodTexture" position="0 1 -3"></a-box>

Flat Shading (no lighting):

<a-plane material="shader: flat; color: #4CC3D9"></a-plane>
6. Animations

Property Animation:

<a-box
  position="0 1 -3"
  animation="property: rotation; to: 0 360 0; loop: true; dur: 5000">
</a-box>

Multiple Animations (use animation__* naming):

<a-sphere
  position="0 1 -3"
  animation__position="property: position; to: 0 3 -3; dir: alternate; loop: true; dur: 2000"
  animation__rotation="property: rotation; to: 360 360 0; loop: true; dur: 4000"
  animation__scale="property: scale; to: 1.5 1.5 1.5; dir: alternate; loop: true; dur: 1000">
</a-sphere>

Event-Based Animation:

<a-box
  color="blue"
  animation__mouseenter="property: scale; to: 1.2 1.2 1.2; startEvents: mouseenter"
  animation__mouseleave="property: scale; to: 1 1 1; startEvents: mouseleave"
  animation__click="property: rotation; from: 0 0 0; to: 0 360 0; startEvents: click">
</a-box>
7. Assets Management

Preload assets for better performance:

<a-scene>
  <a-assets>
    
    <img id="texture1" src="texture.jpg">
    <img id="skyTexture" src="sky.jpg">

    
    <video id="video360" src="360video.mp4" autoplay loop></video>

    
    <audio id="bgMusic" src="music.mp3" preload="auto"></audio>

    
    <a-asset-item id="tree" src="tree.gltf"></a-asset-item>

    
    <a-mixin id="redMaterial" material="color: red; metalness: 0.7"></a-mixin>
  </a-assets>

  
  <a-entity gltf-model="#tree" position="2 0 -5"></a-entity>
  <a-sphere mixin="redMaterial" position="0 1 -3"></a-sphere>
  <a-sky src="#skyTexture"></a-sky>
</a-scene>
8. Custom Components

Register custom components to encapsulate logic:

AFRAME.registerComponent('rotate-on-click', {
  // Component schema (configuration)
  schema: {
    speed: {type: 'number', default: 1}
  },

  // Lifecycle: called once when component attached
  init: function() {
    this.el.addEventListener('click', () => {
      this.rotating = !this.rotating;
    });
  },

  // Lifecycle: called every frame
  tick: function(time, timeDelta) {
    if (this.rotating) {
      var rotation = this.el.getAttribute('rotation');
      rotation.y += this.data.speed;
      this.el.setAttribute('rotation', rotation);
    }
  }
});
<a-box rotate-on-click="speed: 2" position="0 1 -3"></a-box>

Common Patterns

Pattern 1: VR Controller Interactions

Problem: Enable object grabbing and manipulation in VR

Solution: Use hand-controls and custom grab component

<a-scene>
  
  <a-entity id="rig">
    <a-camera position="0 1.6 0"></a-camera>

    <a-entity
      id="leftHand"
      hand-controls="hand: left"
      laser-controls="hand: left">
    </a-entity>

    <a-entity
      id="rightHand"
      hand-controls="hand: right"
      laser-controls="hand: right">
    </a-entity>
  </a-entity>

  
  <a-box class="grabbable" position="-1 1.5 -3" color="#4CC3D9"></a-box>
  <a-sphere class="grabbable" position="1 1.5 -3" color="#EF2D5E"></a-sphere>
</a-scene>

<script>
AFRAME.registerComponent('grabbable', {
  init: function() {
    var el = this.el;

    el.addEventListener('triggerdown', function(evt) {
      console.log('Grabbed by', evt.detail.hand);
      el.setAttribute('color', 'green');
    });

    el.addEventListener('triggerup', function(evt) {
      el.setAttribute('color', 'blue');
    });

    el.addEventListener('gripdown', function(evt) {
      // Attach object to controller
      var controllerEl = evt.detail.controller;
      controllerEl.object3D.attach(el.object3D);
    });

    el.addEventListener('gripup', function(evt) {
      // Detach from controller
      var sceneEl = el.sceneEl.object3D;
      sceneEl.attach(el.object3D);
    });
  }
});

// Apply grabbable component
document.querySelectorAll('.grabbable').forEach(el => {
  el.setAttribute('grabbable', '');
});
</script>
Pattern 2: 360° Image Gallery

Problem: Create an interactive 360° photo viewer

Solution: Use sky primitive and clickable thumbnails

<a-scene>
  <a-assets>
    <img id="city" src="city.jpg">
    <img id="forest" src="forest.jpg">
    <img id="beach" src="beach.jpg">
    <img id="city-thumb" src="city-thumb.jpg">
    <img id="forest-thumb" src="forest-thumb.jpg">
    <img id="beach-thumb" src="beach-thumb.jpg">
    <audio id="click-sound" src="click.mp3"></audio>
  </a-assets>

  
  <a-sky id="image-360" src="#city" rotation="0 -130 0"></a-sky>

  
  <a-entity id="menu" position="0 1.6 -2">
    <a-entity class="link"
      geometry="primitive: plane; width: 0.7; height: 0.7"
      material="shader: flat; src: #city-thumb"
      position="-1 0 0"
      sound="on: click; src: #click-sound"
      event-set__mouseenter="scale: 1.2 1.2 1"
      event-set__mouseleave="scale: 1 1 1"
      event-set__click="_target: #image-360; material.src: #city">
    </a-entity>

    <a-entity class="link"
      geometry="primitive: plane; width: 0.7; height: 0.7"
      material="shader: flat; src: #forest-thumb"
      position="0 0 0"
      sound="on: click; src: #click-sound"
      event-set__mouseenter="scale: 1.2 1.2 1"
      event-set__mouseleave="scale: 1 1 1"
      event-set__click="_target: #image-360; material.src: #forest">
    </a-entity>

    <a-entity class="link"
      geometry="primitive: plane; width: 0.7; height: 0.7"
      material="shader: flat; src: #beach-thumb"
      position="1 0 0"
      sound="on: click; src: #click-sound"
      event-set__mouseenter="scale: 1.2 1.2 1"
      event-set__mouseleave="scale: 1 1 1"
      event-set__click="_target: #image-360; material.src: #beach">
    </a-entity>
  </a-entity>

  
  <a-camera>
    <a-cursor raycaster="objects: .link"></a-cursor>
  </a-camera>
</a-scene>
Pattern 3: AR Hit Testing (Place Objects in Real World)

Problem: Place virtual objects on detected real-world surfaces

Solution: Use ar-hit-test component

<a-scene
  webxr="optionalFeatures: hit-test, dom-overlay; overlayElement: #overlay"
  ar-hit-test="target: #furniture; type: footprint">

  <a-assets>
    <a-asset-item id="chair" src="chair.gltf"></a-asset-item>
  </a-assets>

  
  <a-entity id="furniture" gltf-model="#chair" scale="0.5 0.5 0.5"></a-entity>

  
  <div id="overlay" style="position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%);
                           background: rgba(0,0,0,0.7); color: white; padding: 15px;
                           border-radius: 8px; font-family: sans-serif;">
    <p id="message">Tap to enter AR mode</p>
  </div>
</a-scene>

<script>
const sceneEl = document.querySelector('a-scene');
const message = document.getElementById('message');

sceneEl.addEventListener('enter-vr', function() {
  if (this.is('ar-mode')) {
    message.textContent = '';

    this.addEventListener('ar-hit-test-start', function() {
      message.innerHTML = 'Scanning environment, finding surface.';
    }, { once: true });

    this.addEventListener('ar-hit-test-achieved', function() {
      message.innerHTML = 'Tap on the screen to place the object.';
    }, { once: true });

    this.addEventListener('ar-hit-test-select', function() {
      message.textContent = 'Object placed!';
      setTimeout(() => message.textContent = '', 2000);
    }, { once: true });
  }
});

sceneEl.addEventListener('exit-vr', function() {
  message.textContent = 'Tap to enter AR mode';
});
</script>
Pattern 4: Mouse/Gaze Interactions

Problem: Enable click interactions with desktop mouse or VR gaze

Solution: Use cursor component and raycaster

<a-scene>
  
  <a-box
    class="interactive"
    position="-1 1.5 -3"
    color="#4CC3D9"
    event-set__mouseenter="color: yellow"
    event-set__mouseleave="color: #4CC3D9"
    event-set__click="scale: 1.5 1.5 1.5">
  </a-box>

  <a-sphere
    class="interactive"
    position="1 1.5 -3"
    color="#EF2D5E"
    event-set__click="color: orange; scale: 2 2 2">
  </a-sphere>

  <a-plane position="0 0 -4" rotation="-90 0 0" width="10" height="10" color="#7BC8A4"></a-plane>

  
  <a-camera position="0 1.6 0">
    
    <a-cursor
      raycaster="objects: .interactive"
      fuse="true"
      fuse-timeout="1500">
    </a-cursor>
  </a-camera>
</a-scene>

<script>
// Advanced click handling with JavaScript
document.querySelectorAll('.interactive').forEach(el => {
  el.addEventListener('click', function(evt) {
    console.log('Clicked:', this.id || this.tagName);
    console.log('Intersection point:', evt.detail.intersection.point);
  });
});
</script>
Pattern 5: Dynamic Scene Generation

Problem: Programmatically create and manipulate entities

Solution: Use JavaScript DOM manipulation

<a-scene>
  <a-camera position="0 1.6 5"></a-camera>
  <a-entity light="type: ambient; color: #888"></a-entity>
  <a-entity light="type: directional; color: #FFF" position="1 2 1"></a-entity>
</a-scene>

<script>
const scene = document.querySelector('a-scene');

// Create sphere
function createSphere(x, y, z, color) {
  const entity = document.createElement('a-entity');

  entity.setAttribute('geometry', {
    primitive: 'sphere',
    radius: 0.5
  });

  entity.setAttribute('material', {
    color: color,
    metalness: 0.5,
    roughness: 0.3
  });

  entity.setAttribute('position', {x, y, z});

  // Add animation
  entity.setAttribute('animation', {
    property: 'position',
    to: `${x} ${y + 1} ${z}`,
    dir: 'alternate',
    loop: true,
    dur: 2000
  });

  scene.appendChild(entity);
  return entity;
}

// Generate grid of spheres
for (let x = -3; x <= 3; x += 1.5) {
  for (let z = -5; z <= -2; z += 1.5) {
    const color = `#${Math.floor(Math.random()*16777215).toString(16)}`;
    createSphere(x, 1, z, color);
  }
}

// Listen to component changes
scene.addEventListener('componentchanged', function(evt) {
  console.log('Component changed:', evt.detail.name);
});

// Access Three.js objects directly
setTimeout(() => {
  const entities = document.querySelectorAll('a-entity[geometry]');
  entities.forEach(el => {
    el.object3D.visible = true; // Direct Three.js manipulation
  });
}, 1000);
</script>
Pattern 6: Environment and Skybox

Problem: Create immersive environments quickly

Solution: Use community components and 360 images

<html>
  <head>
    <script src="https://aframe.io/releases/1.7.1/aframe.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@fern-solutions/aframe-sky-background/dist/sky-background.umd.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/c-frame/[email protected]/dist/aframe-extras.min.js"></script>
  </head>
  <body>
    <a-scene>
      
      <a-sky-background
        top-color="#4A90E2"
        bottom-color="#87CEEB">
      </a-sky-background>

      
      

      
      <a-entity
        ocean="density: 20; width: 50; depth: 50; speed: 4"
        material="color: #9CE3F9; opacity: 0.75; metalness: 0; roughness: 1"
        rotation="-90 0 0">
      </a-entity>

      
      <a-entity
        particle-system="preset: snow; particleCount: 2000; color: #FFF">
      </a-entity>

      <a-entity light="type: ambient; color: #888"></a-entity>
      <a-entity light="type: directional; color: #FFF; intensity: 0.7" position="1 2 1"></a-entity>
    </a-scene>
  </body>
</html>
Pattern 7: GLTF Model Loading

Problem: Load and display 3D models

Solution: Use gltf-model component with asset management

<a-scene>
  <a-assets>
    <a-asset-item id="robot" src="robot.gltf"></a-asset-item>
    <a-asset-item id="building" src="building.glb"></a-asset-item>
  </a-assets>

  
  <a-entity
    gltf-model="#robot"
    position="0 0 -3"
    scale="0.5 0.5 0.5"
    animation="property: rotation; to: 0 360 0; loop: true; dur: 10000">
  </a-entity>

  
  <a-entity
    gltf-model="#building"
    position="5 0 -10"
    animation-mixer="clip: *; loop: repeat">
  </a-entity>

  <a-camera position="0 1.6 5"></a-camera>
  <a-entity light="type: ambient; intensity: 0.5"></a-entity>
  <a-entity light="type: directional; intensity: 0.8" position="2 4 2"></a-entity>
</a-scene>

<script>
// Handle model loading events
document.querySelector('[gltf-model="#robot"]').addEventListener('model-loaded', (evt) => {
  console.log('Model loaded:', evt.detail.model);

  // Access Three.js object
  const model = evt.detail.model;
  model.traverse(node => {
    if (node.isMesh) {
      console.log('Mesh found:', node.name);
    }
  });
});

document.querySelector('[gltf-model="#robot"]').addEventListener('model-error', (evt) => {
  console.error('Model loading error:', evt.detail);
});
</script>

Integration Patterns

With Three.js

Access underlying Three.js objects:

// Get Three.js scene
const scene = document.querySelector('a-scene').object3D;

// Get entity's Three.js object
const box = document.querySelector('a-box');
const threeObject = box.object3D;

// Direct Three.js manipulation
threeObject.position.set(1, 2, 3);
threeObject.rotation.y = Math.PI / 4;

// Add custom Three.js objects
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
With GSAP (Animation)

Animate A-Frame entities with GSAP:

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script>
const box = document.querySelector('a-box');

// Animate position
gsap.to(box.object3D.position, {
  x: 3,
  y: 2,
  z: -5,
  duration: 2,
  ease: 'power2.inOut'
});

// Animate rotation
gsap.to(box.object3D.rotation, {
  y: Math.PI * 2,
  duration: 3,
  repeat: -1,
  ease: 'none'
});

// Animate attributes
gsap.to(box.components.material.material, {
  opacity: 0.5,
  duration: 1
});
</script>
With React

Integrate A-Frame in React components:

import React, { useEffect, useRef } from 'react';
import 'aframe';

function VRScene() {
  const sceneRef = useRef(null);

  useEffect(() => {
    const scene = sceneRef.current;

    // Create entities dynamically
    const entity = document.createElement('a-sphere');
    entity.setAttribute('position', '0 1.5 -3');
    entity.setAttribute('color', '#EF2D5E');
    scene.appendChild(entity);

    // Listen to events
    scene.addEventListener('enter-vr', () => {
      console.log('Entered VR mode');
    });
  }, []);

  return (
    <a-scene ref={sceneRef}>
      <a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" />
      <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E" />
      <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D" />
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" />
      <a-sky color="#ECECEC" />
    </a-scene>
  );
}

export default VRScene;

Performance Best Practices

1. Use Asset Management

Preload assets to avoid blocking:

<a-assets>
  <img id="texture1" src="large-texture.jpg">
  <video id="video360" src="360video.mp4" preload="auto"></video>
  <a-asset-item id="model" src="complex-model.gltf"></a-asset-item>
</a-assets>
2. Pool Entities

Reuse entities instead of creating/destroying:

AFRAME.registerComponent('bullet-pool', {
  init: function() {
    this.pool = [];
    this.used = [];

    // Pre-create bullets
    for (let i = 0; i < 20; i++) {
      const bullet = document.createElement('a-sphere');
      bullet.setAttribute('radius', 0.1);
      bullet.setAttribute('visible', false);
      this.el.sceneEl.appendChild(bullet);
      this.pool.push(bullet);
    }
  },

  getBullet: function() {
    if (this.pool.length > 0) {
      const bullet = this.pool.pop();
      bullet.setAttribute('visible', true);
      this.used.push(bullet);
      return bullet;
    }
  },

  returnBullet: function(bullet) {
    bullet.setAttribute('visible', false);
    const index = this.used.indexOf(bullet);
    if (index > -1) {
      this.used.splice(index, 1);
      this.pool.push(bullet);
    }
  }
});
3. Optimize Geometry

Use low-poly models and LOD:


<a-sphere radius="1" segments-width="8" segments-height="6"></a-sphere>


<a-sphere radius="1" segments-width="32" segments-height="32"></a-sphere>
4. Limit Draw Calls

Use instancing for repeated objects:

AFRAME.registerComponent('instanced-trees', {
  init: function() {
    // Use Three.js InstancedMesh for repeated geometry
    const scene = this.el.sceneEl.object3D;
    const geometry = new THREE.ConeGeometry(0.5, 2, 8);
    const material = new THREE.MeshStandardMaterial({ color: 0x228B22 });
    const mesh = new THREE.InstancedMesh(geometry, material, 100);

    // Position instances
    for (let i = 0; i < 100; i++) {
      const matrix = new THREE.Matrix4();
      matrix.setPosition(
        Math.random() * 20 - 10,
        0,
        Math.random() * 20 - 10
      );
      mesh.setMatrixAt(i, matrix);
    }

    scene.add(mesh);
  }
});
5. Throttle tick() Functions

Don't update every frame if unnecessary:

AFRAME.registerComponent('throttled-update', {
  init: function() {
    this.lastUpdate = 0;
    this.updateInterval = 100; // ms
  },

  tick: function(time, timeDelta) {
    if (time - this.lastUpdate >= this.updateInterval) {
      // Expensive operation here
      this.lastUpdate = time;
    }
  }
});
6. Use Stats Component for Monitoring
<a-scene stats>
  
</a-scene>

Common Pitfalls and Solutions

Pitfall 1: Entities Not Appearing

Problem: Entity added but not visible

Causes:

  • Entity positioned behind camera
  • Scale is 0 or very small
  • Material opacity is 0
  • Entity outside camera frustum

Solution:

// Wait for scene to load
const scene = document.querySelector('a-scene');
scene.addEventListener('loaded', () => {
  const entity = document.createElement('a-box');
  entity.setAttribute('position', '0 1.5 -3'); // In front of camera
  entity.setAttribute('color', 'red');
  scene.appendChild(entity);
});

// Debug: Check entity position
console.log(entity.getAttribute('position'));

// Debug: Check if entity is in scene
console.log(entity.parentNode); // Should be <a-scene>
Pitfall 2: Events Not Firing

Problem: Click/mouseenter events don't trigger

Cause: Missing raycaster or cursor

Solution:


<a-camera>
  <a-cursor raycaster="objects: .interactive"></a-cursor>
</a-camera>


<a-box class="interactive" position="0 1 -3"></a-box>


<a-entity raycaster="objects: [geometry]" cursor></a-entity>
Pitfall 3: Performance Degradation

Problem: Low FPS with many entities

Causes:

  • Too many draw calls
  • Complex geometries
  • Unoptimized textures
  • Too many tick() updates

Solutions:

// 1. Use object pooling (see Performance section)
// 2. Simplify geometry
// 3. Optimize textures (reduce size, use compression)
// 4. Throttle updates

AFRAME.registerComponent('optimize-far-entities', {
  tick: function() {
    const camera = this.el.sceneEl.camera;
    const entities = document.querySelectorAll('[geometry]');

    entities.forEach(el => {
      const distance = el.object3D.position.distanceTo(camera.position);

      // Hide distant entities
      el.object3D.visible = distance < 50;
    });
  }
});
Pitfall 4: Z-Fighting (Overlapping Surfaces)

Problem: Flickering when surfaces overlap

Cause: Two surfaces at same position

Solution:


<a-plane position="0 0.01 0" rotation="-90 0 0"></a-plane>
<a-plane position="0 0.02 0" rotation="-90 0 0"></a-plane>


<a-entity
  geometry="primitive: plane"
  material="src: #texture1; transparent: true"
  class="has-render-order">
</a-entity>

<script>
document.querySelector('.has-render-order').object3D.renderOrder = 1;
</script>
Pitfall 5: Mobile VR Performance

Problem: Low performance on mobile VR

Solutions:


<a-scene renderer="maxCanvasWidth: 1920; maxCanvasHeight: 1920">


<a-sphere radius="1" segments-width="8" segments-height="6"></a-sphere>


<a-entity light="type: ambient; intensity: 0.6"></a-entity>
<a-entity light="type: directional; intensity: 0.4" position="1 2 1"></a-entity>


<a-scene renderer="antialias: false">
</a-scene>
Pitfall 6: Asset Loading Issues

Problem: Assets not loading or CORS errors

Solutions:


<a-assets>
  <img id="texture" src="https://example.com/texture.jpg" crossorigin="anonymous">
</a-assets>


<script>
const assets = document.querySelector('a-assets');
assets.addEventListener('loaded', () => {
  console.log('All assets loaded');
  // Safe to use assets now
});

assets.addEventListener('timeout', () => {
  console.error('Asset loading timeout');
});
</script>


<script>
const img = document.querySelector('img#texture');
img.addEventListener('error', () => {
  console.error('Failed to load texture');
  // Use fallback
  img.src = 'fallback-texture.jpg';
});
</script>

Resources

Related Skills

  • threejs-webgl: For advanced Three.js control beyond A-Frame's declarative API
  • babylonjs-engine: Alternative 3D engine with different architecture
  • gsap-scrolltrigger: For animating A-Frame entities with GSAP
  • react-three-fiber: React approach to Three.js (compare with A-Frame's HTML approach)

Archivos 11 archivos

Instálala a mano

Deska ejecuta esto por ti, para cada agente que elijas. Para ejecutarlo tú en una terminal:

npx skills add freshtechbro/claudedesignskills --skill aframe-webxr

Más de freshtechbro

  • motion-framerfreshtechbroModern animation library for React and JavaScript. Create smooth, production-ready animations with motion components, variants, gestures (hover/tap/drag), layout animations, AnimatePresence exit animations, spring physics, and scroll-based effects. Use when building interactive UI components, micro-interactions, page transitions, or complex animation sequences.5,100 instalaciones en skills.sh0
  • threejs-webglfreshtechbroComprehensive skill for Three.js 3D web development. Use this skill when building interactive 3D scenes, WebGL/WebGPU applications, product configurators, 3D visualizations, or immersive web experiences. Triggers on tasks involving Three.js, 3D rendering, scenes, cameras, meshes, materials, lights, animations, textures, or WebGL/WebGPU rendering.4,100 instalaciones en skills.sh0
  • react-three-fiberfreshtechbroBuild declarative 3D scenes with React Three Fiber (R3F) - a React renderer for Three.js. Use when building interactive 3D experiences in React applications with component-based architecture, state management, and reusable abstractions. Ideal for product configurators, portfolios, games, data visualization, and immersive web experiences.3,200 instalaciones en skills.sh0
  • blender-web-pipelinefreshtechbroBlender to web export workflows for 3D models and animations. Use this skill when exporting Blender models to glTF for web, optimizing 3D assets for Three.js or Babylon.js, batch processing models with Python scripts, automating Blender workflows, or creating web-ready 3D pipelines. Triggers on tasks involving Blender glTF export, bpy scripting, 3D asset optimization, model compression, texture baking, or Blender automation. Exports models for threejs-webgl, react-three-fiber, and babylonjs-engine skills.3,000 instalaciones en skills.sh0
  • web3d-integration-patternsfreshtechbroMeta-skill for combining Three.js, GSAP ScrollTrigger, React Three Fiber, Motion, and React Spring for complex 3D web experiences. Use when building applications that integrate multiple 3D and animation libraries, requiring architecture patterns, state management, and performance optimization across the stack. Triggers on tasks involving library integration, multi-library architectures, scroll-driven 3D experiences, physics-based 3D animations, or complex interactive 3D applications.2,800 instalaciones en skills.sh0
Todas las skills de freshtechbro