Perlin Fire - feel free to help make it better

Really short FastLED Perlin Fire by @Johnny5canuck

Similarly short by ldirko
https://www.reddit.com/r/FastLED/comments/hgu16i/my_fire_effect_implementation_based_on_perlin/

Code is linked in each…

Both use a fire palette and inoise. We have neither, so this is quite a bit longer. Lots of tunable sliders, and it’s not done by any means. Suggestions and improvements welcome. There are lots of ways to build a fire…

It’s bit too orange-y I think, but it has a really nice roar, like a big bonfire or a fireplace, as opposed to a steady burn. Adjust by adding wood, or maybe sliding the sliders, till it’s at a comfy level for you.

Perlin Fire - an early attempt on PB
// Perlin Fire - an early attempt on PB

export var reset = 1
export function sliderNewGrid(v){
  var rereset = reset
  reset = v
  if (reset == 0 && rereset != reset){
    buildTable()
  }
}

export var noisescaleX = 1
export function sliderScaleX(v){
  noisescaleX = v*10
}

export var noisescaleY = 1
export function sliderScaleY(v){
  noisescaleY = v*10
}

export var noisescaleZ = 1
export function sliderScaleZTime(v){
  noisescaleZ = v*10
}

export var fireheight = 1
export function sliderFireHeight(v){
  fireheight = 10 - v*10
}

function lerp(a, b, t) {
		return (1 - t) * a + t * b;
}

export var time
export function beforeRender(delta) {
  time += delta/5000 * noisescaleZ
}

export function render2D(index, x, y) {
  h = lerp(-.05,.25,abs(noise(x*noisescaleX, y*noisescaleY, time)))
  s = 1
  if (h < 0) {
    h = abs(h)
    s = 1-h
  }
  v = 1-(x+h*fireheight)
  hsv(h,s,v)
}

//
// Written by Thom Chiovoloni, dedicated into the public domain 
// per http://creativecommons.org/publicdomain/zero/1.0
// https://github.com/thomcc/quick-noise.js
//
// adapted by ScruffyNerf into Pixelblaze's JSish language
// you could replace the use of random() with a different RNG if you wish

var arraySize = 256
var permSize = arraySize
var gradSize = permSize
var perm = array(permSize)
var grad1 = array(gradSize)
var grad2 = array(gradSize)
var grad3 = array(gradSize)
var gradBasis = array(36)
var gradIndex = 0
var gradIdx = 0



function gradinit(){
		grad(1,1,0); grad(-1,1,0); grad(1,-1,0); grad(-1,-1,0)
    grad(1,0,1); grad(-1,0,1); grad(1,0,-1); grad(-1,0,-1)
    grad(0,1,1); grad(0,-1,1); grad(0,1,-1); grad(0,-1,-1)
}

function buildTable() {
		perm.mutate(arrayFill)
		perm.mutate(arrayShuffle)
		perm.mutate(arrayShuffle) // for good measure, shuffle twice
		gradIdx = 0
    perm.forEach(gradPop)
}

function arrayFill(v,i,a){
  return i	  
}

function arrayShuffle(v,i,a){
  r = floor(random(a.length))
  t = a[r]
  a[r] = v
  return t
}

function grad(x, y, z) {
  gradBasis[gradIndex] = x
  gradIndex++
  gradBasis[gradIndex] = y
  gradIndex++
  gradBasis[gradIndex] = z
  gradIndex++
}

function gradPop(v,i,a){
  g = v%12 * 3
  grad1[gradIdx] = gradBasis[g]
  grad2[gradIdx] = gradBasis[g+1]
  grad3[gradIdx] = gradBasis[g+2]
  gradIdx++
}

function fade(t) {
  return t * t * t * (t * (t * 6 - 15) + 10)
}


function noise(x, y, z, xWrap, yWrap, zWrap) {
	// x, y, z are numbers.
	// xWrap, yWrap, and zWrap are integer powers of two between 0 and 256.
	// (0 and 256 are equivalent). If these aren't provided, they default to 0.
	
  xMask = ((xWrap-1) & 255) >> 0
	yMask = ((yWrap-1) & 255) >> 0
	zMask = ((zWrap-1) & 255) >> 0

	px = floor(x)
  py = floor(y)
	pz = floor(z)

	x0 = (px+0) & xMask
	x1 = (px+1) & xMask

	y0 = (py+0) & yMask
	y1 = (py+1) & yMask

	z0 = (pz+0) & zMask
	z1 = (pz+1) & zMask

	x -= px
	y -= py
	z -= pz

	u = fade(x)
	v = fade(y)
	w = fade(z)

	r0 = perm[x0%256]
	r1 = perm[x1%256]

	r00 = perm[(r0+y0)%256]
	r01 = perm[(r0+y1)%256]
	r10 = perm[(r1+y0)%256]
	r11 = perm[(r1+y1)%256]

	h000 = perm[(r00+z0)%256]%256
	h001 = perm[(r00+z1)%256]%256
	h010 = perm[(r01+z0)%256]%256
	h011 = perm[(r01+z1)%256]%256
	h100 = perm[(r10+z0)%256]%256
	h101 = perm[(r10+z1)%256]%256
	h110 = perm[(r11+z0)%256]%256
	h111 = perm[(r11+z1)%256]%256

	n000 = grad1[h000]*(x+0) + grad2[h000]*(y+0) + grad3[h000]*(z+0)
	n001 = grad1[h001]*(x+0) + grad2[h001]*(y+0) + grad3[h001]*(z-1)
	n010 = grad1[h010]*(x+0) + grad2[h010]*(y-1) + grad3[h010]*(z+0)
	n011 = grad1[h011]*(x+0) + grad2[h011]*(y-1) + grad3[h011]*(z-1)
	n100 = grad1[h100]*(x-1) + grad2[h100]*(y+0) + grad3[h100]*(z+0)
	n101 = grad1[h101]*(x-1) + grad2[h101]*(y+0) + grad3[h101]*(z-1)
	n110 = grad1[h110]*(x-1) + grad2[h110]*(y-1) + grad3[h110]*(z+0)
	n111 = grad1[h111]*(x-1) + grad2[h111]*(y-1) + grad3[h111]*(z-1)

	n00 = n000 + (n001-n000) * w
	n01 = n010 + (n011-n010) * w
	n10 = n100 + (n101-n100) * w
	n11 = n110 + (n111-n110) * w

	n0 = n00 + (n01-n00) * v
	n1 = n10 + (n11-n10) * v

	return n0 + (n1-n0) * u
}

function fractal3d(x, y, z, octaves) {
			val = 0;
			for (i = 0; i < octaves; i++) {
				val += noise(x, y, z) / pow(2, 0.5 + i - 0.5 * i);
				x -= i * 7;
				y += i * 13;
				z -= i * 23;
				x *= 1.57;
				y *= 1.57;
				z *= 1.57;
			}
			return val;
}

gradinit()
buildTable()