欢迎来到 Skydimo 脚本开发世界!本指南将帮助您从零开始学习如何使用 Lua 脚本创建自己的 RGB 灯效,无论您是初学者还是高级用户。该功能在 Skydimo 内测版本推出。
目录
功能概览
- 自由创作:用 Lua 代码编写独一无二的灯效
- AI 辅助:一句话生成专属灯效,AI 帮您编写和优化代码
- 音频响应:让灯光随音乐律动,支持实时 FFT 频谱分析
- 多标签管理:同时编辑多个脚本,轻松切换和组织
- 热更新:修改即刻生效,无需重启软件
- 导入导出:分享您的创作,或使用社区脚本
- 完全控制:速度、亮度、色温、色调一应俱全
快速入门
第一个脚本:彩虹渐变
在 Skydimo → “脚本”页面,新建脚本并输入:
function get_color(x, y, width, height, env)
-- 根据位置和时间生成彩虹色
local hue = (x / width * 360 + env.time * 60) % 360
return hsv(hue, 255, 255)
end
操作步骤:
- 点击右上角“注册模式”按钮(右上角按钮从左到右一次为注册模式/更新模式、恢复、注销、导出、导入)
- 在模式列表中找到刚注册的脚本
- 点击启用,设备将显示流动的彩虹渐变效果
代码解析:
get_color:每个像素调用的函数x / width:生成 0–1 的位置比例env.time:不断增长的时间值,让颜色流动hsv():将色相、饱和度、亮度转换为 RGB 颜色
Lua 脚本基础
什么是 Lua?
Lua 是一种轻量级、易学的编程语言。Skydimo 使用 Lua 5.4 版本。
基本语法速查
-- 单行注释
--[[
多行注释
可以写多行
]]
-- 变量定义(不需要声明类型)
local speed = 100
local name = "Rainbow"
local enabled = true
-- 数学运算
local result = (10 + 5) * 2 / 3
-- 条件判断
if x > 10 then
-- 执行代码
elseif x == 5 then
-- 另一种情况
else
-- 默认情况
end
-- 循环
for i = 1, 10 do
-- 重复 10 次
end
-- 函数定义
local function calculate(a, b)
return a + b
end
核心接口规范
必选函数:get_color(x, y, width, height, env)
作用:为每个 LED 灯珠计算颜色值(每帧调用多次)
参数:
x、y:当前像素坐标(从 0 开始)width、height:设备总宽度/高度env:环境变量对象
返回值:一个 32 位整数,格式 0x00BBGGRR(蓝绿红顺序,每通道 0–255)
示例:
function get_color(x, y, width, height, env)
return rgb(255, 0, 0)
end
可选函数:begin_frame(env)
作用:在每帧开始前执行一次,用于预计算或初始化帧级变量。
-- 全局变量存储预计算结果
local wave_offset = 0
function begin_frame(env)
-- 每帧计算一次波浪偏移
wave_offset = math.sin(env.time) * 50
end
function get_color(x, y, width, height, env)
-- 直接使用预计算的值
local hue = (x / width * 360 + wave_offset) % 360
return hsv(hue, 255, 255)
end
环境变量详解
在渲染周期内,运行时会注入 env 环境对象,供 begin_frame 与 get_color 使用。常用字段如下(如有缺省,以具体版本实现为准):
env.time:自启动以来的累计时间(秒,浮点数)。env.dt:上一帧到当前帧的时间步长(秒)。env.fps:当前帧率(帧/秒)。env.random:0–1 的随机数种子(每帧变化)。env.bpm:节拍(Beat Per Minute),用于节奏驱动效果(可选)。env.audio:音频数据对象(可选),典型结构:env.audio.level:整体音量包络 0–1。env.audio.fft:频谱数组,低频到高频(如 64/128/256 槽)。env.audio.sampleRate:音频采样率。env.audio.enabled:音频输入是否启用。
示例:
-- 根据节拍做脉冲
local pulse = 0
function begin_frame(env)
if env.bpm then
local beat = env.time * env.bpm / 60.0
pulse = 0.5 + 0.5 * math.sin(beat * math.pi * 2)
else
pulse = 0.5 + 0.5 * math.sin(env.time)
end
end
function get_color(x, y, width, height, env)
local hue = (x / width * 360 + env.time * 30) % 360
return hsv(hue, 255, math.floor(255 * pulse))
end
内置函数库
为便于编写高质量灯效,运行时提供了一组常用工具函数(以下为常见约定,最终以具体版本为准):
-
颜色构造与变换:
rgb(r, g, b):返回 32 位颜色(0x00BBGGRR)。hsv(h, s, v):HSV 转 RGB,h: 0–360, s/v: 0–255。saturate(v):将数值夹紧到 0–1。clamp(v, min, max):区间裁剪。mix(a, b, t)/lerp(a, b, t):线性混合。smoothstep(edge0, edge1, x):平滑阶跃。map(x, inMin, inMax, outMin, outMax):区间映射。
-
噪声与随机:
random():0–1 随机。noise1(x)/noise2(x, y):平滑噪声(如 Perlin/Simplex 实现)。
-
数学与常量:
PI、TAU(2π)等。
示例:
-- 使用 smoothstep 做柔和的中心高亮
function get_color(x, y, width, height, env)
local u = x / math.max(1, width - 1)
local v = (height > 1) and (y / (height - 1)) or 0.5
local dx = u - 0.5
local dy = v - 0.5
local d = math.sqrt(dx*dx + dy*dy)
local glow = 1.0 - smoothstep(0.2, 0.5, d)
local hue = (env.time * 40) % 360
return hsv(hue, 255, math.floor(glow * 255))
end
音频可视化
借助 env.audio.fft 可以实现频谱响应、低频鼓点增强等效果:
local spectrum = {}
local smoothed = {}
function begin_frame(env)
if env.audio and env.audio.fft then
spectrum = env.audio.fft
-- 简单平滑
for i = 1, #spectrum do
local v = spectrum[i]
smoothed[i] = smoothed[i] and (smoothed[i] * 0.7 + v * 0.3) or v
end
end
end
function get_color(x, y, width, height, env)
if not smoothed or #smoothed == 0 then
return rgb(10, 10, 10)
end
local band = math.max(1, math.floor((x / math.max(1, width - 1)) * #smoothed))
local amp = smoothed[band] or 0
local h = (band / #smoothed) * 360
local v = math.floor(math.min(255, amp * 255 * 1.5))
return hsv(h, 255, v)
end
实践建议:
- 将低频(如 20–200Hz)映射到暖色,高频映射到冷色,增强声像感。
- 对整体音量
env.audio.level做全局亮度门限,弱音时降低功耗。 - 做峰值保持与缓慢衰减,获得更稳定的视觉反馈。
运行机制详解
渲染循环通常遵循以下顺序:
- 每帧开始先调用
begin_frame(env)(如实现)。 - 随后对每个像素按序调用
get_color(x, y, width, height, env)。 - 将本帧颜色缓冲提交到设备。
性能与内存建议:
- 在
begin_frame中做复杂计算与缓存,避免在get_color内重复开销。 - 避免创建大量临时表;复用数组、使用局部变量。
- 合理限制
math调用次数,优先使用预计算查表。
AI 辅助开发
在脚本编辑器中描述目标效果(例如“低频驱动暖色条形,节拍脉冲增强亮度”),AI 将生成初版代码;随后可继续对“颜色风格、速度、平滑参数”等提出修改建议,快速迭代。
实战案例
1) 频谱条形图(横向)
local smoothed = {}
function begin_frame(env)
if not (env.audio and env.audio.fft) then return end
local fft = env.audio.fft
for i = 1, #fft do
local v = fft[i]
smoothed[i] = smoothed[i] and (smoothed[i] * 0.6 + v * 0.4) or v
end
end
function get_color(x, y, width, height, env)
if not smoothed or #smoothed == 0 then return rgb(0,0,0) end
local band = math.max(1, math.floor((x / math.max(1, width - 1)) * #smoothed))
local level = smoothed[band] or 0
local barH = math.floor(level * height)
if (height - 1 - y) <= barH then
local hue = (band / #smoothed) * 360
return hsv(hue, 255, 255)
else
return rgb(0, 0, 0)
end
end
2) 流星雨(一维)
local tails = {}
local speed = 20 -- 像素/秒
local length = 10 -- 尾巴长度
function begin_frame(env)
-- 随机生成流星
if (env.time % 1.0) < env.dt * 2 then
table.insert(tails, { pos = 0, hue = (env.time * 80) % 360 })
end
-- 更新位置
for i = #tails, 1, -1 do
tails[i].pos = tails[i].pos + speed * env.dt
if tails[i].pos - length > 1000 then
table.remove(tails, i)
end
end
end
function get_color(x, y, width, height, env)
local v = 0
local hue = 0
for i = 1, #tails do
local p = tails[i].pos
local d = math.abs(x - p)
if d < length then
local k = 1.0 - d / length
v = math.max(v, math.floor(k * 255))
hue = tails[i].hue
end
end
if v > 0 then return hsv(hue, 255, v) end
return rgb(0, 0, 0)
end
3) 呼吸灯(二维)
local phase = 0
function begin_frame(env)
phase = (phase + env.dt) % 1.0
end
function get_color(x, y, width, height, env)
local u = x / math.max(1, width - 1)
local v = (height > 1) and (y / (height - 1)) or 0.5
local dx = u - 0.5
local dy = v - 0.5
local d = math.sqrt(dx*dx + dy*dy)
local breathe = 0.5 + 0.5 * math.sin((phase + d) * 2 * math.pi)
local hue = (env.time * 20) % 360
return hsv(hue, 200, math.floor(breathe * 255))
end
最佳实践
- 优先在
begin_frame做重计算与数据预处理。 - 用局部变量缓存频繁访问的全局对象(如
math,env.audio.fft)。 - 谨慎创建临时表,循环中尽量避免
table.insert带来的扩容开销。 - 对参数与返回值做边界保护(如
width-1的除零保护)。 - 颜色与亮度范围统一(0–255),超出需裁剪。
常见问题(FAQ)
Q1:get_color 返回格式是什么?
A:返回 32 位整数,格式 0x00BBGGRR。
Q2:为什么开启音频可视化没有反应?
A:检查 env.audio.enabled 与输入设备;另确认运行环境是否授予麦克风权限。
Q3:如何提高帧率?
A:减少 get_color 内的复杂计算;把可复用值放到 begin_frame;避免创建临时表。
Q4:是否支持多脚本同时运行?
A:取决于宿主实现;建议一个设备同时激活一个脚本以便调试与性能保障。