跳到主要内容

灯效插件指南

灯效插件负责生成视觉灯光图案。它们接收一个 LED 缓冲区,并在每帧向其写入 RGB 颜色。

目录结构

plugins/effect.my_effect/
├── manifest.json # 元数据 + 参数定义
├── main.lua # 包含生命周期钩子的入口脚本
├── lib/ # 可选 Lua 模块
├── locales/ # 可选 i18n 文件
│ ├── en-US.json
│ └── zh-CN.json
└── data/ # 运行时数据目录

生命周期

用户选择灯效 → 实例化 Lua 环境
→ plugin.on_init()
→ plugin.on_params(params_table) ← 参数变更时调用
→ [渲染循环]
plugin.on_tick(elapsed, buffer, width, height)
→ plugin.on_shutdown()

生命周期钩子

on_init()

灯效实例化时调用一次。

function plugin.on_init()
-- 初始化状态,预计算查找表等
end

on_params(params)

用户更改参数值时调用,初始化时也会调用一次。

  • params —— 与 manifest params 键值对应的表
function plugin.on_params(p)
if p.speed then speed = p.speed end
if p.color then
base_r = p.color[1]
base_g = p.color[2]
base_b = p.color[3]
end
end

on_tick(elapsed, buffer, width, height)

每帧调用,向缓冲区写入 RGB 颜色。

  • elapsed —— 灯效启动以来的秒数(浮点数,持续递增)
  • buffer —— LED 颜色缓冲区(userdata,1-indexed)
  • width —— 布局宽度(用于 2D 效果)
  • height —— 布局高度(用于 2D 效果)
function plugin.on_tick(elapsed, buffer, width, height)
local count = buffer:len()
for i = 1, count do
local hue = (elapsed * 60 + (i - 1) / count * 360) % 360
buffer:set_hsv(i, hue, 1.0, 1.0)
end
end

on_shutdown()

灯效移除时调用,清理所有资源。

function plugin.on_shutdown()
-- 清理
end

Buffer API

buffer 对象提供设置 LED 颜色的方法:

方法说明
buffer:len()返回 LED 数量
buffer:set(i, r, g, b)通过 RGB 设置 LED 颜色(1-indexed,0–255)
buffer:set_hsv(i, h, s, v)通过 HSV 设置 LED 颜色(h: 0–360,s/v: 0.0–1.0)

Host 工具函数

颜色转换

local r, g, b = host.hsv_to_rgb(hue, saturation, value)
-- hue: 0-360, saturation: 0.0-1.0, value: 0.0-1.0
-- 返回: r, g, b (0-255)

日志

host.log("调试信息")
print("同样可用于日志输出")

屏幕捕获

灯效可捕获屏幕内容以实现环境灯光。需要 "screen:capture" 权限。

manifest.json
{
"permissions": ["screen:capture"]
}
-- 列出可用显示器
local displays = screen.list_displays()
-- 返回: {index, name, width, height, is_hdr}

-- 捕获屏幕(缩放至指定分辨率)
local frame = screen.capture(64, 36)
-- 返回: {width, height, pixels=[0xRRGGBB, ...]}
-- 失败时返回 nil

用户可通过 UI 选择要捕获的显示器。特殊参数 __screen_index__screen_region 由 Core 注入。

音频分析

灯效可对音频作出响应。需要 "audio:capture" 权限。

manifest.json
{
"permissions": ["audio:capture"]
}
-- 获取 FFT 数据
local data = audio.capture(32) -- 32 个频率区间
-- 返回: {amplitude, bins=[0.0..1.0, ...]}
-- amplitude: 整体音量级别
-- bins: 频率幅度值(从低到高)

媒体专辑封面

灯效可使用当前播放媒体的专辑封面。需要 "media:album_art" 权限。

备注

当前仅支持 Windows。在其他平台上返回 nil

manifest.json
{
"permissions": ["media:album_art"]
}
local art = media.album_art(64, 64)
-- 返回: {width, height, pixels=[0xRRGGBB, ...]}
-- 无媒体播放或当前曲目无封面时返回 nil

if art then
local pixel = art.pixels[1]
local r = (pixel >> 16) & 0xFF
local g = (pixel >> 8) & 0xFF
local b = pixel & 0xFF
end
提示

Core 在内部缓存专辑封面,仅在切换曲目时更新。在 on_tick 中每帧调用 media.album_art() 是安全的,不引入任何 I/O 开销 —— 无需自行缓存。

参数类型实战

Slider(滑块)

{"key": "speed", "kind": "slider", "min": 0, "max": 10, "step": 0.5, "default": 2}
function plugin.on_params(p)
if p.speed then speed = p.speed end -- number
end

Select(下拉选择)

{
"key": "mode",
"kind": "select",
"options": [{"label": "Wave", "value": 0}, {"label": "Pulse", "value": 1}],
"default": 0
}
function plugin.on_params(p)
if p.mode then mode = p.mode end -- number (value 字段)
end

Toggle(开关)

{"key": "reverse", "kind": "toggle", "default": false}
function plugin.on_params(p)
if p.reverse ~= nil then reverse = p.reverse end -- boolean
end

Color(颜色)

{"key": "color", "kind": "color", "default": "#FF0000"}
function plugin.on_params(p)
if p.color then
r, g, b = p.color[1], p.color[2], p.color[3] -- 各 0-255
end
end

MultiColor(多颜色)

{
"key": "colors",
"kind": "multi-color",
"default": ["#FF0000", "#00FF00"],
"minCount": 2,
"maxCount": 8
}
function plugin.on_params(p)
if p.colors then
-- {r, g, b} 表格的数组
palette = p.colors
end
end

完整示例:等离子灯效

local plugin = {}

local speed = 1.0
local scale = 3.0

function plugin.on_init() end

function plugin.on_params(p)
if p.speed then speed = p.speed end
if p.scale then scale = p.scale end
end

function plugin.on_tick(elapsed, buffer, width, height)
local count = buffer:len()
local t = elapsed * speed

for i = 1, count do
local x = (i - 1) / count * scale
local v1 = math.sin(x * 10 + t)
local v2 = math.sin(x * 10 * math.sin(t / 2) + t)
local v3 = math.sin(x * 10 + math.sin(t / 3) * 2)
local v = (v1 + v2 + v3) / 3

local hue = ((v + 1) / 2 * 360) % 360
buffer:set_hsv(i, hue, 1.0, 0.8)
end
end

function plugin.on_shutdown() end

return plugin

完整 API 请参阅灯效 API 参考