RomanticShaderWidget
Flutter package for rendering GLSL fragment shaders and a built-in Dart CLI for converting Shadertoy-style GLSL into Flutter-compatible fragment shaders.
More packages by Romantic Developer
Highlights
- Render runtime shaders with RomanticShaderWidget.
- Parse compiled shader uniform metadata into ShaderUniformBindings.
- Build and update float and sampler uniforms with ShaderUniformsBuilder.
- Convert source GLSL files into Flutter runtime_effect shader files.
- Generate optional JSON uniform property files for editor-style controls.
Showcase Shader Set
The example app intentionally ships with a compact 3-shader showcase set:
2d_cloudfractal_thingliquid_glass
This keeps the package lightweight for publishing while still demonstrating procedural and texture-based shader workflows.
API Map
- Widget rendering: RomanticShaderWidget, RomanticShaderPainter
- Uniform domain: ShaderUniforms, ShaderUniformBindings, UniformValue
- Uniform builder: ShaderUniformsBuilder and extension image helpers
- Utility APIs: parseShaderUniforms, readShaderUniformsFromAsset, ShaderConverter
- CLI APIs: runShaderConverterCli and shader_converter executable
Package Setup
Add the package to your app and include shader assets in pubspec.
Example pubspec asset section:
flutter:
shaders:
- assets/generated_shaders/2d_cloud.frag
RomanticShaderWidget Quick Start
import 'package:flutter/material.dart';
import 'package:romantic_shader_widget/romantic_shader_widget.dart';
class ShaderScreen extends StatefulWidget {
const ShaderScreen({super.key});
@override
State<ShaderScreen> createState() => _ShaderScreenState();
}
class _ShaderScreenState extends State<ShaderScreen> {
ShaderUniformBindings _bindings = const ShaderUniformBindings();
@override
void initState() {
super.initState();
_loadBindings();
}
Future<void> _loadBindings() async {
final bindings =
await readShaderUniformsFromAsset('assets/generated_shaders/2d_cloud.json');
if (!mounted) return;
setState(() {
_bindings = bindings;
});
}
@override
Widget build(BuildContext context) {
final uniforms = ShaderUniformsBuilder()
.setTime(1.2)
.setResolution(1080, 1920)
.setMouse(0, 0)
.setViewportScale(1.0)
.addFloat('intensity', 0.8)
.build();
return RomanticShaderWidget(
shaderAssetPath: 'assets/generated_shaders/2d_cloud.frag',
uniformBindings: _bindings,
uniforms: uniforms,
fallbackColor: Colors.black,
);
}
}
GLSL Converter CLI
Use the package executable named shader_converter.
Local package run
Run from this repository root:
dart run bin/shader_converter.dart \
--input <file-or-dir> \
--output-dir <dir> \
[--properties-dir <dir>] \
[--map <sourceA:targetA,sourceB:targetB>] \
[--overwrite] \
[--dry-run] \
[--no-mobile-compat]
Global activation
dart pub global activate --source path .
shader_converter --help
If your shell PATH does not include the Pub cache bin directory, use:
dart pub global run romantic_shader_widget:shader_converter --help
Converter example
dart run bin/shader_converter.dart \
--input original_shaders \
--output-dir build/generated_shaders \
--properties-dir build/generated_properties \
--dry-run
Flutter compatibility guarantees
The converter enforces these runtime shader requirements:
- Injects #include <flutter/runtime_effect.glsl>
- Injects precision highp float;
- Ensures out vec4 fragColor;
- Converts gl_FragCoord to FlutterFragCoord-based coordinates
- Converts gl_FragColor to fragColor
- Adds a main wrapper for mainImage shaders
- Adds standard float uniforms when missing: iTime, iResolutionX, iResolutionY, iMouseX, iMouseY, viewportScale
- Returns non-zero exit code on conversion failures
Exit codes
- 0: success
- 1: one or more files failed conversion
- 2: input path missing or no GLSL files discovered
- 64: argument or usage error
Supported Features
Runtime widget and API support
- Flutter runtime fragment shader rendering via RomanticShaderWidget and RomanticShaderPainter.
- Shader loading from assets compiled under
flutter.shaders. - Uniform binding parsing from:
- Flutter compiled shader metadata (
sksl.uniforms). - Plain GLSL
uniformdeclarations.
- Flutter compiled shader metadata (
- Uniform types currently supported by package runtime bindings:
floatsampler2D- Flutter metadata alias
shader(treated as sampler)
- Fluent uniform updates with ShaderUniformsBuilder:
- Built-ins:
iTime,iResolutionX,iResolutionY,iMouseX,iMouseY,viewportScale,cameraOffsetX,cameraOffsetY - Custom floats and textures (
addFloat,addTexture,addTextures)
- Built-ins:
Converter input/output support
- Input sources:
- Single
.glslfile - Directory of
.glslfiles (recursive)
- Single
- Output:
- Flutter
.fragruntime effect shader files - Optional JSON properties file per shader
- Flutter
- CLI options:
- Required:
--input,--output-dir - Optional:
--properties-dir,--map,--overwrite,--dry-run,--no-mobile-compat,--help
- Required:
GLSL syntax and automatic rewrites supported by converter
- Header/runtime normalization:
- Removes
#versiondirectives. - Ensures
#include <flutter/runtime_effect.glsl>. - Ensures
precision highp float;. - Ensures
out vec4 fragColor;.
- Removes
- Entry point adaptation:
- Keeps
main()if present. - Wraps
mainImage(out vec4, in vec2)into generatedmain()whenmain()is missing.
- Keeps
- Built-in symbol rewrite:
gl_FragColor->fragColorgl_FragCoord-> Flutter coordinate helperiResolution->iResolutionX/iResolutionYfallback vectorsiMouse->iMouseX/iMouseYfallback vectorsiDate-> float-only fallback vectoriFrame->int(iTime * 60.0)fallbackiTimeDelta,iFrameRate,iSampleRate,iChannelTime[n]-> compile-safe fallbacks
- Uniform normalization:
- Converts
const float name = ...;intouniform float name;and uses parsed const as default property value where possible. - Auto-injects missing standard float uniforms (
iTime,iResolutionX,iResolutionY,iMouseX,iMouseY,viewportScale). - Expands
uniform samplerXX iChannel0..3;into explicit sampler declarations.
- Converts
- Compatibility rewrites for common runtime/parser issues:
- Rewrites
tanh(...), some derivative usage (dFdx,dFdy) to compatibility fallbacks. - Rewrites some float-indexed loop forms to int-indexed loops.
- Rewrites/normalizes some compact matrix constructor forms.
- Normalizes texture sampling variants toward
texture(sampler, coord).
- Rewrites
Unsupported or Limited Features
Shader model and pipeline limits
- Fragment shader workflows only. Vertex/geometry/compute shader workflows are out of scope.
- Multi-pass Shadertoy pipeline conversion is not implemented.
varying-based legacy pipeline patterns are treated as incompatible.
GLSL syntax/function limits
- Unsupported by Flutter runtime effects and treated as conversion errors:
textureLod(...)texelFetch(...)- Non-simple
texture(...)usage with extra unsupported arguments
- Function parameters of type
sampler2Dare not generally portable; converter attempts rewrite only for simple, safe cases. - Vector uniform arrays are not preserved as true runtime arrays; converter rewrites references to fallback vectors.
- Int/advanced uniform models are not first-class in package runtime binding APIs (current runtime data model is float + sampler2D).
Platform and backend caveats
- Shaders must be declared under
flutter.shadersinpubspec.yaml; loading raw source text directly is not the intended runtime path. - On Flutter Web, sampler behavior can vary by shader/backend; some sampler bindings may fail at runtime for specific shaders.
- Precision and parser behavior can differ by platform/backend; test converted shaders on all target platforms.
JSON Property File Format
Generated JSON files contain:
- Float uniforms with
{ defaultValue, min, max } - Samplers with
{ type: "sampler2D" }
Example:
{
"exposure": {
"defaultValue": 1.0,
"min": 0.0,
"max": 4.0
},
"iChannel0": {
"type": "sampler2D"
}
}
Operational Notes for Developers
--dry-runvalidates and reports conversion issues without writing files.--overwriteis required to replace existing output files.--map source:targetremaps output basenames (repeatable or comma-separated).--no-mobile-compatdisables mobile precision fallback wrapping forhighp.- Recommended CI gate after converter/runtime API changes:
flutter analyzeflutter test
Libraries
- cli/shader_converter_cli
- domain/index
- Domain models for shader uniforms, bindings, and editable values.
- domain/shader_uniforms
- domain/uniform_value
- romantic_shader_widget
- Flutter package for rendering custom fragment shaders and managing uniforms.
- utils/image_utils
- utils/index
- Utility APIs for shader parsing, conversion, and asset/network loading.
- utils/json_utils
- utils/shader_converter
- utils/shader_utils
- widgets/index
- Widget layer for rendering shaders and building runtime uniform payloads.
- widgets/romantic_shader_painter
- widgets/romantic_shader_widget
- widgets/shader_uniforms_builder
- widgets/shader_uniforms_builder_extension