Setting Up the Platform
Configure platform handlers on the Platform singleton before creating the renderer.
On this page
Ultralight delegates OS tasks (such as file loading, font lookup, clipboard access, logging, GPU rendering, and audio playback) to handler objects registered on the Platform singleton— you configure them once before creating the renderer. If you use AppCore, it sets up default platform handlers automatically.
Registering Platform Handlers
You register each handler on Platform::instance() using its dedicated setter method, such as Platform::set_file_system() or Platform::set_font_loader().
| Handler | Purpose | With Renderer::Create() |
Guide |
|---|---|---|---|
FileSystem |
Loads file:/// URLs and library resource files |
Required | Custom File System |
FontLoader |
Maps CSS font families to font data | Required | Custom Font Loading |
Clipboard |
Handles copy and paste | Optional | Clipboard Integration |
Logger |
Receives library log messages | Optional | Logging and Console Messages |
GPUDriver |
Renders GPU-accelerated Views | Required for accelerated Views | Implementing a GPU Driver |
SurfaceFactory |
Allocates pixel buffers for CPU-rendered Views | Optional (default provided) | Render Surfaces |
AudioOutput |
Plays audio for <video> and <audio> |
Optional (Pro edition and higher) | Media and Audio |
ThreadFactory |
Creates the library's threads | Optional | Custom Threads |
Profiler |
Receives timing callbacks | Optional (Pro edition and higher) | Profiling and Tracing |
đźš§ Missing Required Handlers
The library logs a
LogLevel::Fatalmessage and exits the process if a required handler is missing. This happens at startup ifFileSystemis missing, and when creating the first View ifFontLoaderis missing. Creating an accelerated View without aGPUDriverexits the same way.
Setting Handlers with AppCore
App::Create() installs stock handlers automatically. If you set a handler on Platform before calling App::Create(), AppCore keeps it and fills in stock handlers for the rest.
đźš§ Custom Render Handlers with AppCore
AppCore keeps a
GPUDriverorSurfaceFactoryset beforeApp::Create(), but its windows can't present Views with it. You can set any other handler beforehand.
Using Stock Handlers
If you manage your own run loop and call Renderer::Create(), you can link AppCore to use its stock handlers declared in <AppCore/Platform.h> (the C version sits in the tab below).
#include <Ultralight/Ultralight.h>
#include <AppCore/Platform.h>
using namespace ultralight;
void InitPlatform() {
///
/// Use the OS's native font loader.
///
Platform::instance().set_font_loader(GetPlatformFontLoader());
///
/// Use the OS's native file loader, with a base directory of "."
/// All file:/// URLs will load relative to this base directory.
///
Platform::instance().set_file_system(GetPlatformFileSystem("."));
///
/// Use the default logger (writes to a log file, the library owns it).
///
Platform::instance().set_logger(GetDefaultLogger("ultralight.log"));
}
#include <AppCore/CAPI.h>
void InitPlatform(void) {
///
/// Use the OS's native font loader.
///
ulEnablePlatformFontLoader();
///
/// Use the OS's native file loader, with a base directory of "."
/// All file:/// URLs will load relative to this base directory.
///
ULString base_dir = ulCreateString(".");
ulEnablePlatformFileSystem(base_dir);
ulDestroyString(base_dir);
///
/// Use the default logger (writes to a log file, the library owns it).
///
ULString log_path = ulCreateString("ultralight.log");
ulEnableDefaultLogger(log_path);
ulDestroyString(log_path);
}
The library owns the handlers returned by these helper functions— you must never destroy them.
The SDK's platform/ folder contains the source code for each stock handler under the Zlib license, which you can use as a starting point for custom handlers (see Linking to the Library).
Setup Order for Renderer::Create()
When you create the renderer directly, set up the platform in this order:
- Call
Platform::instance().set_config()with aConfig(see Creating the Renderer). - Register platform handlers on
Platform::instance(). - Call
Renderer::Create()(see Your First Game UI).
Writing Custom Handlers
To write a custom handler in C++, inherit from the interface class, implement its virtual methods, and pass a pointer to the matching setter on Platform::instance().
You retain ownership of custom handlers passed to Platform— each instance must outlive the Renderer.
The library may call handler methods from threads other than the Renderer's thread. Each handler's guide details which calls run concurrently and must be thread-safe.
In C, platform handlers use structs of function pointers instead of C++ classes— see Platform Handlers in C.