| created | "2026-07-07T00:00:00.000Z" |
| modified | "2026-07-31T00:00:00.000Z" |
| reviewed | "2026-07-07T00:00:00.000Z" |
| name | comfy-math-strings |
| description | ComfyUI compute/string nodes: constants, sliders, math expressions, string concat/split/replace/regex, type conversion, JSON/list utilities. Use when computing a value or assembling a string in a workflow. |
| allowed-tools | Read, Grep, Glob |
ComfyUI math & strings
Compute and assemble. Numbers in, numbers out; strings in, strings
out; primitives that hold a constant; sliders that expose a tunable.
The split:
| Pack | Niche |
|---|
comfyui-kjnodes | Primitives (BOOL / INT / Float / String / Multiline), SimpleCalculatorKJ, JoinStrings / JoinStringMulti, AppendStringsToList, Something/WidgetToString |
comfyui_essentials | Math hierarchy: SimpleMath / SimpleMathFloat / SimpleMathInt / SimpleMathDual (AST-based) |
comfyui-custom-scripts (pysssss) | MathExpression (full numpy + math imports), StringFunction (regex), StringNodes (split/case/trim) |
comfyui-mxtoolkit | mxSeed, mxSlider, mxSlider2D widget-driven values |
bjornulf_custom_nodes | AnythingToText / AnythingToInt / AnythingToFloat, TextReplace, CombineTexts, RandomLineFromInput |
ComfyUI-Crystools | CBoolean / CInteger / CFloat / CText / CTextML primitives, CJsonFile / CJsonExtractor / CListAny / CListString |
comfyui-easy-use | easy string / easy int / easy float identity nodes, easy rangeInt |
comfyui-dream-project | DreamCalculation, DreamLinear, sine/saw/triangle waves (animation-flavored, see "out of scope") |
comfyui_yvann-nodes | FloatToInt, InvertFloats, MaskToFloat, FloatsToWeightsStrategy |
When to Use This Skill
| Use this skill when... | Use instead when... |
|---|
| Computing a value or assembling a string in a workflow | Forming a boolean from that computation -> comfy-conditionals |
| Converting between types (anything -> int/float/string) | Displaying the result -> comfy-debug-preview |
Sources of truth
custom_nodes/comfyui-kjnodes/nodes/nodes.py โ primitives, JoinStrings, Something/WidgetToString
custom_nodes/comfyui_essentials/misc.py โ SimpleMath family
custom_nodes/comfyui-custom-scripts/py/math_expression.py โ pysssss MathExpression
custom_nodes/comfyui-mxtoolkit/ โ slider widgets
custom_nodes/ComfyUI-Crystools/crystools/nodes_*.py โ primitives, list helpers, JSON extractor
custom_nodes/bjornulf_custom_nodes/ โ Anything-To-* converters
Math โ which node?
| Need | Best node | Why |
|---|
| Single FLOAT expression, simple ops | SimpleMathFloat (essentials) | Tight; one expression in, FLOAT out |
| Single INT expression | SimpleMathInt | Same, INT result |
Multi-variable expression (a, b, c, d) โ (a+b)/c etc. | SimpleMath | AST-based eval over named inputs; safe (no module imports) |
| Two values, binary op (add/sub/mul/div/pow) | SimpleMathDual | Op picker widget |
| Many variables (aโj) | SimpleCalculatorKJ (kjnodes) | Up to 10 named inputs |
Need numpy / math import โ np.sqrt, math.pi, np.clip, etc. | MathExpression (pysssss) | Full module access, expression as string |
| Animation curve over a frame index โ linear ramp, sine wave | DreamLinear, DreamSineWave etc. | Built-in time/frame parameter |
| Float โ INT | yvann FloatToInt (round/ceil/floor), AnythingToInt (bjornulf) | yvann has the rounding mode; bjornulf is the lenient any-input version |
| Invert FLOAT (1โx or โx) | yvann InvertFloats | Mode picker |
Math hierarchy in one line
SimpleMathFloat < SimpleMath < SimpleCalculatorKJ < MathExpression
Pick the simplest one that compiles. MathExpression (pysssss) is the
"escape hatch" โ full numpy + math imports, but a typo crashes the
node with an opaque traceback. Use it only when AST-safe SimpleMath
can't express what you need.
SimpleMath syntax
Variables: a, b, c, d (wire them as inputs).
Operators: + - * / // % **, parentheses, unary -.
Functions: min, max, abs, round, int, float.
SimpleMath:
expression: int(sqrt(a * 1000000 * b) / 8) * 8
a = megapixels
b = aspect_ratio
โ width snapped to multiple of 8
SimpleMath does NOT support sqrt natively โ drop to
MathExpression for that. Actual AST-safe set is limited; check the
node source for the allowed call list.
MathExpression syntax
import numpy as np
import math
# Expression โ single line:
int(math.sqrt(a * 1e6 * b) / 8) * 8
# Or use numpy:
int(np.sqrt(a * 1e6 * b) / 8) * 8
You write an expression string referencing input variable names that
the node has registered. The node has math and numpy (as np)
already imported. Errors surface as red node + traceback in the
server log; nothing in the workflow UI.
Strings โ concat, replace, regex, split
| Need | Best node |
|---|
| Concat a few strings with a delimiter | JoinStrings (kjnodes, 5-arg) |
| Concat many | JoinStringMulti (kjnodes, dynamic N inputs) |
| Concat 2 with no delimiter | CombineTexts (bjornulf) |
| Find/replace literal | TextReplace (bjornulf) |
| Find/replace regex | StringFunction (pysssss; regex_mode toggle) |
| Pick random line from multiline | RandomLineFromInput (bjornulf) |
| Split on delimiter | StringNodes (pysssss, operation picker) or TextSplitByDelimiter (mixlab) |
| Add line numbers | AddLineNumbers (bjornulf) |
| Tokenize | DreamStringTokenizer (dream-project, word-splitter) |
| Build STRING from a list | AppendStringsToList (kjnodes) |
Single-line vs multiline
StringConstant (kjnodes) โ single line, no embedded newlines
StringConstantMultiline (kjnodes) โ multiline, ideal for prompt
bodies, JSON snippets, multi-clause text
CText (Crystools) โ single line
CTextML (Crystools) โ multiline
Pick multiline for any string longer than ~80 chars or any string
with embedded newlines. Single-line variants are for short labels and
filenames.
Regex via StringFunction
StringFunction (pysssss):
action: replace
regex_mode: ON
text: "michael.jpg"
find: "\.(png|jpg|jpeg|webp)$"
replace: ""
โ "michael"
Useful for stripping extensions from a filename (the exact pattern
we hit in the comfy-image-utils recipe set). Action picker also
supports append, replace, tidy tags (the last one normalizes
commas/spaces in tag lists for booru-style prompts).
Type conversion
bjornulf's AnythingTo* family is the most lenient โ it accepts
literally any input type and produces the named scalar:
| Node | Output | Notes |
|---|
AnythingToText | STRING | str(x)-equivalent on any input |
AnythingToInt | INT | Coerces float / string / bool; raises if string isn't parseable |
AnythingToFloat | FLOAT | Same, FLOAT target |
SomethingToString (kjnodes) | STRING | Similar to bjornulf's AnythingToText |
WidgetToString (kjnodes) | STRING | Reads a specific widget by name from a target node โ useful for surfacing arbitrary widget values into the data flow |
easy string / easy int / easy float (easy-use) are identity
nodes โ they don't convert, just pass through. Their purpose is to
expose a widget UI for a value that downstream nodes will consume; a
debug-friendly handle.
Primitives & sliders
| Source | What it gives you |
|---|
kjnodes INTConstant / FloatConstant / StringConstant / BOOLConstant / StringConstantMultiline | Plain widget-input constants |
Crystools CInteger / CFloat / CText / CTextML / CBoolean | Same, plus some have widget toggle for live update |
mxtoolkit mxSlider | Single tunable INT or FLOAT slider with live drag |
mxtoolkit mxSlider2D | 2D drag-pad emitting two independent values |
mxtoolkit mxSeed | INT pass-through with a seed-control widget (random / fixed / increment) |
easy rangeInt | Emit a range of INTs โ start, end, plus step mode or num_steps mode |
RepeatImageToCount is image-specific (covered in comfy-image-utils); for value-list repetition use Python via JoinString | |
Seed strategy
ComfyUI core's Seed node and the seed widget on KSampler both
support fixed/random/increment. mxSeed adds a slider-style UI and a
pass-through value (useful when one seed feeds multiple samplers and
you want it visible). Seed Everywhere (cg-use-everywhere) is
deprecated in favor of Anything Everywhere connected to an INT.
JSON & lists (Crystools)
| Node | Use |
|---|
CJsonFile | Load a JSON file from disk; emits the parsed structure as a JSON object |
CJsonExtractor | Extract values from a JSON object via dot-path / JSONPath syntax |
CListAny | Build / pass a list of any type |
CListString | Build a list of strings (sometimes more convenient than concatenation) |
Typical use: load a config JSON, extract one value, feed into a
downstream node. The Crystools JSON nodes don't do JSON-write; for
that, save text via bjornulf SaveText or use the MathExpression
escape hatch.
Recipes
Resolution math from megapixels + aspect ratio
You want a target image size of "โ1 MP, 16:9 aspect, both dimensions
divisible by 8".
PrimitiveFloat (mp = 1.0) โโโ
โผ
PrimitiveFloat (ar = 16/9) โโบ MathExpression (pysssss)
โฒ expression: int(math.sqrt(a * 1e6 * b) / 8) * 8
โ a = mp, b = ar
โผ
width = 1336 (for ar=1.78)
(compute height by 1e6/width or as another expression)
Two MathExpression nodes: one for width, one for height = int((a * 1e6) / b / 8) * 8
with the same mp input and width as b. The 8-snapping handles
SD/Flux/Wan latent alignment automatically.
Filename templating
SaveImage.filename_prefix accepts %date:yyyy-MM-dd% / %date:hhmmss%
substitution plus %NodeName.widget%. A run-signature shape
(sampler/scheduler/seed) keeps runs distinguishable, but the exact
convention is per-install โ see "Naming conventions are per-install" in
comfy-workflow-json. When the native substitution isn't enough (e.g. you
need to strip an extension from a source filename), assemble the prefix via:
LoadAndResizeImage โโโบ image_path (STRING, kjnodes)
โ
โผ
StringFunction (pysssss)
action: replace, regex: ON
find: "\.(png|jpg|jpeg|webp)$"
replace: ""
โ
โผ (basename without ext, STRING)
JoinStringMulti (kjnodes)
in_1: "<bucket>/%date:yyyy-MM-dd%/%date:hhmmss%_%ksampler.sampler_name%_%ksampler.scheduler%_s%ksampler.seed%_"
in_2: <stripped basename> # the <descriptor> segment
โ
โผ
easy imageSave (filename_prefix STRING input)
The %date:...% tokens are passed through verbatim; SaveImage's
internal substitution resolves them at save time. The
%LoadImage.image% widget-substitution is bypassed entirely โ we
build the final string in the graph.
Build a comma-separated tag list from individual triggers
Three LoRA trigger words plus a manual prompt, combined:
LoraLoaderVanilla (lora_1) โโโบ civitai_tags_list (STRING) โโโ
LoraLoaderVanilla (lora_2) โโโบ civitai_tags_list (STRING) โโโค
LoraLoaderVanilla (lora_3) โโโบ civitai_tags_list (STRING) โโโค
PrimitiveStringMultiline ("a portrait of a woman") โโโโโโโโโโโโค
โผ
JoinStringMulti (delimiter = ", ")
โ
โผ
CLIPTextEncode
Empty trigger strings produce an extra , โ pipe through
StringFunction (action: tidy tags) to collapse redundant separators.
Range-driven batch
Generate 10 images at incrementing CFG values:
easy rangeInt
start: 3, end: 12, num_steps: 10
โ
โผ (emits 10 INTs at execution)
(route into a forLoopStart, each iteration sets KSampler.cfg)
Pair with easy forLoopStart / forLoopEnd (see comfy-flow-control)
for actual iteration.
Gotchas
SimpleMath โ MathExpression. Essentials' SimpleMath is
AST-safe (no imports, limited function set โ no sqrt, no numpy).
Pysssss MathExpression has full math + numpy access. Don't mix
them up.
- kjnodes Constants vs Crystools Constants โ they look
interchangeable. They mostly are, but Crystools'
CFloat /
CInteger widgets default to wider ranges and Crystools' multiline
CTextML has different newline handling on Windows. Pick one pack
per workflow for consistency.
MathExpression errors are server-side. The node turns red but
the error message ("Error executing MathExpression: NameError")
lives in the ComfyUI server log (journalctl -u comfyui.service
on this install). Add a ShowAnything on the output to confirm
it's emitting what you expect.
StringFunction regex syntax is Python re. Forward slashes
are NOT escapes; backslashes are. \.(png|jpg|jpeg|webp)$ works.
/\\.(png|jpg|jpeg|webp)$/ does not โ that's JavaScript syntax.
AnythingToInt on a non-numeric string crashes. "3.14" โ
fails; "3" โ works; 3.14 (float) โ 3. To coerce a possibly
non-numeric STRING, route through MathExpression with
int(float(a) if a else 0) and a defensive try wrapper.
JoinStringMulti shrinks dynamic inputs. The first time you
add a downstream consumer, the node grows its slot count. If you
later disconnect, the empty slots stay around. Drop and re-add the
node to compact.
easy rangeInt num_steps is INCLUSIVE on both ends, so
start=0, end=10, num_steps=11 gives [0, 1, 2, ..., 10]. With
num_steps=10, you get [0, 1.11, ..., 10] โ not integer.
Prefer the step mode when you want integer-only spacing.
Cross-refs
comfy-conditionals โ feeding math output through a comparator
to form a boolean predicate.
comfy-debug-preview โ ShowAnything / DisplayAny / ShowFloat
for inspecting intermediate math results.
comfy-flow-control โ easy rangeInt feeding forLoopStart;
primitives as switch selectors.
comfy-prompting โ string assembly for prompts (this skill is the
primitive layer; comfy-prompting is the application).
- Project CLAUDE.md "SaveImage filename substitution" โ native
%date:%/%NodeName.widget% syntax that complements the
string-graph approach.
Things this skill does NOT cover
- Animation schedulers โ
DreamSineWave, DreamSawWave,
DreamTriangleWave, FloatsToWeightsStrategy, frame-counter ops.
These are math primitives but their application (AnimateDiff /
IPAdapter transitions / weight schedules over frames) is its own
domain. Future comfy-animation-schedules skill will cover this.
For now: the nodes exist, they emit FLOATs / FLOAT lists driven by
a frame index; consult the comfyui-dream-project and
comfyui_yvann-nodes repos for application examples.
- Display-only nodes โ
ShowText, DisplayAny, ShowFloat,
Crystools CConsoleAny*. Those are inspection, not computation;
see comfy-debug-preview.
- Image / mask arithmetic โ
ImageBlend, MaskComposite. Those
are pixel ops, not scalar math; see comfy-image-utils.
- Sampler internals โ
cfg, denoise, step counts. Math-driven
scheduling of those values is fine, but the values themselves
live in the model-family skills.