Update / Bug Fixes:
- Fixed an issue with the .var package naming.
- Fixed a bug that caused garbled text to appear when loading textures multiple times.
Fixed a bug with the 'Clear Texture' button.
The features of Custom Shader Loader are now fully aligned with CustomShaderLoaderAlt. For more details, please refer to: https://hub.virtamate.com/resources/customshaderloaderalt.65067/
CustomShaderLoader has achieved full feature and UI parity with CustomShaderLoaderAlt. Some bug fixed.
CSL_SP_ALT — v2 Release Notes
Audience: This document is intended for creators already using v1, covering new features and behavioral changes in v2.I. Tab-Based Property Panel Layout
Background
In v1, all Shader properties are stacked in a single linear column, making the panel difficult to navigate when there are many properties. v2 integrates the CustomUILib Tab UI framework (by 14mhz), allowing properties to be grouped by function into separate tabs.
New JSON Layout Control Types
The following type values are reserved for panel layout control and do not correspond to any actual Shader parameter:
"tab" field reference:
Type Purpose "tab" Creates a new tab; all subsequent properties belong to this tab until the next "tab" "column" Toggles the current column (left ↔ right), enabling a two-column side-by-side layout "label" Inserts a text label in the current column for property group annotation
{ "type": "tab", "displayName": "Basic", "tabWidth": 160 }
"label" field reference:
- displayName: The name shown on the Tab button
- tabWidth: Tab button width in pixels; omit to use the default
JSON:{ "type": "label", "displayName": "— Color Settings —", "height": 50, "fontSize": 28, "defaultColor": "#333333", "textColor": "#FFFFFF" }
All Property Types Support Tabs
color, float, range, texture, vector, vector4, toggle, and position can all be placed inside a Tab and are automatically arranged into the left or right column based on the current column state. The first Tab is selected automatically after initialization.
Full Layout Example
JSON:[ { "type": "tab", "displayName": "Base Textures" }, { "type": "texture", "name": "_MainTex", "displayName": "Albedo" }, { "type": "column" }, { "type": "texture", "name": "_BumpMap", "displayName": "Normal Map", "wrapMode": "Repeat" }, { "type": "tab", "displayName": "Detail" }, { "type": "label", "displayName": "— Color —" }, { "type": "color", "name": "_Color", "displayName": "Main Color" }, { "type": "column" }, { "type": "float", "name": "_Glossiness", "displayName": "Smoothness", "defaultValue": 0.5, "minValue": 0, "maxValue": 1 } ]
Backward compatibility: If no "tab" entries are present in the JSON, the panel behaves exactly as in v1 — no changes to existing configurations are required.II. New Property Types and Fields
2.1 "vector4" — Four-Component Vector
v1 only supported "vector" (Vector3, generating X/Y/Z sliders). v2 adds the "vector4" type, generating four sliders for X/Y/Z/W. This is commonly used for UV transform parameters (e.g. _MainTex_ST) or any Shader parameter that requires a fourth component.
Any slider change writes the complete Vector4 to the Shader in real time. Values are saved and restored with the scene.
JSON:{ "name": "_MainTex_ST", "displayName": "Main Tex Tiling/Offset", "type": "vector4", "defaultVector4": { "x": 1, "y": 1, "z": 0, "w": 0 }, "minVector4": { "x": 0, "y": 0, "z": -2, "w": -2 }, "maxVector4": { "x": 4, "y": 4, "z": 2, "w": 2 } }
2.2 "toggle" — New keyword Field for Shader Variant Switching
In v1, toggle only wrote a boolean as a float value (1.0/0.0) to the Shader. v2 adds an optional keyword field: checking the toggle calls Material.EnableKeyword; unchecking calls DisableKeyword. This directly drives #pragma multi_compile / #pragma shader_feature variant switching.
JSON:{ "name": "_DETAIL_ON", "displayName": "Enable Detail Layer", "type": "toggle", "defaultValueBool": false, "keyword": "_DETAIL_ON" }
keyword is optional. When omitted, behavior is identical to v1 — the Shader receives 0.0 or 1.0 as a float.2.3 "texture" — New wrapMode Field for Texture Tiling
Background
In v1, all textures were loaded with TextureWrapMode.Clamp hardcoded, meaning UV coordinates were clamped to [0, 1] and edges were stretched. Normal maps, detail textures, and other seamless textures that rely on tiling would show visible seams and could not function correctly.
Improvements in v2
- Default WrapMode changed to Repeat — seamless textures work out of the box with no extra configuration
- Each texture property can independently specify its wrap mode in JSON; the mode is applied automatically at load time
wrapMode value Sampling behavior Typical use case "Repeat" UV coordinates outside [0,1] wrap cyclically Seamless normal maps, detail textures, fabric patterns (v2 default) "Mirror" UV coordinates mirror and repeat past boundaries Symmetrically continuous textures "Clamp" UV coordinates clamped to [0,1]; edge pixels stretched Decals, unique-pattern textures (v1 legacy behavior) JSON:{ "name": "_NormalMap", "type": "texture", "displayName": "Normal Map", "wrapMode": "Repeat" }, { "name": "_DetailTex", "type": "texture", "displayName": "Detail Albedo", "wrapMode": "Mirror" }, { "name": "_DecalTex", "type": "texture", "displayName": "Decal Pattern", "wrapMode": "Clamp" }
Upgrade note: The default WrapMode has changed from Clamp to Repeat. If existing JSON contains decal-type textures without a wrapMode field, add "wrapMode": "Clamp" explicitly after upgrading to preserve the original behavior.III. Other Improvements
Material Slot Count Expanded (10 → 50)
The number of material slots initialized in Init() has been increased from 10 to 50, fully covering large CUA assets and clothing items with many materials. No more missing material slots on complex assets.
ClothSimProxy — Person Atom Mode
ClothSimProxy now supports being added directly to a Person atom:
- When attached to a Person, the UI displays a "Primary Clothing" dropdown
- The simProxyChooser candidate list automatically excludes the currently selected primary clothing, preventing a garment from proxying itself
- A new Awake() method hides the plugin#2 duplicate (within the CSL_SP_ALT combined package) at the earliest possible stage of initialization, keeping the UI clean
ClothSimProxy — Defensive Null Checks
Null checks have been added to SaveWrap, LoadWrap, and ApplySimProxy to prevent null-reference crashes that could occur when dazDynamic or clothingItem is not yet ready under certain load orders.
Appendix: Complete JSON Property Field Reference
The Shader property configuration file is a JSON array where each element is a property object. All supported type values and their fields are listed below.
Layout Control Types (No Shader Parameter)
"tab" — Tab Page
JSON:{ "type": "tab", "displayName": "Basic", "tabWidth": 160 }
Field Type Required Description displayName string Yes Name shown on the Tab button tabWidth int No Tab button width in pixels; omit to use the default "column" — Toggle Column
{ "type": "column" }
No additional fields. Each occurrence toggles the current column between left and right.
"label" — Group Text Label
JSON:{ "type": "label", "displayName": "— Color & Gloss —", "height": 50, "fontSize": 28, "defaultColor": "#2a2a2a", "textColor": "#e0e0e0" }
Field Type Required Default Description displayName string Yes — Label text content height float No 50 Label height in pixels fontSize int No 30 Font size defaultColor color No #404040 Background color textColor color No auto Text color; auto-selects black or white based on background luminance if omitted Shader Parameter Types
Color format: All color fields accept the following formats:
- Hex: "#RRGGBB", "#RRGGBBAA" (with or without #)
- Named colors: "white", "black", "red", "green", "blue", "yellow", "cyan", "magenta", "gray", "clear"
"color" — Color Picker
JSON:{ "type": "color", "name": "_Color", "displayName": "Main Color", "defaultColor": "#FFFFFF" }
Field Type Required Description name string Yes Shader property name displayName string Yes Label shown in the panel defaultColor color Yes Initial color value "float" / "range" — Float Slider
JSON:{ "type": "float", "name": "_Glossiness", "displayName": "Smoothness", "defaultValue": 0.5, "minValue": 0.0, "maxValue": 1.0 }
Field Type Required Description name string Yes Shader property name displayName string Yes Label shown in the panel defaultValue float Yes Slider default value minValue float Yes Slider minimum value maxValue float Yes Slider maximum value "float" and "range" are interchangeable — they behave identically."texture" — Texture Picker
JSON:{ "type": "texture", "name": "_MainTex", "displayName": "Albedo Map", "defaultUrl": "", "wrapMode": "Repeat" }
Field Type Required Default Description name string Yes — Shader property name displayName string Yes — Label shown in the panel defaultUrl string No "" Default texture file path wrapMode string No "Repeat" Tiling mode: "Repeat" / "Mirror" / "Clamp" "vector" — Three-Component Vector (XYZ)
Generates three independent sliders for X, Y, and Z. Any component change writes a complete Vector3 to the Shader.
JSON:{ "type": "vector", "name": "_WindDirection", "displayName": "Wind Direction", "defaultVector": { "x": 0.0, "y": 1.0, "z": 0.0 }, "minVector": { "x": -1.0, "y": -1.0, "z": -1.0 }, "maxVector": { "x": 1.0, "y": 1.0, "z": 1.0 } }
Field Type Required Description name string Yes Shader property name displayName string Yes Label shown in the panel (X/Y/Z suffix appended automatically) defaultVector {x,y,z} Yes Default values for the three sliders minVector {x,y,z} Yes Minimum values for the three sliders maxVector {x,y,z} Yes Maximum values for the three sliders "vector4" — Four-Component Vector (XYZW)
Generates four independent sliders for X, Y, Z, and W. Any component change writes a complete Vector4 to the Shader. Commonly used for texture Tiling/Offset (_ST suffix parameters).New in v2
JSON:{ "type": "vector4", "name": "_MainTex_ST", "displayName": "Main Tex Tiling/Offset", "defaultVector4": { "x": 1.0, "y": 1.0, "z": 0.0, "w": 0.0 }, "minVector4": { "x": 0.1, "y": 0.1, "z": -2.0, "w": -2.0 }, "maxVector4": { "x": 8.0, "y": 8.0, "z": 2.0, "w": 2.0 } }
Field Type Required Description name string Yes Shader property name displayName string Yes Label shown in the panel (X/Y/Z/W suffix appended automatically) defaultVector4 {x,y,z,w} Yes Default values for the four sliders minVector4 {x,y,z,w} Yes Minimum values for the four sliders maxVector4 {x,y,z,w} Yes Maximum values for the four sliders "toggle" — Toggle Switch
JSON:{ "type": "toggle", "name": "_UseEmission", "displayName": "Enable Emission", "defaultValueBool": false, "keyword": "_EMISSION" }
Field Type Required Description name string Yes Shader property name (float: 1.0 / 0.0) displayName string Yes Label shown in the panel defaultValueBool bool Yes Default checked state keyword string No Shader Keyword to bind; when set, toggling calls EnableKeyword / DisableKeyword Full Example
A complete property configuration for a typical clothing Shader, demonstrating Tab pagination, two-column layout, and a practical combination of property types:
JSON:[ { "type": "tab", "displayName": "Textures", "tabWidth": 150 }, { "type": "label", "displayName": "— Main Textures —", "defaultColor": "#1e1e2e", "textColor": "#cdd6f4" }, { "type": "texture", "name": "_MainTex", "displayName": "Albedo", "wrapMode": "Repeat" }, { "type": "texture", "name": "_BumpMap", "displayName": "Normal Map", "wrapMode": "Repeat" }, { "type": "column" }, { "type": "label", "displayName": "— Detail Layer —", "defaultColor": "#1e1e2e", "textColor": "#cdd6f4" }, { "type": "texture", "name": "_DetailAlbedoMap", "displayName": "Detail Albedo", "wrapMode": "Repeat" }, { "type": "texture", "name": "_DecalTex", "displayName": "Decal Pattern", "wrapMode": "Clamp" }, { "type": "tab", "displayName": "Material", "tabWidth": 150 }, { "type": "color", "name": "_Color", "displayName": "Main Color", "defaultColor": "#FFFFFF" }, { "type": "float", "name": "_Glossiness", "displayName": "Smoothness", "defaultValue": 0.5, "minValue": 0.0, "maxValue": 1.0 }, { "type": "float", "name": "_Metallic", "displayName": "Metallic", "defaultValue": 0.0, "minValue": 0.0, "maxValue": 1.0 }, { "type": "column" }, { "type": "color", "name": "_EmissionColor", "displayName": "Emission Color", "defaultColor": "#000000" }, { "type": "toggle", "name": "_UseEmission", "displayName": "Enable Emission", "defaultValueBool": false, "keyword": "_EMISSION" }, { "type": "float", "name": "_EmissionIntensity", "displayName": "Emission Intensity", "defaultValue": 0.0, "minValue": 0.0, "maxValue": 5.0 }, { "type": "tab", "displayName": "UV", "tabWidth": 150 }, { "type": "vector4", "name": "_MainTex_ST", "displayName": "Main Tex Tiling/Offset", "defaultVector4": { "x": 1, "y": 1, "z": 0, "w": 0 }, "minVector4": { "x": 0.1, "y": 0.1, "z": -2, "w": -2 }, "maxVector4": { "x": 8, "y": 8, "z": 2, "w": 2 } }, { "type": "vector4", "name": "_DetailTex_ST", "displayName": "Detail Tex Tiling/Offset", "defaultVector4": { "x": 2, "y": 2, "z": 0, "w": 0 }, "minVector4": { "x": 0.1, "y": 0.1, "z": -2, "w": -2 }, "maxVector4": { "x": 16, "y": 16, "z": 2, "w": 2 } } ]