DreamShaderLang
Tooling

Commandlet

-run=DreamShader — every command and switch, path resolution, exit codes, and why it writes real assets when the editor does not.

-run=DreamShader is the headless entry point. It compiles DreamShader sources into persistent assets and decompiles existing material assets back into source files, with no editor UI and no bridge running.

AspectValue
ClassUDreamShaderCommandlet, in the DreamShaderEditor module
Invocation-run=DreamShader, equivalently -run=DreamShaderCommandlet
Commandscompile, generate, decompile, export
Exit codes0 success, 1 failure
Log categoryLogDreamShader
Commandlet flagsIsClient = false, IsEditor = true, IsServer = false, LogToConsole = true

The commandlet writes real packages. Compilation runs with the transient flag off, so /Game/… .uasset files are created and saved on disk. The interactive editor does the opposite — every compile there is memory-only. This is the intended way to materialize a whole project's sources in CI, and it is also how a commandlet run can leave assets that shadow the editor's in-memory materials. See In-memory Materials.

Synopsis

NotationMeaningExample
<x>Placeholder — substitute a real value; the angle brackets are not typed.Name = <string>
[ x ]Optional — the whole group may be left out.[, Root = <string>]
{ a | b }Choice — take exactly one of the alternatives separated by |.{ Node( … ) | Comment( … ) }
Repetition — the preceding item may appear any number of times.<property-declaration> …
UnrealEditor-Cmd.exe <project>.uproject -run=DreamShader <command> [<option>…]

<command> ::= { compile | generate | decompile | export }

-run=DreamShader { compile | generate } { -Source=<path> | -File=<path> | -All } [-Force]
-run=DreamShader { decompile | export } -Asset=<object-path> [{ -Out | -Output }=<path>]

Commands

The command name is the first bare (non--) argument. If there is no bare argument, a Command=<name> parameter is consulted instead. Matching is case-insensitive and surrounding whitespace is trimmed.

SpellingEquivalent toEffect
compilecompile one source file, or every project source, into assets
generatecompileidentical; alternate spelling
decompileexport a UMaterial / UMaterialFunction graph to a source file
exportdecompileidentical; alternate spelling

Anything else fails with Unknown DreamShader command '{Command}'. followed by the usage banner, and exits 1.

The first bare token is taken as the command name unconditionally, before any of it is validated. Writing an option without its leading dash first-run=DreamShader Source=X compile — consumes Source=X as the command name and produces Unknown DreamShader command 'Source=X'. Keep the command as the first bare argument.

compile / generate

OptionAliasesTypeRequiredDefaultMeaning
-Source=<path>-File=<path>stringone of the threecompile exactly one source file
-Allflagone of the threeoffcompile every project DreamShader source
-Forceflagnooffbypass the source-hash skip and regenerate unconditionally

Precedence: -Source is looked up first, then -File; -All is consulted only when neither yielded a value. -Source and -All together silently compiles only the one file. With none of the three, the usage banner is logged at Error and the run exits 1.

-Force bypasses the source-hash skip only. It deletes nothing.

-Source path resolution

Tried in this order; the first that applies wins.

OrderConditionResult
1the value is empty, or is an absolute pathnormalized as given
2<SourceDirectory>/<value> existsthat path
3<ProjectDir>/<value> existsthat path
4otherwisenormalized as given — which then fails the extension guard or the compile

<SourceDirectory> is the Source Directory project setting, default <Project>/DShader. A relative value therefore resolves against the DreamShader source tree first and the project directory second.

-All discovery and ordering

StepRule
1recursively collect *.dsm, *.dsh, *.dsf under <SourceDirectory>
2drop everything under <SourceDirectory>/Packages
3drop .dsh headers — they generate no assets and are inlined by their dependents
4sort: .dsf function files first (rank 0), then .dsm materials (rank 1); ties broken by case-insensitive path comparison

Step 4 is a guarantee, not an accident: function assets referenced by a material must exist before that material is generated, and the two-rank sort provides that within a single run. Step 2 has a sharp edge for .dsf files that live inside packages — see Packages.

Per-file guard

Each file in the compile list is checked before compiling. A path that is not a DreamShader source, or that is a .dsh header, logs DreamShader compile requires a .dsm or .dsf file: {Path}, marks the whole run failed, and the loop continues with the remaining files. One bad file therefore does not prevent the rest from compiling — but the process still exits 1.

Result messages

Each file's compile result is logged verbatim: Display on success, Error on failure. When one file produces several assets, the messages are joined with newlines.

MessageOutcome
Generated {Kind} {AssetPath} from {SourceFile}.a ShaderFunction / ShaderLayer / ShaderLayerBlend asset was generated; {Kind} is the block keyword
Generated {AssetPath} from {SourceFile}.material generated, Graph backend
Generated DreamShader thin-custom material {AssetPath} from {SourceFile}.material generated, ThinCustom backend
Skipped {AssetPath} from {SourceFile}; source hash is unchanged.hash match — pass -Force to regenerate
Generated DreamShader helper include '{Path}' from {SourceFile}.the file produced only a generated .ush
DreamShader file '{Path}' contains VirtualFunction declarations only; no assets were generated.success, nothing to write
DreamShader file '{Path}' contains GraphFunction declarations only; no assets were generated.success, nothing to write
DreamShader file '{Path}' did not contain any material, ShaderFunction, ShaderLayer, or ShaderLayerBlend assets to generate.failure
DreamShader header '{Path}' does not generate assets directly. Recompile dependent .dsm or .dsf files instead.failure — a .dsh reached the generator
{Path}: .dsf files cannot define top-level Shader blocks.failure

A message ending in (virtual) indicates a transient asset; the commandlet never produces those.

decompile / export

OptionAliasesTypeRequiredDefaultMeaning
-Asset=<object-path>stringyesthe asset to decompile
-Out=<path>-Output=<path>stringnocomputeddestination file

Asset path normalization

StepRule
1every \ becomes /
2if the path starts with / and contains no ., the short name is appended: /Game/Path/Asset/Game/Path/Asset.Asset

The normalized path is loaded first. If that fails and normalization actually changed the string, the raw (quote-stripped) input is retried unchanged.

Supported asset classes

ClassEmitsDefault destination
UMaterial.dsm<SourceDirectory>/Decompiled/Materials/<package path>.dsm
UMaterialFunction.dsf<SourceDirectory>/Decompiled/Functions/<package path>.dsf
UMaterialFunctionMaterialLayer.dsf<SourceDirectory>/Decompiled/Layers/<package path>.dsf
UMaterialFunctionMaterialLayerBlend.dsf<SourceDirectory>/Decompiled/LayerBlends/<package path>.dsf
anything elseerror

Path segments are sanitized: control characters and < > : " / \ \| ? * become _; an empty folder segment becomes Folder<N> and an empty asset segment becomes Asset<N>. Output is UTF-8 without BOM. -Out bypasses the computed destination entirely, creating the directory if needed. The full exporter behaviour is on Decompiler.

Argument syntax

Shared by every command, and pinned by the automation test DreamShader.Commandlet.Args.SplitAndGet.

RuleBehaviour
Key normalizationtrim, then strip all leading -, then trim again. -Source, --Source and Source are the same key
Name matchingcase-insensitive — -source, -SOURCE, -Source are equivalent
Value normalizationtrim, then strip one layer of surrounding quotes, then trim again
Assignment spliton the first =; a value may therefore contain =
Dashless assignmentbare Key=Value is accepted wherever -Key=Value is
Search orderthe parsed parameter map, then the switch list, then the bare-token list; the first match wins
Empty value-Source= resolves to an empty string and is treated as absent
Missing keyabsent

Boolean flags

A flag may be written bare or with a value. The value is lowercased before matching.

Written asResult
-Forceon
-Force= (empty value)on
-Force=1 / -Force=true / -Force=yes / -Force=onon
-Force=0 / -Force=false / -Force=no / -Force=offoff
-Force=<anything else>on

An unrecognized boolean value evaluates to on, not off and not an error. -Force=banana, -Force=disable and -All=never all enable the flag. There is no diagnostic. Use the literals in the table above.

Exit codes

CodeCondition
0the selected command reported success
0compile -All resolved an empty source list — logged Warning, treated as success
1no command token and no Command= value
1unknown command name
1compile with none of -Source / -File / -All
1any per-file guard failure or compile failure during compile
1decompile without -Asset, or a load / decompile / write failure

