When applying effects to text on the web, designers have traditionally been constrained to those provided by CSS
. In the majority of cases this is entirely suitable – text is text right? Yet still, there exist numerous examples of designers combining CSS
properties or gifs and images to create effects that evoke something more playful. Precisely here, Blotter exists to provide an alternative.
Blotter provides a simple interface for building and manipulating text effects that utilize GLSL
shaders without requiring that the designer write GLSL
. Blotter has a growing library of configurable effects while also providing ways for student or experienced GLSL
programmers to quickly bootstrap new ones.
Blotter renders all texts in a single WebGL context and limits the number of draw calls it makes by using atlases. When multiple texts share the same effect they are mapped into a single texture and rendered together. The resulting image data is then output to individual 2d
contexts for each element.
Rather than executing on a time based interval, Blotter's internal animation loop uses requestAnimationFrame
to match the browser's display refresh rate and pause when the user navigates to other browser tabs; improving performance and preserving the battery life on the user's device.
Any texts you pass to Blotter can be individually configured using familiar style properties. You can use custom font faces through the @font-face
spec. However, Blotter ultimately renders the texts passed to it into canvas
elements. This means rendered text won't be selectable. Blotter is great for elements like titles, headings, and texts used for graphic purposes. It's not recommended that Blotter be used for lengthy bodies of text.
To get started, download Blotter and include it in the head of the HTML document like so: <script src="./path/to/blotter.js"></script>
. Once you've done this, visit the page in your browser, open the console, and type “Blotter”. If a function is returned, you're ready to begin.
Before adding any effects, you should learn how to replace text in your document with plain text rendered1 by Blotter. Instances of Blotter take at least one Text object and a single Material object, which is the source of any Blotter effect you wish to apply to your texts.
In the following example, we create a single Text object, apply the basic Blotter.Material
material (which simply draws the Text as described by its properties) and add the rendered canvas
to an element on the page.
Blotter is a tool designed to allow anyone, regardless of their knowledge of GLSL
itself, to use the power of GLSL
fragment shaders2 to create and apply real-time visual effects to texts on the web. To this end, Blotter provides a growing collection of ready-to-use and configurable materials.
The configurability of provided materials will depend on the material itself, but the basic interface will typically center around the manipulation of “uniforms”. Think of uniforms as values that describe how effects are rendered. For example, a material that bends and distorts your text as if viewed on the bottom of a pool might have a uniform called uSpeed
to help you control the speed at which the distortion occurs when animated.
Below, we will use Blotter's ready-made LiquidDistortMaterial
to illustrate how to use Blotter materials by controlling uniforms.
Blotter Materials describe how your texts will be rendered and provide the interface through which you can introduce variety in the characteristics of any effect.
Listed below are Blotter's current set of ready-to-use materials. For information on creating custom materials for private use, or for contributing new materials to Blotter to be listed here, see the documentation.
Class for creating a rolling distortion effect using Blotter.js. It inherits from Blotter.Material
, and therefore has the same properties and functions as Blotter.Material
.
construction
var material = new Blotter.RollDistortMaterial();
uniforms
material.uniforms
An object that holds the uniforms that describe how the material's effects should be rendered.
uTime
material.uniforms.uTime
Represents how much time has elapsed since the last frame in milliseconds.
value
material.uniforms.uTime.value
A floating point number representing how much time has elapsed since the last frame in milliseconds. Default value is 0.0.
type
material.uniforms.uTime.type
The uniform type of the value being passed to the shader. This value is a static "1f".
uDistortion
material.uniforms.uDistortion
Represents the predominant distortion to apply to texts.
value
material.uniforms.uDistortion.value
A floating point number representing the predominant distortion to apply to texts. Default value is 0.0.
type
material.uniforms.uDistortion.type
The uniform type of the value being passed to the shader. This value is a static "1f".
What follows are the main classes an average developer will encounter when working with Blotter. Many classes and utilities are left out of this documentation, as they are more internal to the codebase rather than part of the interface one would need to use Blotter as it comes. If you would like to see Blotter laid bare, please view the source.
Blotter
is the window level interface for interacting with all Blotter classes and properties. Whenever you want to apply a new Blotter material to texts on your page, you will instantiate a new object of the Blotter
class.
construction
var blotter = new Blotter(material[, options]);
Create a new instance of Blotter
where material
is an instance of any Blotter.Material
and options
is an optional JavaScript object with any of the following optional parameters.
texts
options.texts
An array of Blotter.Text
objects, or optionally a single Blotter.Text
object. Any texts given to an instance of Blotter
will be drawn according to the instance's material.
ratio
options.ratio
The backing store size in relation to the canvas element, or otherwise known as the devicePixelRatio
. This property essentially tells Blotter what pixel ratio to draw texts for in relation to the screen, and will effect the clarity of rendered texts on retina devices. Blotter determines this property by default to ensure the most appropriate pixel ratio for your user's device, so it's unlikely you'll need to set this yourself.
autobuild
options.autobuild
Tells the instance of Blotter
whether or not to immediately build and configure itself using the supplied Blotter.Material
instance and optional parameters such as supplied Blotter.Text
objects. By default, Blotter will assume this to be true
. If for some reason you intend to add additonal texts or change the material prior to use, it would be a good idea to set this to false
and later set the value of needsUpdate
to true
in order to trigger a fresh build.
autostart
options.autostart
Tells the instance of Blotter
whether or not to immediately begin rendering and updating universal uniforms. By default, Blotter will assume this to be true
.
autoplay
options.autoplay
Tells the instance of Blotter
whether or not to immediately begin the render loops for all Blotter.RenderScope
objects created for each of its texts. By default, Blotter will assume this to be true
.
Each draw will happen on requestAnimationFrame
.
Listen for the ready
event to perform work after the instance has finished building itself.
needsUpdate
blotter.needsUpdate = true
Occasionally you may need to perform actions on your instances of Blotter
that require it to repeat important preparatory steps necessary for rendering the instance's texts. To do so, simply set the value of blotter.needsUpdate
to true
and the instance will take care of the rest. You can listen for the instance's update
event if you need to do any work after the update has completed.
material
blotter.material
A reference to the Blotter.Material
instance being used to render your texts. Setting this property after your Blotter
object's initialization requires that your Blotter
instance be rebuilt by setting the value of its needsUpdate
property to true
.
texts
blotter.texts
A reference to the Blotter.Text
objects being rendered by your instance of Blotter
. Setting this property after your Blotter
object's initialization requires that your Blotter
instance be rebuilt by setting the value of its needsUpdate
property to true
.
start
blotter.start()
Tells the instance of Blotter
to begin rendering and updating universal uniforms.
At the time of each draw on requestAnimationFrame
the instance will emit a render
event.
stop
blotter.stop()
Tells the instance of Blotter
to stop rendering and updating universal uniforms.
setMaterial
blotter.setMaterial(material)
Sets the Blotter.Material
instance being used to render your texts. In order for this change to go into effect you'll have to rebuild your Blotter
instance by setting the value of its needsUpdate
property to true
.
addText
blotter.addText(text)
Alias method for blotter.addTexts(text)
, see below.
addTexts
blotter.addTexts(texts)
Adds one or more Blotter.Text
objects to be rendered by your instance of Blotter
. In order for this change to go into effect you'll have to rebuild your Blotter
instance by setting the value of its needsUpdate
property to true
.
removeText
blotter.removeText(text)
Alias method for blotter.removeTexts(text)
, see below.
removeTexts
blotter.removeTexts(texts)
Removes one or more Blotter.Text
objects from being rendered by your instance of Blotter
. In order for this change to go into effect you'll have to rebuild your Blotter
instance by setting the value of its needsUpdate
property to true
.
forText
blotter.forText(text)
Returns an instance of Blotter.RenderScope
for the given Blotter.Text
object.
boundsForText
blotter.boundsForText(text)
Returns a JavaScript object containing the width (w
), height (h
), x-offset (x
), and y-offset (y
) of the given Blotter.Text
object in the backbuffer the Blotter
instance uses to render the material's effect collectively for all texts in the instance. These values, especially the x-offset and y-offset, will likely be of little use to you.
Blotter Materials describe how your texts will be rendered and provide the interface through which you can control uniforms
to introduce variety in the characteristics of any effect.
As the Blotter.Material
class is the abstract base class for all Blotter Materials, using this class will simply render your texts according to their font and style properties. See the documentation for specific Materials for further details on their individual usages.
construction
var material = new Blotter.Material();
Create a new instance of Blotter.Material
.
needsUpdate
material.needsUpdate = true
Rarely, you may need to perform actions on your instances of Blotter.Material
that require it to tell the instance of Blotter
to repeat important preparatory steps necessary for rendering the instance's texts. To do so, set the value of material.needsUpdate
to true
and the instance will take care of the rest. You can listen for the Blotter
instance's update
event if you need to do any work after the update has completed.
mainImage
material.mainImage
For every Blotter Material, there is an underlying GLSL
fragment shader that describes how the individual Material's effect will be rendered. The material.mainImage
property returns the shader's GLSL
in string form. Setting this property after your Blotter.Material
object's initialization requires that your Blotter.Material
instance be rebuilt by setting the value of its needsUpdate
property to true
.
uniforms
material.uniforms
The fundamental interface for all effects in Blotter. Every Material will provide its own array of uniform objects, each having a type
and a value
. To manipulate any effect, simply set the value
of the uniform you wish to change.
Listed below are the four uniform types available in Blotter.
"1f"
For "1f" type uniforms, values should be set using floating point values.
material.uniforms.myUniform1.value = 0.5;
.
"2f"
For "2f" type uniforms, values should be set using an array of two floating point values.
material.uniforms.myUniform2.value = [0.5, 0.5];
.
"3f"
For "3f" type uniforms, values should be set using an array of three floating point values.
material.uniforms.myUniform3.value = [0.5, 0.5, 0.5];
.
"4f"
For "4f" type uniforms, values should be set using an array of four floating point values.
material.uniforms.myUniform4.value = [0.5, 0.5, 0.5, 0.5];
.
As stated, every Blotter Material will provide its own uniforms unique to the characteristics of its own effect. However, there are a handful of uniforms on which all Blotter Materials rely. These are listed below.
uResolution
The resolution of an individual text within the mapping material being rendered by your material. Type "2f". You should never set the value of this uniform yourself.
uGlobalTime
The global time in seconds. Type "1f". You should never set the value of this uniform yourself.
uTimeDelta
The render time in seconds. Type "1f". You should never set the value of this uniform yourself.
uBlendColor
The base color against which all blending should occur within an effect. Type "4f". The default value for this uniform is white, or [1.0, 1.0, 1.0, 1.0]
, where each index in the array represent an R,G,B, and A value respectively in a 0.0 to 1.0 range.
This uniform is important for effects that sample the area around your texts for blending purposes, such as for the RGB splitting that occurs in the ChannelSplitMaterial, and you should set it to match the RGBA color that will be the background for any of your texts.
uPixelRatio
The pixel ratio of the user's device. Type "1f". You should never set the value of this uniform yourself.
For each string of text you wish to render with a given Material, you should create an instance of Blotter.Text
.
construction
var text = new Blotter.Text(value[, properties]);
Create a new instance of Blotter.Text
where value
is string of text1 and properties
is an optional styles object for applying styles to your texts prior to them being rendered with your Material. The styles object takes any of the following optional parameters.
family
properties.family
A string representing the font family to be applied to the text. The default value is 'sans-serif'.
size
properties.size
A number representing the size of the rendered text. The default value is 12.
leading
properties.leading
A number representing the leading or line-height of the rendered text. The default value is 1.5. You should try to keep this number above 1.0, as Blotter bases text positions within the text atlas on computed text heights, and leading values that are lower than the text size they coorespond with can cause texts to overflow into adjacent canvases.
fill
properties.fill
A string representing the color of the rendered text. The default value is '#000'.
style
properties.style
A string representing the style of the rendered text. The options are 'normal', 'italic', or 'bold'. The default value is 'normal'.
weight
properties.weight
A number representing the weight of the rendered text. The default value is 400.
padding
properties.padding
A number representing the padding around the rendered text. The default value is 0.
paddingTop
properties.paddingTop
A number representing the padding above the rendered text. The default value is 0.
paddingRight
properties.paddingRight
A number representing the padding to the right of the rendered text. The default value is 0.
paddingBottom
properties.paddingBottom
A number representing the padding below the rendered text. The default value is 0.
paddingLeft
properties.paddingLeft
A number representing the padding to the left of the rendered text. The default value is 0.
needsUpdate
text.needsUpdate = true
Rarely, you may need to perform actions on your instances of Blotter.Text
that require it to tell the instance of Blotter
to repeat important preparatory steps necessary for rendering the instance's texts. To do so, set the value of text.needsUpdate
to true
and the instance will take care of the rest. You can listen for the Blotter
instance's update
event if you need to do any work after the update has completed.
value
text.value
The string of text for the instance. Setting this property after your Blotter.Text
object's initialization requires that your Blotter.Text
instance be rebuilt by setting the value of its needsUpdate
property to true
.
properties
text.properties
The styles object representing the style properties being applied to your string of text. Setting this property after your Blotter.Text
object's initialization requires that your Blotter.Text
instance be rebuilt by setting the value of its needsUpdate
property to true
.
Blotter RenderScopes are the primary interface for interacting with your texts on an individual basis. When you render one or more texts inside an instance of Blotter
, the instance will create the scopes for you automatically, and you can use them to perform a number of critical actions, such as placing your rendered texts within DOM elements and setting uniform values specific to individual texts while rendering texts collectively in a single material.
obtainment
var scope = blotter.forText(text);
You will never create Blotter.RenderScope
objects directly. Instead, you should obtain them from your instance of blotter by calling blotter.forText(text)
where text
is an instance of Blotter.Text
known to your blotter
object.
text
scope.text
The instance of Blotter.Text
for the scope.
playing
scope.playing
A boolean value indicating whether or not the scope will actively be rendered by the Blotter
instance. On initialization, this value is set to the value of the Blotter
instance's autoplay
property.
timeDelta
scope.timeDelta
The scope's render time in seconds.
lastDrawTime
scope.lastDrawTime
The scope's last draw time.
frameCount
scope.frameCount
The number of times the scope has been rendered.
domElement
scope.domElement
The DOM element for the given scope. This will return a HiDPI canvas with a 2d
context containing an up-to-date rendering of your text. You should place this element where you want the text for the scope to appear on the page. You may access the element directly through this property, or append it to another DOM element using the convenience method, scope.appendTo(domElement)
.
Because it is likely you will want to respond to pointer events on these elements, Blotter RenderScopes emit the "mousedown"
, "mouseup"
, "mousemove"
, "mouseenter"
, and "mouseleave"
events.
context
scope.context
The 2d
context for the scope's domElement
.
material
scope.material
The primary interface for interacting with the Material being rendered by your Blotter
instance in a manner specific to an individual text. This is critically important for updating uniforms in a non-global way. For example, if you are rendering several texts using a single Material, and want to have one of those texts update its visual appearance on a mouseover event without changing the other texts, you would want to access the uniforms for the Material through the scope, and not on the Material's instance directly.
material.uniforms.myUniform.value = 0.5; // GLOBAL TO ALL TEXTS
scope.material.uniforms.myUniform.value = 0.5; // TEXT SPECIFIC
play
scope.play()
Tells the scope to begin or resume being rendered by the instance of Blotter
.
pause
scope.pause()
Tells the scope to pause being rendered by the instance of Blotter
.
render
scope.render()
Tells the scope to update its rendering one time.
appendTo
scope.appendTo(domElement)
A convenience method for appending the scope's domElement
to the page.