Skip to content

Visualizers

nari.visualizer("bars.gdshader")

The file is a Godot canvas_item shader. It shows up in Now Playing’s visualizer button after the built-in ones, and Nari sets these uniforms every frame:

Uniform
uniform vec4 bands[8] 32 spectrum bands (4 per vec4), 0 to 1.
uniform vec4 peaks[8] Falling peaks of the bands.
uniform vec4 wave[32] 128 waveform samples, -1 to 1.
uniform float level Overall loudness, 0 to 1.
uniform float bass Average of the 4 lowest bands.
uniform float travel Grows over time, faster with bass, for scrolling effects.
uniform float progress Position in the current song, 0 to 1.
uniform sampler2D cover The current song’s cover.
uniform vec4 color_1, color_2, color_3 Theme colors: accent gradient, background tint and accent.
uniform vec2 rect_size Size of the area in pixels.

Declare only the uniforms you use. Nari’s own visualizers, assets/shaders/viz_*.gdshader, are good examples.

Pass a table to set your own uniforms too. Strings ending in an image extension are loaded from the plugin folder as textures:

nari.visualizer({
shader = "stars.gdshader",
params = { speed = 2.0, star_color = Color("#ffd27a"), noise = "noise.png" },
})

Leave shader out and give build and update to draw with nodes instead: particles, labels, your own _draw…

local bars = {}
nari.visualizer({
build = function(area)
bars = {}
for i = 1, 32 do
local bar = ColorRect.new()
bar.color = ThemeEngine:get_color(ThemeEngine.Colors.AccentBg)
area:add_child(bar)
bars[i] = bar
end
end,
update = function(data)
local width = data.size.x / 32
for i, bar in ipairs(bars) do
local height = data.bands[i] * data.size.y
bar.position = Vector2((i - 1) * width, data.size.y - height)
bar.size = Vector2(width - 4, height)
end
end,
})
  • build(area) runs every time the visualizer is picked, with an empty Control that fills its area. The nodes in it are freed when another visualizer is picked.
  • update(data) runs every frame while it’s shown, with bands, peaks, wave (lists of numbers, like the uniforms), level, bass, travel, progress and size. It doesn’t run while the music is paused.
  • A visualizer can have a shader and build/update at the same time; the nodes are drawn above the shader.