The text component renders signed distance field (SDF) font text.
Note that rendering text in 3D is hard. In 2D web development, text is the most basic thing because the browser’s renderer and layout engine handle everything. In a 3D context, we don’t have those luxuries. There are several other different ways to render text in A-Frame including:
As a default, we’ve selected SDF-based text to be included as a core component
due to its relatively good performance and clarity. This component uses
three-bmfont-text library. The standard text
component has a long lineage, starting out as a community component and was
forked and improved several times before landing into A-Frame!
Here’s a basic example of text defining just the content with not much other configuration.
<a-entity text="value: Hello World;"></a-entity>
See more examples to see configuration of alignments, anchors, baselines, scaling, and auto-sizing.
Open any of these example scenes, hit
<ctrl> + <alt> + i to open the
Inspector, and play with all the possible values to see the effects instantly!
|align||Multi-line text alignment (left, center, right).||left|
|alphaTest||Discard text pixels if alpha is less than this value.||0.5|
|anchor||Horizontal positioning (left, center, right, align).||center|
|baseline||Vertical positioning (top, center, bottom).||center|
|font||Font to render text, either the name of one of A-Frame’s stock fonts or a URL to a font file||default|
|fontImage||Font image texture path to render text. Defaults to the
||derived from font name|
|height||Height of text block.||derived from text size|
|letterSpacing||Letter spacing in pixels.||0|
|lineHeight||Line height in pixels.||derived from font file|
|opacity||Opacity, on a scale from 0 to 1, where 0 means fully transparent and 1 means fully opaque.||1.0|
|shader||Shader used to render text.||sdf|
|side||Side to render. (front, back, double)||front|
|tabSize||Tab size in spaces.||4|
|transparent||Whether text is transparent.||true|
|value||The actual content of the text. Line breaks and tabs are supported with
|whiteSpace||How whitespace should be handled (i.e., normal, pre, nowrap). Read more about whitespace.||normal|
|width||Width in meters.||derived from geometry if exists|
|wrapCount||Number of characters before wrapping text (more or less).||40|
|wrapPixels||Number of pixels before wrapping text.||derived from wrapCount|
|xOffset||X-offset to apply to add padding.||0|
|zOffset||Z-offset to apply to avoid Z-fighting if using with a geometry as a background.||0.001|
|textfontset||Emitted when the font source has been loaded|
We can specify different fonts, although the process is not as simple as Web
Fonts. The text component defaults to
roboto which uses a multi-channel
signed distance (MSDF) font. MSDF helps to preserve sharp corners and edges.
Select from one of A-Frame’s built-in fonts. These fonts will be loaded in from over a CDN. If you want your application to work better offline, download these fonts locally and point to them via a URL.
|Stock MSDF Fonts||URL|
|Stock SDF Fonts||URL|
Different fonts can be specified using the
<a-entity text="font: mozillavr; value: Via stock font name."></a-entity>
If not specified,
fontImage will be the
font‘s name, but with the extension
.png. For example, if the
font path ends with
fontImage texture will default to
Below is an example comparing a font generated with Hiero, Arial Black, with the SDF font, DejaVu:
To use non-ascii characters, you need to create your own custom font. The easiest way is to use a web-based MSDF tool. Select your required character set and generate your own custom msdf font zip file.
Here is an example of a French character set you can use:
Once you download your custom msdf font zip file, extract it, then put both png and json files to your A-Frame directory.
From A-Frame 0.9.0 and above, you don’t need to rename
*-msdf.png anymore, A-Frame loads the image defined in the json file.
Lastly, you should specify the character set used in your HTML by using
<meta> tag to avoid text to be garbled. If your text is garbled, it is not rendered.
To change the size of the text, we can:
- Change the
- Change the
wrapCount(roughly how many characters to fit inside the given width).
- Change the scale component.
- Position the text closer or farther away.
Text can be wrapped by specifying width in A-Frame units.
In case we need to do custom layout or need to know the bounds of the text, the output length of the text can be pre-calculated dynamically with something like:
totalWidth = data.value.length * (data.width / data.wrapCount)
The text component introduces special behavior when using alongside the
geometry component (e.g., a background plane) to fit. Note this only works with
2D-friendly geometries that define a width and height (i.e.,
The text can either be scaled, bounded, or aligned in relation to the geometry,
or the text can auto-scale the geometry to fit the text.
To have the text component’s
width property automatically scale to match the
width, do not specify a
width for the text component:
To have the geometry automatically scale with the text, set the geometry
height properties to
auto, and set the text
width as desired. In this example, the plane’s
width will be
set to 4 units, and its
height will be set to match the actual height of the
Note that if neither
text specify a width, the text
property will default to 1 unit (meter), and the geometry
width property will
then become 1 unit as well.
The text component does not make use of all of the features of the
three-bmfont-text library nor its sister modules.
Bitmap font rendering limits you to the characters included in the font (Unicode this is not). SDF font rendering tends to produce smooth sharp edges though there are ways around this.
The generated text is not suitable for raycaster intersection testing. For raycaster or cursor detection it is necessary to use a geometry component along with the text component.
If you are curious about the details of text rendering in WebGL, three.js, and A-Frame, below are links to some background reading: