{
    "effectName": "Shader",
    "properties": [
        {
            "id": "Shader_FilenameBlock",
            "label": "",
            "type": "string",
            "controlType": "custom",
            "default": "",
            "fullWidth": true,
            "description": "Custom block with Select/Clear/Download buttons, animated shader preview, and filename label. The shader file path is serialized as E_0FILEPICKERCTRL_IFS via a hidden file picker; the leading 0 forces it to be processed first at load time so the shader config is known before dynamic uniform settings are applied."
        },
        {
            "id": "Shader_LeadIn",
            "label": "Lead in frames",
            "type": "int",
            "controlType": "slider",
            "settingPrefix": "TEXTCTRL",
            "default": 0,
            "min": 0,
            "max": 1000,
            "description": "Number of frames to pre-render before the effect starts, allowing time-based shaders to reach a desired visual state at the beginning of the effect."
        },
        {
            "id": "Shader_SpeedRow",
            "label": "",
            "type": "string",
            "controlType": "custom",
            "default": "",
            "fullWidth": true,
            "description": "Custom Time Speed slider row. Built as a BulkEditSliderF2 with the slider as the serialized control (E_SLIDER_Shader_Speed, divisor 100) and a buddy text control, matching the legacy naming so old sequences continue to deserialize."
        },
        {
            "id": "Shader_Offset_X",
            "label": "Offset X",
            "type": "int",
            "controlType": "slider",
            "settingPrefix": "TEXTCTRL",
            "default": 0,
            "min": -100,
            "max": 100,
            "valueCurve": true,
            "description": "Horizontal offset of the shader viewport as a percentage. Only active for shaders that consume iResolution / coordinate uniforms."
        },
        {
            "id": "Shader_Offset_Y",
            "label": "Offset Y",
            "type": "int",
            "controlType": "slider",
            "settingPrefix": "TEXTCTRL",
            "default": 0,
            "min": -100,
            "max": 100,
            "valueCurve": true,
            "description": "Vertical offset of the shader viewport as a percentage. Only active for shaders that consume iResolution / coordinate uniforms."
        },
        {
            "id": "Shader_Zoom",
            "label": "Zoom",
            "type": "int",
            "controlType": "slider",
            "settingPrefix": "TEXTCTRL",
            "default": 0,
            "min": -100,
            "max": 100,
            "valueCurve": true,
            "description": "Zoom level for the shader output. Positive values zoom in, negative values zoom out, and zero shows the shader at its native scale. Only active for shaders that consume iResolution / coordinate uniforms."
        },
        {
            "id": "Shader_DynamicParams",
            "label": "",
            "type": "string",
            "controlType": "custom",
            "default": "",
            "fullWidth": true,
            "description": "Container for per-shader dynamic uniform controls. ShaderPanel reserves the sizer here; ShaderConfig::GetDynamicPropertiesJson emits a schema-shaped JSON array for every visible uniform, and the JsonEffectPanel builder renders the rows so iPad and desktop share the same layout logic. The sizer is wiped (and its PropertyInfo entries purged via RemovePropertiesWithPrefix) whenever the shader file changes."
        }
    ]
}
