Skip to content

Instantly share code, notes, and snippets.

@coderofsalvation
Last active June 4, 2024 10:11
Show Gist options
  • Select an option

  • Save coderofsalvation/edf5bfb946a37b9ecc8cc55fa654b339 to your computer and use it in GitHub Desktop.

Select an option

Save coderofsalvation/edf5bfb946a37b9ecc8cc55fa654b339 to your computer and use it in GitHub Desktop.
My favorite 3D / XR javascript patterns

Useful 3D Patterns/Functions

Besides all the classical designpatterns in js, (re)using a simple underscore object (lodash-style) with useful patterns can be really productive.

square wave

square = (x,freq) => ( x & freq )

Smoothing values

Sometimes sensors are too noisy (accelerometer/gyroscope), therefore smoothing comes in handy:

function smooth(coef){
  this.x = 0
  return (x) => (this.x = this.x * coef + x * (1.0-coef))
}

var s = new smooth(0.9)
s(0.1) // 0.009 
s(0.8) // 0.088
s(0.8) // 0.160

Snap to 3d grid

handy to spawn 3d objects randomly into space, but aligned to a grid and without overlapping other objects.

// usage: snapToGrid({position:[0,0,0],1,1,1,['x','y'],{}) 
let snapToGrid = (obj, snapX, snapY, snapZ, axes, cache ) => {                                                                                                   const pos = AFRAME.utils.clone(obj.position)                                                                                              
      pos.x = Math.floor(pos.x / snapX) * snapX //+ data.offset.x;                                                                               
      pos.y = Math.floor(pos.y / snapY) * snapY //+ data.offset.y;                                                                               
      pos.z = Math.floor(pos.z / snapZ) * snapZ //+ data.offset.z;                                                                               
      var hash = String(pos.x+pos.y+pos.z)                                                                                                       
      obj.position.set( pos.x,  pos.y,  pos.z )                                                                                                  
      if( cache[ hash ] ){ // recurse if coordinates already taken (in cache)                                                                                                         
          let items = []
          if( axes.includes('x') items.push({f:'translateX', snap:snapX})
          if( axes.includes('y') items.push({f:'translateY', snap:snapY})
          if( axes.includes('z') items.push({f:'translateZ', snap:snapZ})                                                                                                                             
          let t = items[Math.floor(Math.random() * items.length)];                                                                               
          obj[ t.f ]( t.snap )                                                                                                                   
          this.snapToGrid(obj, snapX, snapY, snapZ )                                                                                             
      }                                                                                                                                          
      hash = String(pos.x+pos.y+pos.z) // final coords                                                                                           
      cache[hash] = true                                                                                                                
}                                                                                                                                              

console HTML overlay #threejs

const consoleOverlay = () => {
  // add onscreen console
  let divConsole = document.createElement('pre')
  divConsole.style.position = 'fixed'
  divConsole.style.overflow = 'auto'
  divConsole.style.top = divConsole.style.left = divConsole.style.bottom = divConsole.style.right = '0px'
  divConsole.style.height = '98.5vh';
  divConsole.style.width = '100%'
  divConsole.id = 'console'
  document.body.appendChild(divConsole)
  const wrapper = (scope, fn, name) => {
    return function(msg) {
      divConsole.innerHTML += `[${name}] ${msg}<br>`;
      if( name == 'err'){
        let err = new Error()
        String(err.stack).split("\n").slice(2).map( (l) => divConsole.innerHTML += ` └☑ ${l}\n` )
      }
      divConsole.scrollTop = divConsole.scrollHeight;
      fn.call(scope,msg);
    };
  }
  window.console.log   = wrapper(console, console.log, "log");
  window.console.warn  = wrapper(console, console.warn, "wrn");
  window.console.error = wrapper(console, console.error, "err");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment