dream-shader-create · diff
git:20261002.635465f to git:20261004.d47f43f
95 added, 108 removed. Audit A to A.
---
name: dream-shader-create
- description: Write a new DreamShaderLang material or material function from a plain-language description, then compile it headlessly to prove it builds. Use when asked to create, author, add, or write a .dsm / .dsf / DreamShader material, shader, or material function for an Unreal project.
+ description: Write a new DreamShader source from a plain-language description — a material, material function, layer, material instance or Custom Pass pipeline — then check and compile it headlessly to prove it builds. Use when asked to create, author, add or write a DreamShader material, shader, material function, material instance, .dss / .dsi / .dsp file (or a .dsm in a 1.x project), or a render pass for an Unreal project.
---
# dream-shader-create `<description>`
- Turn a description — "a UI panel with scrolling scanlines and a glow band" — into a `.dsm` that
- **provably compiles**. The verification step is not optional: DreamShaderLang has several traps
- (reserved builtin names, no matrix types, silent identifier rewrites) that only surface at compile.
+ Turn a description — "a UI panel with scrolling scanlines and a glow band" — into a source file that
+ **provably builds**. The proof is not optional: the compiler checks names, types, widths and engine pins, and
+ the only way to know a file passes is to run it.
Paths below are relative to the plugin root, `Plugins/DreamShader/`.
## Do this
- **1 — Read the grammar.** [`reference/dreamshaderlang.md`](../reference/dreamshaderlang.md).
- Do not write DreamShaderLang from memory; the builtin set is small and closed, and inventing a
- function name fails at step 3.
+ **1 — Pick the kind, then read its reference.** Do not write DreamShaderLang from memory.
- **2 — Decide, then write the file.**
+ | The user wants | Write | Read first |
+ | :-- | :-- | :-- |
+ | a material, material function, layer or layer blend | a `.dss` | [`reference/dss.md`](../reference/dss.md) |
+ | a variant of an existing material — other colours, other textures | a `.dsi` (material instance) | [`reference/dss.md` § 7](../reference/dss.md#7-instances--dsi) |
+ | a render pass — an outline, a blur, a screen effect, a compute shader writing a texture | a `.dsp` and the `.dss` materials its passes use. **UE 5.8+ only** | [`reference/dsp.md`](../reference/dsp.md) |
+ | a change in a project whose sources are `.dsm` / `.dsf` | match the project: a `.dsm` / `.dsf` — or offer [`dream-shader-migrate`](../dream-shader-migrate/SKILL.md) first | [`reference/legacy.md`](../reference/legacy.md) |
+ New work is `.dss`. Look at what the project already has (`DShader/**`) before choosing: mirror its folders,
+ naming (`M_`, `MF_`, `MI_`, `CP_`) and the doc-tag style of its parameters.
+
+ **2 — Decide the details, then write the file** under the project's `DShader/` tree. A `.dss` builds its asset
+ where the file is: `DShader/UI/M_Panel.dss` → `/Game/UI/M_Panel`, named after its `export` function.
+
| Question | Answer it with |
| :-- | :-- |
- | Material, or reusable function? | `.dsm` holds one `Shader`; `.dsf` holds `ShaderFunction`/`ShaderLayer`/`ShaderLayerBlend`; `.dsh` holds helpers only |
- | Where does the asset land? | `Shader(Name="UI/M_Panel")` → `/Game/UI/M_Panel`. `Root="Plugin.X"` for a content plugin |
- | Node graph, or one HLSL node? | `Settings { Backend = "Graph"; }` for a graph an artist can open; omit for the default thin-custom material |
- | Which surface? | `Domain` `ShadingModel` `BlendMode` — see [`Docs/settings/material-enums.md`](../../Docs/settings/material-enums.md) |
- | A render pass of your own, not a material? | a `.dsp` Custom Pass pipeline (UE 5.8 only), which this skill does not write: start from [`Docs/language-v2/passes.md`](../../Docs/language-v2/passes.md) and [`Docs/examples/custom-pass.md`](../../Docs/examples/custom-pass.md). It compiles with the same `dsc.ps1 compile`; its pass materials are ordinary `.dss` sources |
-
- Write it under the project's `DShader/` tree — `DShader/Materials/` for `.dsm`,
- `DShader/Functions/` for `.dsf`, `DShader/Shared/` for `.dsh`.
+ | Which surface? | `#pragma material(Domain = …, ShadingModel = …, BlendMode = …)` — [`Docs/settings/material-enums.md`](../../Docs/settings/material-enums.md) |
+ | Must an artist open the graph? | `#pragma material(Backend = Graph)` for a plain `UMaterial`; leave it out for the project default (ThinCustom) |
+ | Dense math, a matrix, a real loop? | a `/// @custom` function — its body is verbatim HLSL |
+ | Reuse an existing material function? | `/// @asset <path>` + an `extern` prototype |
+ | Something a material cannot do — draw objects again, read another pass's output, run compute? | a `.dsp` |
- Every parameter gets `Group`, `SortPriority` and `Description` metadata. That is the house style in
- `DShader/Materials/M_TZM_CardFoil_Holographic.dsm`, and it is what makes the generated material
- instance usable without reading the source.
+ Give every parameter `@group`, `@sort` and `@desc` — that is what makes the generated material instance usable
+ without reading the source — and `@slider min max` on scalars with a sensible range.
- **3 — Compile it.** This is the whole point of the skill:
+ **3 — Check it.** Fast, writes nothing, reports every diagnostic of the file at once:
```bash
- pwsh -File Plugins/DreamShader/.skill/dsc.ps1 compile DShader/Materials/M_Panel.dsm -Force -CleanNew
+ pwsh -File Plugins/DreamShader/.skill/dsc.ps1 check DShader/UI/M_ScanlinePanel.dss
```
- Run it from anywhere inside the project — the driver walks up for the `.uproject` and resolves the
- engine from its `EngineAssociation`. Exit `0` means the material generated; exit `1` means it did
- not, and the `LogDreamShader: Error:` line carries `file(line,col): message`.
+ Fix everything it reports, then check again. An unfamiliar code →
+ [`dream-shader-diagnose`](../dream-shader-diagnose/SKILL.md); every code has a page under
+ [`Docs/diagnostics/`](../../Docs/diagnostics/README.md).
- `-CleanNew` deletes the `.uasset` the commandlet wrote, provided git reports it untracked. Keep it
- on while iterating: the interactive editor generates the same material **in memory**, and a
- leftover file on disk shadows it. See [`dream-shader-verify`](../dream-shader-verify/SKILL.md) for
- the details.
+ **4 — Build it.** `check` stops before the shader compiler; `compile` builds the asset:
- **4 — Fix one error, recompile.** The compiler stops at the **first** failing `Graph` statement, so
- a file with three mistakes reports one. Iterate. Unfamiliar message →
- [`dream-shader-diagnose`](../dream-shader-diagnose/SKILL.md).
+ ```bash
+ pwsh -File Plugins/DreamShader/.skill/dsc.ps1 compile DShader/UI/M_ScanlinePanel.dss -Force -CleanNew
+ ```
- **5 — Report** the source path, the generated asset path, and every parameter with its default.
+ Exit `0` and a `Generated …` line mean it built. `-CleanNew` deletes the `.uasset` the run created — keep it on:
+ the editor generates the same material in memory, and a leftover file shadows that. For a file with a
+ `/// @custom` body, or a `.dsp` with HLSL passes, run `check -Shaders` as well — it is the only thing that
+ compiles that HLSL ([`dream-shader-verify`](../dream-shader-verify/SKILL.md)).
- ## Worked example
+ Batch: every run boots the editor (tens of seconds), and a run over many files costs about the same as one.
+ Write all the files first, then check them with `check -All`.
- A description of *"a UI scanline panel with a scrolling glow band and adjustable tint"* became this,
- which compiled on the first run:
+ **5 — Report** the source path, the asset path, every parameter with its default and range, and anything the
+ user should look at in the editor (a material's look cannot be checked headlessly).
- ```c
- Shader(Name="DreamShaderSkillProbe/M_SkillProbe")
- {
- Properties = {
- VectorParameter Tint = float4(0.25, 0.85, 1.0, 1.0) [
- Group="Scanline | Style"; SortPriority=10; Description="Base panel colour";
- ];
- ScalarParameter LineCount = 48.0 [
- Group="Scanline | Style"; SortPriority=20; Description="Scanlines across the panel height";
- ];
- ScalarParameter ScrollSpeed = 0.35 [
- Group="Scanline | Motion"; SortPriority=30; Description="Glow band travel speed";
- ];
- }
+ ## Worked example
- Settings = {
- Backend = "Graph";
- Domain = "UI";
- ShadingModel = "Unlit";
- BlendMode = "Translucent";
- }
+ *"A UI scanline panel with a scrolling glow band and an adjustable tint"*:
- Outputs = {
- float3 EmissiveColor;
- float Opacity;
+ ```hlsl
+ // DShader/UI/M_ScanlinePanel.dss -- scanlines and a glow band that scrolls down the panel
+ #pragma material(Domain = UI, BlendMode = Translucent, ShadingModel = Unlit)
- Base.EmissiveColor = EmissiveColor;
- Base.Opacity = Opacity;
- }
+ /// @group Scanline|Style @sort 10 @desc Base panel colour; alpha scales the opacity
+ uniform float4 Tint = float4(0.25, 0.85, 1.0, 1.0);
- Graph = {
- float2 uv = UE.TexCoord(Index=0);
- float t = UE.Time();
+ /// @group Scanline|Style @sort 20 @slider 8 128 @desc Scanlines across the panel height
+ uniform float LineCount = 48.0;
- float scanline = 0.5 + 0.5 * sin(uv.y * LineCount * 6.2831853);
- float band = frac(uv.y - t * ScrollSpeed);
- float glow = pow(saturate(1.0 - abs(band - 0.5) * 4.0), 3.0);
+ /// @group Scanline|Motion @sort 30 @slider 0 2 @desc Glow band travel speed, panels per second
+ uniform float ScrollSpeed = 0.35;
- float mask = saturate(scanline * 0.6 + glow);
+ float GlowBand(float V, float Phase)
+ {
+ float Band = frac(V - Phase);
+ return pow(saturate(1.0 - abs(Band - 0.5) * 4.0), 3.0);
+ }
- EmissiveColor = Tint.rgb * (0.4 + glow * 1.6);
- Opacity = mask * Tint.a;
- }
+ export void M_ScanlinePanel(inout material m)
+ {
+ float2 UV = UE.TexCoord(Index = 0);
+ float Scan = 0.5 + 0.5 * sin(UV.y * LineCount * 6.2831853);
+ float Glow = GlowBand(UV.y, UE.Time() * ScrollSpeed);
+ m.EmissiveColor = Tint.rgb * (0.4 + Glow * 1.6);
+ m.Opacity = saturate(Scan * 0.6 + Glow) * Tint.a;
}
```
```text
- LogDreamShader: Display: Generated /Game/DreamShaderSkillProbe/M_SkillProbe.M_SkillProbe from …/M_SkillProbe.dsm.
+ LogDreamShader: Display: Generated Material /Game/UI/M_ScanlinePanel.M_ScanlinePanel from …/DShader/UI/M_ScanlinePanel.dss.
+
+ Assets written to disk by this run:
+ Content/UI/M_ScanlinePanel.uasset [NEW]
+ deleted (-CleanNew)
+
dsc: OK (exit 0)
```
- ## Gotchas
+ A red variant is a `.dsi` beside it, overriding only what differs:
- - **The 29 math builtins are reserved and shadow user code silently.** A `Function`, property or
- `ShaderFunction` named `lerp`, `dot`, `pow`, `min`, `max`, `clamp`, `abs`, `step`, `length`,
- `cross`… is unreachable from a `Graph` block and there is **no diagnostic**. The declaration still
- compiles and still generates its asset; only the call site is redirected to the builtin.
- - **Inside a `Function` / `GraphFunction` body, `mix` `mod` `fract` `vec3` `mat4` and friends are
- rewritten as whole identifiers, case-insensitively.** A local named `Mix` silently becomes `lerp`.
- `Graph` blocks are not rewritten.
- - **No matrix types.** `mat3` parses in a `Function` signature — the normalizer rewrites it to
- `float3x3` before validation — and then fails at the first call site. A `Graph` block has no matrix
- value at all, because the Unreal material graph has none; matrix math belongs in a `Function` HLSL
- body.
- - **`reflect` and `refract` are builtins but not nodes.** They expand to a 4-node and a 14-node
- subgraph. Correct, but if the surrounding code is already HLSL, write them in a `Function` body
- and let the intrinsic do it in one node.
- - **Component counts are not checked for math builtins.** `dot(float3Value, floatValue)` passes
- DreamShader and fails later inside Unreal's shader compiler, with a message that does not name
- your source line.
- - **A `.dsh` is rejected for containing the *text* `Shader(`** — in a comment, in a string, anywhere.
- The kind check is a substring scan that runs before parsing. `Shader (` with a space passes.
- - **Only one `Shader` block per import closure**, not per file. Imports are inlined before parsing.
- - `Path(Game, "…")`, not `"/Game/…"`, for asset references in `Properties`.
+ ```hlsl
+ // DShader/UI/MI_ScanlinePanel_Red.dsi
+ #pragma instance(Parent = "M_ScanlinePanel")
- ## Troubleshooting
+ uniform float4 Tint = float4(1.0, 0.25, 0.2, 1.0);
+ ```
- | Message | Cause and fix |
- | :-- | :-- |
- | `Unknown Graph function 'saturte'.` | misspelled builtin, or a call to something the `Graph` dispatcher cannot see. Check the 19-name list |
- | `Math function 'lerp' expects exactly 3 argument(s).` | wrong arity — **or a named argument**. Both report as arity. Builtin arguments are positional only |
- | `Graph variable type 'Texture2D' requires an explicit initializer.` | texture / `SamplerState` / `Substrate` declarations in `Graph` need `= something` |
- | `Unsupported property type 'Scalar'.` | `Scalar`, `Color` and `Vector` were removed. Use `float`, `float4`, `float2..4` |
- | `Only one top-level Shader block is currently supported.` | a second `Shader` somewhere in the import closure |
- | `DreamShader header '…' may only declare …` | a `.dsh` whose text contains one of the six forbidden substrings |
- | `dsc: FAILED (exit 1)` with no `LogDreamShader` line | re-run the same command with `-Raw` to see the engine log |
+ ## Gotchas
+ - **Names are case-sensitive** (`DSH4200` / `DSH4208`, with a "did you mean"). HLSL spellings only — `mix`,
+ `fract`, `mod`, `vec3` are `DSH4250`.
+ - **A vector never narrows silently**: assigning a `float4` to a `float3` is `DSH4226` — write `.rgb`.
+ - **No matrices, unbounded loops, `discard` in a branch or `switch` in graph code** (`DSH4361`, `DSH4360`,
+ `DSH4362`, `DSH2160`). Those belong in a `/// @custom` body.
+ - **`UE.*` calls take named arguments** (`UE.LinearInterpolate(A = 0.0, B = Gain, Alpha = t)`); positional is
+ `DSH5220` except for a few (`UE.TexCoord`, `UE.Time`, …). Look the node up in [`Docs/builtins/ue.md`](../../Docs/builtins/ue.md) rather than guessing pin names.
+ - **A `/// @custom` body is not checked by `check`** — only `check -Shaders` compiles it.
+ - **One `export void … (inout material m)` per file**, and a material's functions in another file (`DSH6201`).
+ - **A texture uniform has no `= …`**: `/// @default /Game/T_X` above `uniform Texture2D T;` (`DSH7213`).
+ - **`@slider` is for scalars** — on a vector it is ignored with `DSH7233`.
+ - **A `.dsp` is UE 5.8+** and needs its pass materials written as `.dss` too; its traps are in
+ [`reference/dsp.md` § 6](../reference/dsp.md#6-traps).
+
## See also
- - [`dream-shader-verify`](../dream-shader-verify/SKILL.md) — the compile gate, and `-All`
- - [`dream-shader-optimize`](../dream-shader-optimize/SKILL.md) — cleaning up decompiler output
- - [`dream-shader-diagnose`](../dream-shader-diagnose/SKILL.md) — resolving a message
- - [`Docs/examples/index.md`](../../Docs/examples/index.md) — complete sources to copy
+ - [`dream-shader-verify`](../dream-shader-verify/SKILL.md) — `check`, `compile`, `check -Shaders`, `-All`
+ - [`dream-shader-diagnose`](../dream-shader-diagnose/SKILL.md) — resolving a code
+ - [`Docs/language-v2/index.md`](../../Docs/language-v2/index.md) — the 2.0 language in full
+ - [`Docs/examples/custom-pass.md`](../../Docs/examples/custom-pass.md) — complete pipelines with their materials