What does not run

  • The editor bridge never starts inside a commandlet. The editor module returns from startup as soon as it detects a commandlet process, so there is no source-directory watcher, no auto-compile-on-save, no WebSocket server on port 17864, no diagnostics.json writer, no bridge.db, and no menu registration.
  • The only exception is the cook commandlet, which installs a post-engine-init hook. On the cook director only — a process whose -run= contains Cook and that does not carry -cookworker — DreamShader materializes every project source as a persistent asset before the cook proper. A generation failure there is Fatal and aborts the cook.
  • Adding -NoDreamShaderEditorBridge to a non-commandlet automation run (for example -ExecCmds="Automation RunTests …") suppresses the bridge there too — see Editor Tools.

Diagnostics

All messages go to LogDreamShader. Runtime substitutions are written {Placeholder}.

MessageSeverityCause
(the usage banner)Errorno command token and no Command= value
Unknown DreamShader command '{Command}'. + the usage bannerErrorthe command is not compile / generate / decompile / export
(the usage banner)Errorcompile with neither -Source / -File nor -All
DreamShader commandlet found no source files to compile.Warningthe resolved source list is empty; the run still exits 0
DreamShader compile requires a .dsm or .dsf file: {Path}Errorthe file is not a DreamShader source, or is a .dsh header
(the compile result message)Display / Errorper-file outcome — see Result messages
(the usage banner)Errordecompile without -Asset
DreamShader could not load asset '{AssetPath}'.Errorthe asset failed to load under both the normalized and the raw path
DreamShader failed to decompile '{LoadPath}': {Error}Errorthe decompiler reported failure
DreamShader decompile supports Material and MaterialFunction assets only: {AssetPath}Errorunsupported asset class
Decompile did not produce source text.Errorthe decompiler failed with no error text
DreamShader failed to resolve an output file path.Errorthe destination path resolved empty
DreamShader failed to create output directory '{Directory}'.Errorthe destination directory could not be created
DreamShader failed to write decompiled source '{Path}'.Errorthe file could not be written
DreamShader decompiled '{LoadPath}' to '{OutputPath}'.Displaysuccess

The usage banner, verbatim:

Usage:
  -run=DreamShader compile -Source="C:/Project/DShader/File.dsm" [-Force]
  -run=DreamShader compile -All [-Force]
  -run=DreamShader decompile -Asset="/Game/Path/Asset.Asset" [-Out="C:/Project/DShader/Decompiled/File.dsm"]
Supported asset types: Material -> .dsm, MaterialFunction -> .dsf.

Examples

Compile a single source, bypassing the hash skip:

& "C:\Program Files\Epic Games\UE_5.5\Engine\Binaries\Win64\UnrealEditor-Cmd.exe" `
  "C:\Projects\MyGame\MyGame.uproject" `
  -run=DreamShader compile -Source="C:/Projects/MyGame/DShader/Materials/M_Sample.dsm" -Force `
  -unattended -nopause -nosplash -stdout -log

Compile every project source — .dsf first, then .dsm — as a CI gate:

& "C:\Program Files\Epic Games\UE_5.5\Engine\Binaries\Win64\UnrealEditor-Cmd.exe" `
  "C:\Projects\MyGame\MyGame.uproject" `
  -run=DreamShader compile -All -Force `
  -unattended -nopause -nosplash -stdout -log

Decompile an existing material to a chosen path:

& "C:\Program Files\Epic Games\UE_5.5\Engine\Binaries\Win64\UnrealEditor-Cmd.exe" `
  "C:\Projects\MyGame\MyGame.uproject" `
  -run=DreamShader decompile -Asset="/Game/Materials/M_Existing" `
  -Out="C:/Projects/MyGame/DShader/Decompiled/Materials/M_Existing.dsm" `
  -unattended -nopause -nosplash -stdout -log

A relative -Source resolves against DShader/ first:

-run=DreamShader compile -Source="Materials/M_Sample.dsm"

Console output of a successful two-file -All run:

LogDreamShader: Display: Generated ShaderFunction /Game/Functions/MF_Noise from C:/Projects/MyGame/DShader/Functions/MF_Noise.dsf.
LogDreamShader: Display: Generated DreamShader thin-custom material /Game/Materials/M_Sample from C:/Projects/MyGame/DShader/Materials/M_Sample.dsm.

Where next

On this page