One method I often use during development is to design
the interface first, and implement it afterwards.
This works for me most of the time :)
When I first got the idea to add shaders to
css-doodle,
I started with what it might look like:
Later I realized there are two kinds of shaders, vertex shader and fragment shader.
They're usually separated in different <script> tags or JavaScript variables.
In order to put them into single @shader() together, I borrowed the idea of the CSS syntax,
that is, to group them with the syntax of CSS selectors.
This also extends well while adding textures.
Multiple textures can be identified by their prefixes.
If there's no fragment group I'll treat the whole as fragment shader,
which makes the code much simpler.
Code inside Custom Properties
The length of the shader code increases easily so it's a good idea to place it to somewhere else.
Using CSS Custom properties is an option.
Since css-doodle supports writing rules in ordinary CSS files,
the code can be breakdown into smaller parts and join them together with var().
Pitfalls
However, the values of custom property will be serialized by the CSS parser. All the numbers like 3.0
will be transformed to integer 3, which makes the shader code fails to compile.
A workaround is to write 3. instead of 3.0.
Implementation
The implementation is quite straightforward.
Parse code inside @shader() to read fragment/vertex shader and textures.
Transform textures into images before passing them to WebGL.
Handle shader compiling and linking.
Output the canvas as image data in the end.
Examples
So there's a basic example, fill the color of each pixel based on its coordinates.
Although there's no animation yet, I'm already excited about it.
See also the above demo on CodePen.
Next step
I'll try to add animation by introducing the uniform u_time,
but then the whole thing can't be put into background anymore.
I really wish the element() function
can be supported more widely soon.