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.