From 1055af7ca9c91b44561dd5f46bde1a6640eb571e Mon Sep 17 00:00:00 2001 From: Mark Z <93454788+markzvo@users.noreply.github.com> Date: Sat, 4 Oct 2025 23:53:19 -0500 Subject: [PATCH] Create bars.js A new RGB matrix generated with AI (Google Gemini) - tested as working in 4.14.3. It is similar to stripes except you can have multiple repeating stripes... "bars"... and you can adjust the width of the bars and the width of the gap between them. --- resources/rgbscripts/bars.js | 145 +++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 resources/rgbscripts/bars.js diff --git a/resources/rgbscripts/bars.js b/resources/rgbscripts/bars.js new file mode 100644 index 0000000000..76c124d6ca --- /dev/null +++ b/resources/rgbscripts/bars.js @@ -0,0 +1,145 @@ +/* + Q Light Controller Plus + Bars (ANIMATED - Configurable Width & Gap) + + FIXED: Configurable properties now use the "type:range|display:Label|values:min,max" + syntax confirmed to work in QLC+ scripts like propellor.js. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Development tool access +var testAlgo; + +( + function() + { + var algo = new Object; + algo.apiVersion = 2; + algo.name = "Bars"; + algo.author = "Google Gemini AI (via markzvo)"; + + // Initialize internal variables first, as seen in propellor.js and stripes.js + algo.orientation = 0; + algo.barWidth = 2; // Thickness of the 'ON' stripe + algo.gapWidth = 2; // Thickness of the 'OFF' gap + + // --- Properties Definition --- + algo.properties = new Array(); + + // Property 1: Orientation + algo.properties.push("name:orientation|type:list|display:Orientation|values:Horizontal,Vertical|write:setOrientation|read:getOrientation"); + + // Property 2: Bar Thickness (FIXED: Using type:range and values:min,max) + // Range type is used for integer sliders, similar to propellor.js + algo.properties.push("name:barWidth|type:range|display:Bar Thickness|values:1,30|write:setBarWidth|read:getBarWidth"); + + // Property 3: Gap Thickness (FIXED: Using type:range and values:min,max) + algo.properties.push("name:gapWidth|type:range|display:Gap Thickness|values:1,30|write:setGapWidth|read:getGapWidth"); + + + // --- Orientation Accessors --- + algo.setOrientation = function(_orientation) + { + if (_orientation === "Vertical") { algo.orientation = 1; } + else { algo.orientation = 0; } + }; + + algo.getOrientation = function() + { + if (algo.orientation === 1) { return "Vertical"; } + else { return "Horizontal"; } + }; + + // --- Bar Width Accessors --- + algo.setBarWidth = function(_barWidth) + { + // The value comes in as a string and must be parsed + algo.barWidth = parseInt(_barWidth); + if (algo.barWidth < 1) algo.barWidth = 1; // Safety check + }; + + algo.getBarWidth = function() + { + return algo.barWidth; + }; + + // --- Gap Width Accessors --- + algo.setGapWidth = function(_gapWidth) + { + // The value comes in as a string and must be parsed + algo.gapWidth = parseInt(_gapWidth); + if (algo.gapWidth < 1) algo.gapWidth = 1; // Safety check + }; + + algo.getGapWidth = function() + { + return algo.gapWidth; + }; + + + // --- Main Mapping Function --- + algo.rgbMap = function(width, height, rgb, step) + { + var map = new Array(height); + + var w = algo.barWidth; // Stripe ON width + var g = algo.gapWidth; // Stripe OFF width + var cycle = w + g; // Total cycle length + + for (var y = 0; y < height; y++) + { + map[y] = new Array(); + for (var x = 0; x < width; x++) + { + var isStripe = false; + var position; + + // Determine the coordinate to use based on orientation + if (algo.orientation === 1) { // Vertical Stripes: pattern repeats and scrolls on X + position = x; + } else { // Horizontal Stripes: pattern repeats and scrolls on Y + position = y; + } + + // Animated Check: Shift the pattern by 'step' + // If ((current position + animation offset) MOD cycle length) is less than the bar width, it's ON. + if (((position + step) % cycle) < w) { + isStripe = true; + } + + if (isStripe) { + map[y][x] = rgb; // Stripe color (current color from QLC+ function) + } else { + map[y][x] = 0; // Gap color (black/off) + } + } + } + + return map; + }; + + // --- Step Count Function --- + // The number of steps is equal to the total pattern cycle length (bar + gap). + algo.rgbMapStepCount = function(width, height) + { + // Return the dynamically calculated cycle length + return algo.barWidth + algo.gapWidth; + }; + + // Development tool access + testAlgo = algo; + + return algo; + } +)();