ComfyUI Node

3D Angles Selector

Spin a 3D sphere, get a whole character turnaround

By jianglinbin·Created 8 months ago·Updated 8 months ago· 1
3D Angles Selector
    • prompt
    selected_points[]

    You're here because you're building a multi-angle Qwen-Image-Edit workflow, and this is the nicest way to drive it. AnglesSelector3D drops a little Three.js sphere into your graph - complete with a cartoon cat standing in the middle of it - and you click points on the sphere to say "I want this character from front-right, elevated, wide" and also "back-left, eye level, close-up." Every point you click becomes one prompt string, and the node hands you back the whole list. It's a batch camera-rig UI for a LoRA that speaks camera vocabulary.

    The LoRA this was built for is the fal Multiple-Angles LoRA for Qwen-Image-Edit-2511. That whole family is the reason camera-angle work stopped needing OpenPose plus a ControlNet in the first place - posing and framing moved onto LoRAs trained on the edit model, and this pack is one of the purpose-built camera nodes that followed. The LoRA's trigger token is <sks>, and it understands prompts like <sks> front-right quarter view elevated shot close-up.

    How it works

    The heavy lifting is all in the browser. The node ships Three.js bundled in its own web/lib folder - no CDN, no internet needed - plus a toon_cat_free.glb model it plops at the center as a reference figure (if the GLB fails to load, it falls back to a simple humanoid, so the UI still works). Around the cat are 96 clickable spheres: 8 azimuths, 4 elevations, and 3 distance rings color-coded red (close-up), yellow (medium), and green (wide).

    Click a sphere to select it, click again to drop it. Drag to orbit the camera, scroll to zoom, double-click to reset to the front view, and each distance ring can be toggled on and off so the wide ring isn't in your way while you're picking close-ups. Every click serializes your selection into the node's one input - selected_points, a STRING holding JSON like [{"azimuth": 315, "elevation": 30, "distance": 2}] - and when the graph runs, the Python side parses that JSON and maps the numbers back to English phrases (315 → "front-left quarter view", 30 → "elevated shot", 2 → "wide shot") to build each prompt.

    The inputs and output that matter

    There's really only one thing to know here:

    • selected_points - the JSON state carrier. Normally you never touch it; the 3D widget writes it for you. If you edit it by hand, it must be a valid JSON array of {azimuth, elevation, distance} objects, or the node quietly returns an empty list.
    • prompt (output, a LIST of STRINGs) - one <sks> [azimuth] [elevation] [distance] prompt per selected point. That list output is the whole point: it's what turns one interaction into a batch of generations, a full turnaround from a single reference.

    Wire the output into a TextEncodeQwenImageEditPlus node the way the pack's example workflow does, and each angle becomes its own conditioning. Run it a few hundred times - cheap, now that lightx2v step-reduction LoRAs made that workflow actually affordable - and you've got a turnaround sheet without touching a camera.

    Installing it

    ComfyUI Manager (search "ComfyUI-AnglesSelect" or "3D Angles Selector"), or the old-fashioned way:

    cd ComfyUI/custom_nodes
    git clone https://github.com/jianglinbin/ComfyUI-AnglesSelect
    

    Restart ComfyUI. That's the entire install - there are no Python dependencies and no requirements.txt, because Three.js and the GLB model are bundled in the repo. The MIT license means you can even lift the widget code if you want. One heads-up: the README's clone URL is written lowercase and with hyphens (comfyui-angles-selector), which GitHub resolves fine, but the canonical repo name is ComfyUI-AnglesSelect.

    Gotchas

    The UI auto-switches to Chinese if your system locale starts with zh - that's a feature, not a breakage. If the 3D view ever fails to appear, check the browser console (F12); the widget logs AnglesSelector3D: Init error there. And remember: selected_points is a widget value, so save the workflow after you pick your points, or a fresh copy of the graph starts back at [] with zero prompts.

    Categoryutils

    Inputs (1)

    NameTypeDefaultDescription
    selected_pointsSTRING[]

    Outputs (1)

    NameTypeDescription
    promptSTRING