Rendering
Overview
Our World of Text uses HTML5 canvas as the core for its world rendering. HTML5 canvas allows for advanced graphics capabilities and high performance, unlike direct DOM text.
A world is divided into tiles. The text content of each tile is cached as an image and is redrawn every time the content changes. Whenever the user scrolls the world around, all tiles in the viewport are taken out of the cache and blitted onto the screen.
As a part of the rendering process, three distinct type of canvases are used: the main screen canvas, the tile rendering canvas, and the content cache canvases. Everything a user sees on a world is the main screen canvas. Each time a tile is ready to be drawn, all characters are rendered to the tile rendering canvas one-by-one. The content of the tile rendering canvas is then cached to a content cache canvas, which is then composited to the main screen canvas.
Caching
Rendering text takes a lot of time. To save on time, the content of a tile is cached to a canvas. This avoids the need to re-render all tiles every time the user moves the page.
Prior to July 2021, all tiles had their own dedicated canvas to cache the rendered content. This later proved to be inefficient, since browsers tend to struggle having hundreds of canvas contexts in memory. The solution was to create large canvases, storing multiple tiles per canvas. Whenever a tile is ready to be placed onto the main screen, the specific region where the tile is located within the canvas is put onto the screen.
Transparency
By default, the text rendering canvas has the 'alpha' flag set to true, meaning its background is transparent. This means the tile's background color and cell protections are re-drawn for every frame and are not cached.
In non-transparent mode, the 'alpha' flag is set to false, meaning the background along the text is cached. Thus the tile's background is not redrawn for every frame. This mode also has the added consequence of text having subpixel rendering, which may make the text look crisper on LCD screens.
Queued rendering
As of June 2023, the rendering process started to use a queue for the rendering of the tiles. Prior to the update, the page would freeze if the user did performance-intensive tasks like show or hide the grid while zoomed all the way out. The update allowed the user to use the page normally while large rendering batch jobs complete in the background. Each frame is allowed 16 milliseconds of rendering time, allowing the user to continue using the client as tiles are being rendered. This allowed for more possibilities, like smooth zooming.
Shift optimization
Blitting tiles to the screen, while a very simple operation, takes a lot of time when there are thousands of tiles on the screen. This results in a choppy scrolling experience. This can happen when the page is zoomed out too far. The solution is to shift the content of the main canvas according to how far the user has scrolled. The tiles on the edge of the screen are then blitted individually. This is only enabled automatically when the user zooms out past 50%.
Edge buffering
Certain characters, like Emojis, are very wide. Emoji characters used to cut off at the rightmost edge of the tile. Edge buffering allows most wide characters to overflow into neighboring tiles, removing spontaneous cutoffs. This is achieved by rendering the content of the neighboring top and left tiles on the far top/left edges of the tile.
Special characters
Some box drawing characters, as well as those in the Symbols for Legacy Computing block, are rendered procedurally. This only includes blocky characters and SLC slope characters.
Scripting
The client's `w` namespace has several functions pertaining to rendering. It's important to know when it's appropriate to use certain functions.
w.redraw()
Forces all loaded tiles to have its text content re-rendered. This can be called frequently with no performance issues.
w.reloadRenderer()
Fully clears the renderer cache.
w.setRedraw()
Alias for w.redraw()
w.setTileRedraw(tileX, tileY, highPriority, fastQueue)
Forces a specific tile to have its text content re-renderered.
The highPriority parameter determines that this tile must be rendered before anything else.
The fastQueue parameter forces the renderer queue to process all tiles with this option immediately. This is useful for hiding the row-by-row rendering effect.
w.setTileRender(tileX, tileY)
Schedule a tile to be blitted onto the screen.
In transparent mode, only the background content and protections are re-rendered.
w.setTransparency(transparent)
Change the renderer's 'alpha' mode. Please see the Transparency section above for more details.
w.render(redraw)
Blits all tiles onto the screen. Must be called when the world position changes.
If the redraw parameter is set to true, then it's equivalent to calling w.redraw().