Scene script for "Lava lamp"

The following scenescript is suitable for SmartLED lights such as the p44torch (in both the do-it-yourself and ready-bought versions). It uses the LEDs, which should be arranged in an area (in the p44torch in approx. 22 rows with 11 LEDs each), to display a lava lamp like animation.

How to enter a scene script?

Detailed instructions on how to create a scene script on a P44-DSB or P44-LC device can be found here.

Requires firmware 2.7.0 / 2.7.0.34 or newer

This example requires version 2.7.0.34 or newer, which is available as a public beta at the time of writing. Only this version allows scrolling with subpixel resolution, which creates the illusion of continuous movement and not pixel-by-pixel "hopping".

Create additional "lamp"

As a basis, the scene script needs a surface on which the animation can be displayed. Setting this up works in exactly the same way as with the "torch" animation, i.e. as described in detail here, with the exception that the last field "Feature config" must not contain "torch" but "stack". A "stack" is an initially empty view on which the moving bubble (blob) views are then placed and animated with the scene script.

Enter scene script

The following script can be copied 1:1 and entered in the "Script to execute..." field in the Sceneedit dialogue but can of course also be customised as required.

// "Lava-Lamp"

// remove all existing subviews (blobs from previous runs)
view.clear()
view.configure({
  framing: 'repeatX|clipY',
  bgcolor: '#001608', // yellow orange
})

// get the frame of the area to display the "lava" animation
var area = ledchaincover()

// the sea view is a slightly "waving" bottom
var sea = {
  type: 'lightspot',
  label: 'sea',
  extent_x: 5,
  extent_y: 5,
  color: '#480',
  bgcolor: '0000',
  alpha:255,
  z_order: 1000,
  // finetuning
  brightness_gradient: -1,
  hue_gradient: 0.34,
  saturation_gradient: 0,
  brightness_mode: 'linear|oscillating|unlimited',
  hue_mode: 'linear|oscillating|unlimited',
  saturation_mode: 'linear|oscillating|unlimited',
  radial: false,
  orientation: 'up',
}
sea += area
sea.dy = 5
var s = makeview(sea)
s.set('fullframe', true)
view.addview(s)
// make it "rocking" a bit with a continuously running back-and-forth animation of the rotation parameter
s.animator('rotation').repeat(-1,true).step(0.05,1).from(-15).runto(15,20)

var blobcount = 0
var currentblobs = 0

while (true) {

  var blob = {
    type: 'lightspot',
    extent_x: 5,
    extent_y: 5,
    color: hsv(random(15, 90, 1)), // orange to yellow
    bgcolor: '0000', // transparent background (important)
    alpha:200,
    z_order: 900,
    // finetuning
    brightness_gradient: -1,
    hue_gradient: 0,
    saturation_gradient: 0,
    brightness_mode: 'linear|oscillating|unlimited',
    hue_mode: 'linear|oscillating|unlimited',
    saturation_mode: 'linear|oscillating|unlimited',
    radial: true,
  }
  blob += area
  blobcount++
  blob.label = format("blob_%d", blobcount)

  var v = makeview(blob)
  v.fullframe()
  v.content_x = 5
  v.content_y = 5
  v.framing = 'repeatX|clipY' // wrap around tube in X-direection

  v.x = random(0, area.dx, 1) // random position somewhere around the tube
  view.addview(v)

  // further "life" of the blob view (moving up, sinking down again) now happens in a concurrent thread
  concurrent passing v {
    currentblobs++
    // move up
    threadvar a = v.animator('scroll_y').function('easeinout').from(10).runto(-area.dy+6,random(15,22))
    await(a)
    // sink down again
    a = v.animator('scroll_y').function('easeinout').runto(10,random(18,30))
    await(a)
    // that's it for this blob, remove it
    v.remove()
    currentblobs--
    log('%s removed, now=%d',v.label, currentblobs)
  }

  // wait a bit before creating another blob
  delay(random(4,15))
  while (currentblobs>=3) {
    // wait longer when we already have 3 or more blobs
    delay(20)
  }
}

More info