Nodes/ComfyUI_MieNodes/保存剧本 · Save Script Asset 🐑
ComfyUI Node

保存剧本 · Save Script Asset 🐑

Authoring the H3 plan without a single model call

By MieMieeeee·Created 2 years ago·Updated 6 days ago· 280
保存剧本 · Save Script Asset 🐑
    • name
    • storyboard
    • status
    ◄library_dir►
    ◄name(下拉选择剧本 · pick script)►
    ◄json_text►
    ◄new_name►

    Every "let the LLM write the prompts" pipeline I've used eventually hits the same wall: on a good day it writes something better than I would have, and on a bad day it silently moves a character to the wrong side of the room and burns six API calls finding out. MieNodes' answer is a second track - you write the storyboard, code does the assembly. Save Storyboard Asset|Mie is the authoring half of that: a text box, a name, a file on disk.

    What it is

    It's a storyboard writer, not a generator. You paste JSON describing a short multi-shot sequence - cast, shots, dialogue, style prefix - and it validates the thing and stores it at <library_dir>/storyboards/<name>/storyboard.json. Load Storyboard Asset|Mie then reads it back, and BuildPlanFromStoryboard|Mie (or the V3 generator) turns it into the plan_json the MiniMax H3 loop chain consumes.

    Why bother, when the LLM generators in the same pack will write a plan from a paragraph? Because the interesting part of an H3 loop is repeatability. A storyboard is a file: it diffs, it version-controls, it survives the provider having a bad afternoon, and re-running it gives you the same plan byte for byte. That's the entire pitch, and it's a good one.

    The three inputs

    • library_dir - blank means the default asset library; anything you type must be an absolute path. Same rule as every other asset node in the pack.
    • name - two mutually exclusive modes on one widget. 📋 Existing shows a dropdown of storyboards already on disk; picking one and saving overwrites it. ✏️ New takes the name you type in new_name and creates it. If both look plausible, the new name wins - pick one mode and stay in it.
    • json_text - the multiline box you paste into. It carries a placeholder listing the required fields, which is genuinely the best short spec of the schema.

    Outputs: name (STRING), storyboard (MIE_STORYBOARD, the same bundle the Load node emits, so you can author and build in one graph), and status - created (<path>) or overwritten (<path>). This is an output node too, so it runs whenever the graph runs, and it will happily rewrite the file each time.

    The schema, in the size you actually need

    The minimum that survives validation is smaller than the docs suggest:

    {
      "name": "living_room_dialogue",
      "version": 1,
      "language": "zh",
      "camera_discipline": "locked",
      "pacing": "normal",
      "seed_policy": "per_scene_increment",
      "prompt_prefix": "A cozy cottage living room, polished 3D, warm light.\nThe camera stays locked off.",
      "cast": {"granddaughter": {"character_slot": 1}, "grandpa": {"character_slot": 2}},
      "setting_line": "Grandpa and the girl sit on the sofa, talking.",
      "shots": [
        {"lines": [{"speaker": "granddaughter", "text": "爷爷,我一直有个心理阴影。"},
                   {"speaker": "grandpa", "text": "是什么呢。"}]}
      ]
    }
    

    Three rules bite hardest. prompt_prefix, setting_line, picture and ambience must be English - a CJK character in any of them is a hard rejection, because those strings are dropped verbatim into an English prompt and the author refuses to machine-translate them. The line text is verbatim - that's your dialogue, it goes into the <d> tag byte for byte, so it follows language, not the English rule. And shots must be a non-empty array on save; an empty [] is an error, not "auto-pack please". Omit shots entirely if you'd rather supply a flat top-level lines array and let the assembler pack it two lines at a time.

    cast maps speaker names to picture slots 1–8. Slots are absolute, not decorative - if your cast uses 1 and 3, something must be wired at character_2 downstream. Optional extras worth knowing about: spatial_layout (who stands where, and a pin for an off-screen speaker is rejected), ambience (one English line shared by the whole film), and assembly_mode: "authored" for when you've written each shot's complete prompt yourself - which forces prompt_prefix to be empty and allows a prompt string per shot plus up to 32 lines instead of 2.

    Install

    cd ComfyUI/custom_nodes && git clone https://github.com/MieMieeeee/ComfyUI-MieNodes
    cd ComfyUI-MieNodes && pip install -r requirements.txt
    

    Restart, or install MieNodes from ComfyUI Manager (registry publisher mie). Nothing here downloads weights - the pack's dependencies are ordinary pip packages for file handling, and the storyboard track needs no model at all.

    Getting burned

    The classic one: the name inside your JSON has to match the destination name exactly. Paste a template you copied from a tutorial and save it as living_room_dialogue, and you get an error naming both - which is the node protecting you from a load-time mismatch that would otherwise surface three nodes later.

    Then there's the reload behaviour. Save a new storyboard, go to the Load node, and the dropdown looks empty: it was populated before your file existed. Press R. Everyone hits both of these once.

    Category🐑 MieNodes/🐑 Assets

    Inputs (4)

    NameTypeDefaultDescription
    library_dirSTRING—
    nameCOMBO(下拉选择剧本 · pick script)剧本名:📋 已有剧本 Existing 模式下拉选名字 = 覆盖;✏️ 新建 New 模式输入名字 = 新建(互斥二选一)。 Storyboard name: 📋 Existing = overwrite, ✏️ New = create.
    json_textSTRING新版资产 version=2:角色编号连续,每条事件明确角色、类型、原文与语言。展开 events 必须逐条匹配 source_script;允许纯动作及多句对白。错误会带具体原因,不保存不完整资产。节点内外使用同一份系统指令和校验器。角色和场景可独立留空;默认外观写 character_designs 及 execution.character_designs,接入资产时覆盖对应默认设计。
    new_nameSTRING—

    Outputs (3)

    NameTypeDescription
    nameSTRING—
    storyboardMIE_STORYBOARD—
    statusSTRING—