FL Interactive Scan FX
Turn footage into a voxel scan nobody is controlling
- images
- analysis
- kick_envelope
- snare_envelope
- hihat_envelope
- final
- projected_surface
- reveal_mask
- report
You've seen the effect: a piece of footage gets rendered as a chunky voxel relief that looks like a lidar scan, someone drags a selection rectangle around, and the revealed windows show the world underneath as normal maps, digital edges and depth. FL Interactive Scan FX is that whole aesthetic in one node, and it's the largest and most opinionated thing in this pack.
Here's the trick, and it's why the node is called interactive when nothing is actually clicking: there are no hand-drawn cursors. The node generates cursor gestures procedurally - where they drag, how long they hold, which effect layer they reveal - from a seed, and then modulates all of it with your kick, snare and hi-hat envelopes. You steer by parameter, not by mouse. Stay with it and the "interaction" reads as deliberate, because the gestures are random-but-bounded rather than smooth.
What it takes in
images is the source video, and analysis is an autogrow input of FL_SCAN_ANALYSIS sockets - one per shot, chronological, from FL Scan Analysis. The frame accounting is strict: the summed analysis frames must equal the video frame count exactly, no padding, no repeats, and the error message tells you both numbers and the per-shot breakdown. That's the first thing to check when this node refuses to run.
kick_envelope, snare_envelope and hihat_envelope are typed FL_AUDIO_ENVELOPE sockets - not JSON, actual sockets, which means they only connect to the pack's audio analysis and beat sequencer nodes. All of them must match the video's frame count and its fps, or you get a straight error. Mismatched timing is the single most common way people break this pipeline.
Then the dials. cube_size (4–64) is the voxel cell size - larger cells, chunkier cubes. relief (default 0.65) is extrusion height; push it much past a comfortable range and neighbouring cubes start overlapping, which the node's own help text warns about. animation and speed control how much the voxel heights wobble and how fast. cursor_count (0–3) sets concurrent cursor lanes; zero disables reveals entirely. motion_strength is the audio-triggered camera accent strength. seed keeps it reproducible - the help text literally says keep it fixed to compare settings.
The settings that matter most
advanced_settings is a JSON blob with around fifty keys, and it's where the look actually lives: orbit angle, depth relief, scene scale, back-plate stacks and their palette, reveal window order and blending, voxel/edge/depth opacity and their relative weights, HUD and pose overlay opacity, glow colour and blend mode, depth parallax, and an audio_mappings list that binds envelopes to specific parameters. In the UI these are tabs, not typed JSON - the node build reads the metadata and presents sliders, colour choices and ranges per key. You should never hand-edit it unless you're copying settings between workflows.
The three layer weights - voxel, edge and depth - are the parts most worth your attention, because they decide what a gesture reveals. At least one has to be positive. Three cursor lanes hitting three different layers is the look people are chasing.
Outputs
final is the rendered video. projected_surface is the voxel/normal surface before the effects composite, which is useful for a quick sanity check on your normals. reveal_mask is the per-frame mask of where reveals happen - feed it downstream if you want to do something else inside those windows. report is a string of what the node actually did: cut points, cursor events, the resolved settings. When a render looks wrong, read the report before you touch a slider.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/filliptm/ComfyUI_Fill-Nodes
Restart ComfyUI. This node leans on PyAV and OpenCV for its video writes and previews - both in the pack's requirements - and on a recent ComfyUI for its node API. It loads no models: all the analysis comes from upstream nodes you already installed for depth, normals, masks and pose.
Where people get burned
Envelope frame counts. The strictest requirement in the node. Envelopes have to be generated at the same fps and length as the video, which usually means calculating your audio's frame count first and letting the audio side drive the video length, not the other way round.
Analysis resolution. Each shot's depth and normals must match the video's spatial dimensions. Depth maps from a downscaled analysis run need resizing before they arrive, and the node checks.
Cost. Voxel relief plus depth projection over a long clip is slow, and the node reports progress per shot and per stage so you can see where the time is going. Test on a few seconds. Nobody's first render of five hundred frames at cube size 8 goes well.
Inputs (14)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| analysis | COMFY_AUTOGROW_V3 | — | |
| kick_envelope | FL_AUDIO_ENVELOPE | — | |
| snare_envelope | FL_AUDIO_ENVELOPE | — | |
| hihat_envelope | FL_AUDIO_ENVELOPE | — | |
| fps | INT | 241–120 | — |
| cube_size | INT | 124–64 | — |
| relief | FLOAT | 0.650–2 | — |
| animation | FLOAT | 0.180–1 | — |
| speed | FLOAT | 0.700–5 | — |
| cursor_count | INT | 30–3 | — |
| motion_strength | FLOAT | 0.600–2 | — |
| seed | INT | 730–2147483647 | — |
| advanced_settings | STRING | {"orbit_degrees": 5.5, "depth_relief": 1.0, "scene_scale": 0.74, "stack_count": 4, "stack_spacing": 1.0, "stack_x": 1.0, "stack_y": 1.0, "stack_rotation": 0.0, "stack_opacity": 1.0, "stack_palette": "cobalt", "window_order": "newest_on_top", "window_blend": "normal", "voxel_opacity": 1.0, "edge_opacity": 1.0, "depth_opacity": 1.0, "window_fade_in": 0.0, "window_fade_out": 0.0, "normal_mix": 0.0, "hud_opacity": 0.7, "pose_opacity": 0.5, "surface_seed": 41, "min_cut_frames": 10, "max_cut_frames": 20, "cursor_scale": 1.2, "reveal_strength": 1.0, "base_brightness": 1.0, "brightness_intensity": 0.16, "base_saturation": 0.9, "saturation_intensity": 0.3, "edge_threshold": 0.15, "glow_intensity": 0.0, "envelope_intensity": 0.28, "glow_color": "white", "blend_mode": "screen", "motion_mode": "current", "parallax_scope": "whole_scene", "depth_style": "grayscale", "parallax_strength": 1.0, "offset_x": 0.0, "offset_y": 0.0, "dolly": 0.0, "steady_depth": 0.5, "voxel_weight": 50.0, "edge_weight": 50.0, "depth_weight": 0.0, "cursor_activity": 1.0, "reveal_size": 1.0, "audio_mappings": []} | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| final | IMAGE | — |
| projected_surface | IMAGE | — |
| reveal_mask | MASK | — |
| report | STRING | — |