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)
}