New patterns for Lux Lavalier

Here are a few new things I’ve done for the Lux Lavalier. (If you haven’t seen it, click the link and check out this fun, beautiful wearable art piece.)

Blue Holiday Candle 2D
// Candle flame using distorted circles
// Yet another way to make fire! 
//
// MIT License
// 1/25/2023 ZRanger1


var numTwinklers = 3
var twinkleSpeed = 0.01
export var tIndex = array(numTwinklers);
export var tPos = 0;
export var twinklers = array(numTwinklers);
var twinkleState = array(numTwinklers);
var twinkleIncrement = array(numTwinklers);
var timebase;

// move coordinate origin to 0 and flip y axis so we can
// put the candle at the bottom (comment out the scale() statement if
// you don't need it for your display.
translate(-0.5,-0.5);
//scale(1,-1);  // not needed for lux

function sortIndex(v1, v2) {
  return (twinklers[v1] < twinklers[v2]) ? -1 : 0;
}

export function beforeRender(delta) {
  timebase = (timebase + delta/1000) % 3600;
  
  // generate 3 octave sine wave pattern for flame movement
  t1 = -0.875+(wave(time(0.06)) + wave(time(0.03))/2 + wave(time(0.015))/4); 
  
  // timer for blue flame's internal flicker
  t2 = timebase * 2;
  
  // twinkling white stars in background
  for (i = 0; i < numTwinklers;i++) {
     if (twinkleState[i] <= 0) {
       twinklers[i] = floor(random(pixelCount));
       twinkleIncrement[i] = 0.0075+twinkleSpeed * random(1);
       twinkleState[i] = 1;

     }
     else {
       twinkleState[i] -= twinkleIncrement[i];
     }
     tIndex[i] = i;                
  }
  
  arraySortBy(tIndex, sortIndex);
  ak = tPos
  tPos = 0;
}

export function render2D(index,x,y) {

  // calculate position and width of candle at base of flame
  f = max(0,(-(abs(x) - 0.425)) * (y < -0.4));  

  // adjust aspect ratio to make flame taller and less round
  x *= 1.75;
  
  // calculate x displacement value for this y coord
  x += (-0.5+wave(6*y * t1)) * (y+0.5) * 0.175;
  
  // inner (blue) circle
  d = (hypot(x,y)-0.1)+(y/3);
  s = 1-clamp(d/0.15,0,1);
  s += s * (-0.5+0.5*triangle(t2+x*5+y*11))

  // outer (orange) circle
  d = abs(hypot(x,y)-0.33);
  h = 1-smoothstep(0,0.15,d);

  // build the flame + candle color
  // edge is red with a tiny amount of green added to make yellow at bottom
  // center and candle are blue
  r = s * 0.2 + h * 0.9;
  g = s * 0.3 + (h * 0.4*(1-2*y));
  b = s + f
  
  // if this pixel is part of the flame, use the calculated flame color
  if ((r+g+b) > 0.05) {
    rgb(r,g,b);
  } 
  else {
    // if it's a twinkling "star" in the on state, light it up!
    if (tPos < numTwinklers && index == twinklers[tIndex[tPos]]) {
      hsv(0.025,0.15,0.75*wave(-.25+twinkleState[tIndex[tPos]]))
      tPos++;
      return;
    }  
    // otherwise, use the background color - dark purple
    hsv(0.75,1,0.02)
  }
}
Perlin Kaleidoscope
/*
 Perlin Kaleidoscope 2D
 
 Uses Pixelblaze's noise functions to generate an "interesting" base
 texture of RGB lines, then generates kaleidoscopic reflections.
 
 Try with Reflections slider set to minimum to see the noise lines!
 
 MIT License
 
 Take this code and use it to make cool things!
 
 12/29/2022 ZRanger1
*/

export var lineWidth = 0.075;
export var speed = 0.5;
export var nSides = 3;
var slice = PI/nSides;  
var outx,outy;

// movement speed
export function sliderSpeed(v) {
  speed = 0.25 + 2 * v * v;
}

// width of base texture lines
export function sliderLineWidth(v) {
  lineWidth = 0.02 + (v * 0.3);
}

// number of kaleidoscope "slices"
export function sliderReflections(v) {
  nSides = 1+floor(6*v);
  slice = PI2 / nSides;
}

// sets up a kaleidoscope effect - makes the image repeat over evenly divided
// rotated "slices" about the center.
function kal(x,y,r,theta) {
  // convert to radial coords, repeat image over each
  // angular "slice" and rotate the slices over time
  var angle = abs(theta + mod(atan2(y,x), slice)-slice);

  // map new rotated coordinates back to original image space
  outx = r * cos(angle);  outy = r * sin(angle);
}

var timebase = 0;
var t1,theta;
export function beforeRender(delta) {
  timebase = (timebase + delta / 1000)  % 3600;
  t1 = timebase * speed;
  theta = PI * t1;
}

translate (-0.5,-0.5)
export function render2D(index, x, y) {
  r = hypot(x,y);  
  if (nSides > 1) { 
    kal(x,y,r,theta); x = outx; y = outy;
  }  
  
  lr = perlinFbm(x,y,t1,1.15,0.15,3);
  lg = perlinFbm(y,x,t1,0.5,0.1,3);
  lb = perlinFbm(t1,x,y,0.25,0.15,3);
  
  r = 2-abs(y - lr) / lineWidth;
  g = 2-abs(y - lg) / lineWidth;
  b = 2-abs(y - lb) / lineWidth;

  rgb(r, g, b);
}
LAVAlier
/*
 Lava/Surface of the Sun pattern for Lux Lavalier (but also works
 fine on other 2D Pixelblaze displays!)
 
 Uses multiple layers of perlin fbm to create a swirling lava 
 effect.  
 
 MIT License
 
 Take this code and make cool things!
 
 12/15/2022 ZRanger1
*/

export var lineWidth = 1;
export var fill = 0;
export var speed = 0.04;
export var frequency = 1;


// controls wave movement speed
export function sliderSpeed(v) {
  speed = 0.01 + v*v;
}

// returns fbm noise value scaled to the range we need
function fbm(x,y) {
  return 0.5+0.5*perlinFbm(x,y,PI,1.5,0.5,2);
}

// create two noise fields, and use a third to mix them together.
// (this is "normal" in shader land, but probably overkill here)
function pattern(px,py) {
  qx = fbm(px + t1 * .2,py + t1 * .2 + 0.4);
  qy = fbm(px + t1 * .3 + 2.4, py + t1 * 0.3 + 4.8);
  
  rx = fbm(qx - t1 * .3 + 4. * qx + 3,qy - t1 * .3 + 4. * qy + 9);
  ry = fbm(qx + t1 * .2 + 8. * qx + 2.4,qy + t1 * .3 + 4. * qy + 9);
  return fbm(px + rx * 2. - t1 * .09,py + ry * 2. - t1 * .09);
}

function quantize(c, low, hi) {
  c = c - low;
  return c*c*c/(hi-low); 
}

var timebase = 0;
var t1;
export function beforeRender(delta) {
  timebase = (timebase + delta / 1000)  % 3600;
  t1 = timebase * speed;
}

translate (-0.5,-0.5)
export function render2D(index, x, y) {
  var f = pattern(x,y);
  
  r = quantize(f,0,0.35);
  g = quantize(f,0.3,0.55);
  b = quantize(f,0.5,0.8);

  rgb(r,g,b)
}

Of course, they also work on any Pixelblaze with a 2D display. I’ve uploaded the first two to the pattern library, and source code is also available from my github repo.

8 Likes

I LOVE these and cannot wait to wear them!

3 Likes