I’ll try to break down the scopes and variable visibility.
//this is the global scope, code here runs once when the pattern loads
//variables created here may be accessed in any scope
var thisIsAGlobal = 1
thisIsAnImplcitGlobal = 2
function thisIsAFunction (thisIsAParameter, anotherParameter) {
//this is a local scope, code here runs when the function is called
//variables created here may be accessed only while this function runs
//parameters are also locally scoped, and work just like local variables
var thisIsALocal = 3
//however, you can also implicitly declare globals when the 'var' keyword isn't used
thisIsAnotherImplicitGlobal = 4
}
Keep an eye out for implicitly declared globals in a function. The default rainbow uses these! I’ll annotate with comments:
export function beforeRender(delta) {
t1 = time(.1) //this creates an implicit global, which will be used later in another function
}
export function render(index) {
h = t1 + index/pixelCount // Here the global t1 is accessed.
// this also created another implicit global 'h', but it could have been a local
s = 1 //another
v = 1 //another
hsv(h, s, v)
}
The other trick to scopes is that it’s possible to create independent variables with the same name. When a function declares a variable or parameter, it will shadow (hide) a global with the same name. Here are 3 different count variables:
var count = 10 //a global
function setCount() {
count = 30 // the count global may be used or modified. calling this function will set the global count
}
function myFunction() {
var count = 5 //a local variable, declared with the 'var' keyword and will shadow the global
//the global count is a different variable, and now cannot be seen/used by this function
//...
}
function otherFunction(count) {
//here, a parameter is called count and acts just like a local variable
//the global count is a different variable, and now cannot be seen/used by this function
//...
}
I think some of the confusion comes from patterns using variables called h, s, and v as a shorthand, and implicitly declaring them as globals. When a slider function also has a parameter called v it is a completely different variable. These names could be anything, and perhaps using names with more uniqueness and careful attention to locally scope variables would aid in readability.
Here’s a pattern that sets all variables up with proper scope and with unique names. It is a basic moving rainbow with its own brightness slider.
//declare globals
var brightness //used to set the overall brightness through a slider
var t1 //a sawtooth waveform passed between beforeRender() and render()
export function sliderBrightness(sliderValue) {
//copy the local parameter sliderValue to the brightness global so it can be used later
brightness = sliderValue
}
export function beforeRender(delta) {
//generate a sawtooth waveform and store the current sample in the t1 global
t1 = time(.1)
}
export function render(index) {
//declare local variables.
var h, s, v
h = t1 + index/pixelCount
s = 1
v = brightness //here the V of HSV comes from the brightness global
hsv(h, s, v)
}
Here is the same pattern but using shorthand variable names and lazy variable scoping. It relies on both implicit global declaration for t1, and scope shadowing for v. Tricky!
export function sliderBrightness(v) {
b = v
}
export function beforeRender(delta) {
t1 = time(.1)
}
export function render(index) {
h = t1 + index/pixelCount
s = 1
v = 1
hsv(h, s, v * b)
}