⬡ Polyhedron Media Loader
One input node for images, video and audio, straight off your disk
- image
- mask
- video
- audio
- video_audio
- frame_count
- fps
- width
- height
- filename
- batch_info
- video_path
Most of this pack is about LoRA management, but the Media Loader is the part that quietly changes how you work. It's a pinned-folder input node: point it at any folder on your machine - not just ComfyUI's input directory - and you get a visual tile browser of everything inside. Images, videos and audio all show up as tiles, hover a video and it plays right in the grid, hover audio and it previews, click anything and it loads. It's the load node that finally treats media like files instead of forcing you to remember paths.
It was built to pair with the pack's Save node, and the round trip is the interesting part. Wire a mask into Save alone and it writes grayscale stills; load those back here and the grayscale rule turns them into the identical mask again. The "two-loader idiom" falls out of that: one loader carries your images, a second carries the masks, and a background-removal node takes both. Edit a mask in any painting tool, drop it back in the folder, hit re-read, and the correction flows through.
The outputs that matter
There are twelve, but a beginner lives on a handful:
image- the decoded frames; N = 1 for a still, the frame count for a video or batch.mask- a still's alpha (opaque → 0, transparent → 1, matching core LoadImage). A grayscale still without alpha carries its luminance as the mask, white → 1 - that inversion is what makes the Save round trip work.video- a single video file, losslessly with its own audio. Trim it and it's re-encoded from the sliced frames with the sound cut to the same window.audioandvideo_audio- the paired audio, and the frames muxed with it (wirevideo_audiointo a Save for an mp4 with a soundtrack).frame_count,fps,width,height,filename,batch_info,video_path- the metadata pins for scheduling and downstream logic.
Video and audio behavior worth knowing
Four widgets on the body control how video reaches the graph: frame_load_cap (max frames, 0 = all), frame_skip, force_fps (0 = native), and keep_input_fps. Trimming is drag-handles on a track with editable timecodes, and you can lock a fixed window and slide it through the clip - the tool for cutting many clips to the exact same length.
When a visual and audio are paired, one of them sets the length. Still + audio: the audio wins, and the still expands into a real clip of the audio's length. Video + audio: the video wins, and the audio is capped or silence-padded to fit. The picture never gets stretched to fit a track.
Installing it
It's part of the Polyhedron Suite pack:
cd ComfyUI/custom_nodes
git clone https://github.com/PolyhedronAI/ComfyUI-PolyhedronLoRAStack.git
# restart ComfyUI
or via Manager, search "Polyhedron Suite". The node itself has no hard dependencies, but video thumbnails and alpha-mask decoding lean on OpenCV and PyAV. Recent ComfyUI builds ship PyAV; if a feature degrades, pip install "polyhedron-lora-stack[media]" fixes it. If nothing loads, check on_empty - placeholder keeps a half-built graph running with a built-in frame, error stops the run instead.
One genuine security note: if you run ComfyUI with --listen, the loader's browse/upload routes return 403 to LAN clients on purpose - they can't read arbitrary folders on your host. Set ULS_ALLOW_LAN_BROWSE=1 to open them deliberately. On a normal localhost setup, nothing changes.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| media_ref | STRING | Managed by the node UI: the pinned folder + chosen file. Pick a folder and a thumbnail above. | |
| frame_load_cap | INT | 00–2000 | Video only: max frames to load (0 = all, capped for safety). |
| frame_skip | INT | 00–100000 | Video only: skip this many frames at the start. |
| force_fps | FLOAT | 24.000–240 | Output fps (default 24). 0 = the file's native fps. With keep_input_fps on, the native fps is used regardless. Sets the play rate, and the frame count when a still is expanded to the trimmed audio's length. |
| batch_config | STRING | Managed by the node's Batch panel: a small JSON {enabled, source, sort_mode, name_filter, every_nth, resize_method}. Empty / enabled=false = single mode. | |
| proc_config | STRING | Managed by the node's Batch Processing panel: a small JSON {enabled, source, sort_mode, name_filter, wrap, start_at, reset_seq}. enabled=true streams the folder one file per run (iterative mode). | |
| keep_input_fps | BOOLEAN | false | On: ignore force_fps and use the source's native fps (a still/sequence falls back to 24). Off: force_fps applies. |
| on_empty | COMBO | placeholder | When there is NOTHING to load (no selection, empty or empty-filtered folder, vanished file): emit a built-in placeholder frame instead of a hard error. Misconfiguration and decode failures always error. |
Outputs (12)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |
| video | VIDEO | — |
| audio | AUDIO | — |
| video_audio | VIDEO | — |
| frame_count | INT | — |
| fps | FLOAT | — |
| width | INT | — |
| height | INT | — |
| filename | STRING | — |
| batch_info | STRING | — |
| video_path | STRING | — |