Common Code section

I was thinking it would be a good idea to have a code section separate from patterns where you could put code used in all patterns.

You could put routines/controls/variables in there that are used by multiple patterns. Something like global speed, or relay on for power to the LED’s.

I’m suggesting this, because I have found that I am copying and pasting the same code/controls/variables over and over into different patterns, as they all have the same controls, and are controlled via websocket (so the variables are the same also).

Then utility functions (I have HSV2RGB, RGB2HSV, and Relay_Control functions for example) could be separate from actual pattern code.

Exported variables and controls in the “Common Code” section would appear for all patterns (even if not used for that pattern). There may be a better way of doing this, maybe some sort of “include” mechanism? ie the common code section is only included if you specifically “include” it?

What do you think?

1 Like

Hi @Nick_W,
I’ve been thinking about something similar. The JS language has the module system which should work for this sort of thing.

Importing could have double benefits, allowing a pattern to import others in order to compose them, sequence, etc., and/or as a way to act as a library by consuming exported APIs.

Some global code could help give advanced configuration and behavior to the whole Pixelblaze. Maybe some kind of plugin/extension architecture for sharing these bits that aren’t patterns. Map code is one example, even if it runs in browser. Perhaps something that would allow you to trigger controls based on analog inputs, or adapters for network messages, automatic gain control for audio expansions, and that sort of thing. I’d want these to be more or less self-contained and independent, and having patterns depend on them could create portability issues.

For sharing code, having everything self contained really helps with sharing and distribution. I’d be very tempted to bundle up everything that the pattern imported so you don’t end up with a broken pattern, and it gets a bit tricky if you wanted to load a pattern that was bundled with a bunch of things, especially if those names were taken in the global namespace. For that to work without conflict, we’d need something like local packages. Theres a lot of ways of doing it, but I want it to work seamlessly and intuitively for beginner coders.

I’m currently leaning toward allowing multiple files in a pattern. These might be in an emulated filesystem with directories with a file list view and/or editor tabs, and support embedding documentation and possibly media assets in the future. Having a “standard library” as a secondary source would make the copy+paste a bit easier and cleaner, and would still be self contained for export/import.

2 Likes

As an example of a “common” include, defining missing v2 functions with a set of replacements would allow v3 code to work just by adding
something akin to include v3shims

I could see some of the code examples that seem to be good foundational code become “libraries” making a basic pattern using them just a few lines plus an include, rather than repeating dozens of lines of redundant code. That likely would help with limited space as well, right?

Ideally super common functions would make their way into native function land. I’ll start a topic to capture people’s favorite functions as candidates.

The array functions will make their way in to v2. I don’t think shims will work well (missing array length), and I think it will be better for everyone if they are on par language-wise without too many exceptions.

Wishlist here:

1 Like

Jus a quick thought inspired by the recent “segmented patterns” query. As WLED and other controllers add multistrip support, you’re going to see more of this.

What if a multi-pattern pattern could do “includes” on multiple “sub” patterns? Yes, existing patterns would have to be slightly rewritten… but I’m picturing having a standardized way of including multiple pattern code, maybe functions that mirror existing code beforerender/render but are geared to the needs of a “shared” setup. So I’d setup my multiple pattern to include KITT and 2 or 3 others, and segment info, and it would run the actual KITT code for those pixels within the larger setup.

Nontrivial for sure, but better than the alternative of requiring someone to cut and paste entire patterns into a massive pattern, and deal with conflicts and so on. A way to include functions would go a long way here.

Pattern segments is on the list, doable with V3 given the expanded memory available.

I thought about importing other patterns. This could work, and it might be a thing, but for solving this use case it introduces a lot of complexity and code.

Given the import capability mentioned above with a multi-file pattern, you could copy pattern code into another pattern as a separate file/module without the naming conflicts, then call out to the beforeRender and renders of the imported pattern. Each “module” gets its own module-global namespace, with sharing handled with import/export.

The linear pixel space needs to be split up somehow (1 range per, or something more complex?). The UI would need some way to select which segment(s) you were working with. Add in playlists, etc. I’ve seen how this is done in WLED, and it’s too confusing. Better than coding it though.

2 Likes

Not to add fuel to the fire, but if I wanted to segment a large matrix into smaller square ones, linear won’t work, but maps absolutely would.

Make segmenting entirely map based. Then I can define segment Map 1, segment Map 2, etc and never have to worry about the underlying stuff.

If I have 100 pixels (10x10 for example) and let me map them as 0-24, 25-49 , 50-74, and 75-99
I can’t do as much as if you’d let me just say Map1 is 0,0 thru .5,.5, Map 2 is 0.5,0 thru .5,1 and so on. Or perhaps Pattern 1 map, Pattern 2 map might be a better way to word/discuss this. Now render info could include what pattern/map the pixel lives in. Maybe
function render2D(index, x, y, segmentmap)

[After sleeping on this, I think some form of this is doable now, and might adapt the multi pattern to use mapping as a test.]

If it’s 1D only, the map is still easy, just use X.

In the long run, treating each segment as its own “virtual Pixelblaze”, with a UI subset allowing selecting the segment, a pattern and a map, would be the way to go.

Not today maybe, but I’m willing to wait – I’ve been badly underestimating how quickly small computers improve since the 90s, and at last I think I finally begin to understand the curve. In a couple of years, the microcontroller that sells at the ESP32 price point will be able to do this without breaking a sweat.

2 Likes

In digging thru code, I realized that @jeff’s rewrite/cleanup of the Utility Mapper ends up using a technique I’m going to modify/clone, to implement my idea above. (It calls multiple patterns, cycling thru them.) My multi-segment (ok, multimap) version won’t cycle, but will instead call different patterns, depending on the multiple maps and settings, either as a partial map or a renormalized map.

Kudos for his clean code techniques.

2 Likes

These thoughts remind me of my favourite GIMP plugin: MathMap, which in modern terms would be a “fragment shader”. MathMap does composition with a fancy GUI which, in the end, pastes all the pattern functions together in one messy thing which is sent to the compiler. Each function’s “namespace” is its lexical context and there is no global namespace. UI screenshot

In a PB context, static segmentation makes a lot of sense, since it usually depends on the physical layout of the LEDs … but you might also want to to determine the segmentation dynamically. Suppose we have a big matrix and want to display 4 different patterns in quadrants, but the segmentation of the quadrants can shift … when you specify a variable patternFOO, you get a widget letting you pick a pattern for FOO:

export var patternTL, patternTR, patternBL, patternBR
function render2D(x, y) {
   midpoint = 1/4 + 1/2 * wave(time(0.25))
   if (x <= midpoint) {
     if (y <= midpoint) {
       return patternTL(x/midpoint, y/midpoint)
     } else {
       return patternBL(x/midpoint, (y-midpoint)/(1-midpoint))
     }
   } else {
     ...
   }
}

I might also want to duplicate pixels without duplicating rendering … so for example, to project a 1D pattern (FOO, chosen in UI) radially:

var patternFOO
var pixels = array(pixelCount)
function beforeRender(pixelCount) {
  pixels.renderfrom(patternFOO)
}
function render2D(x,y) {
  return pixels[floor(length(x,y)*pixelCount]
}

More food for thought I guess :relaxed:

See my Multimap… You could easily use something like that.

If you really want to minimize calculation (same pattern radially), you could precalc and then push it all into a framebuffer (so calc once, then push to all matching pixels.

1 Like