One documentation hub for the engine's C++ core, internal architecture, public API, JavaScript runtime, editor, UI system, project structure, game modules, assets, build pipeline and runtime.
Start here. You do not need C++ to make a game with Lynx. Use the editor and JavaScript for gameplay. C++ is the extension layer when you need custom Actors, Components, systems or native modules.
1. What is Lynx?
Lynx is a C++ game engine built around Actors, Components, Levels and a lightweight JavaScript layer. Rendering is provided by HRL, while EnTT is used internally for the ECS registry and QuickJS-ng powers scripting.
ActorWorld object with transform, scripts, components and ownership.
LevelOwns active Actors and safely defers spawn/destruction during iteration.
ComponentReusable native gameplay behavior attached to an Actor.
ObjectBase reflected object used by engine and game classes.
EngineOwns global runtime state, the current Level, factory, players and HRL scene.
QuickJSRuns gameplay scripts and JavaScript classes.
2. The project workflow
A normal Lynx project is edited as a project folder. The editor manages the level, Actors, assets, input settings and scripts. The game itself is built as a separate DLL which is loaded by the editor or runtime.
01 / CREATEOpen a project and configure its assets, level and input.
02 / BUILDUse JavaScript and the editor first. Add C++ only when native extension is required.
03 / PLAYEditor Play mode loads the game module and runs the current level.
04 / RELOADReload Game can rebuild/reload the game DLL without restarting the editor.
05 / SHIPLynxRuntime runs the project without the editor.
06 / DISTRIBUTEShip Game prepares a release runtime and project assets.
The native API is intended for extending Lynx rather than forcing every game to be written in C++. Public engine headers expose stable concepts such as Engine, Level, Actor, Component, input, scripting and widgets without requiring third-party ECS headers in gameplay code.
The host application is responsible for the window and for feeding frames to the engine. Rendering is initialized through HRL before the engine scene is created.
Custom Component
struct Health : lynx::Component
{
float hp = 100.f;
protected:
void BeginPlay() override {}
void Tick(float dt) override
{
if (hp <= 0.f)
GetOwner()->GetController(); // example engine access
}
void EndPlay() override {}
};
auto& health = actor->AddComponent<Health>();
Component callbacks are optional. The lifecycle is OnAttach(), BeginPlay(), Update(dt), Tick(dt), EndPlay(), then destruction. Update also runs outside gameplay; Tick is gameplay simulation and respects tick_enabled.
4. Engine internals
The runtime is deliberately split into layers. The editor and host are not the same thing as the engine DLL, and third-party implementation details stay behind the public headers.
Layer
Responsibility
Host
Window, platform integration, project selection and gamepad plumbing.
Engine
Game state, Level, Actors, Components, players, factory and frame progression.
ECS
Internal EnTT registry. Actors expose an opaque entity id instead of EnTT types.
Scripting
QuickJS-ng runtime, script instances, JavaScript classes and bindings.
Rendering
HRL scene, viewports, cameras, sprites, lights and rendering resources.
Level iteration is protected by deferred queues. Actors spawned or destroyed while the engine is traversing the Actor list are finalized safely after the iteration instead of invalidating the container.
5. Actors, Components and Levels
Actor
lynx::Actor inherits from Object. It contains a transform, script list, possession state, editor folder metadata and an internal ECS entity. Components are owned by the Actor.
Level owns active Actors. Native code can spawn by factory class name, construct a concrete Actor, find Actors by id, iterate them, count classes and save the level.
auto* player = level->SpawnActor("Player");
auto* enemy = level->GetActorFromID("Enemy01");
for (auto* actor : level->GetActors())
{
// inspect actors
}
level->DestroyActor(enemy);
6. Reflection, properties and functions
Lynx uses explicit reflection. A native member becomes visible to the editor and JavaScript when registered by the class. This keeps the public system predictable and avoids requiring a general-purpose C++ reflection library.
class Pawn : public lynx::Actor
{
public:
float move_speed_ = 5.f;
void Jump();
Pawn()
{
HPROPERTY(move_speed_, lynx::Exposed);
HFUNCTION(Jump);
}
};
HPROPERTY exposes a value to Details, level serialization and JavaScript. HFUNCTION registers a callable function for the same reflection system. Supported property values include int, float, bool, std::string, vec2, vec3, vec4 and transform.
Dynamic properties
Objects can also create reflected properties at runtime. This is used by JavaScript classes for static properties, which then appear in Details and are serialized like native properties.
7. Game DLLs and the Factory
Game projects are separate from the engine. The factory allows native classes to be registered when the game module is loaded and removed again when it is unloaded.
The exported module functions are FactoryRegisterClasses() and FactoryUnregisterClasses(). The engine removes constructors belonging to an unloaded DLL so the factory never keeps function pointers into a module that no longer exists.
The game should be compiled with the same compiler/toolchain and engine version as the editor/runtime.
8. JavaScript runtime
JavaScript is the preferred gameplay iteration layer. A normal attached script is a behavior, not a class. Every attachment receives its own execution environment while the source can be compiled and cached.
function BeginPlay()
{
parent.position = vec3(5, 0, 0);
}
function Update(dt)
{
parent.position.x += 3 * dt;
}
JavaScript classes
Assets can also define Actor classes using standard JavaScript inheritance:
Classes derived from Actor are registered in the same factory concept as C++ classes and can appear in Place Actors, level files and Level.spawn().
Core globals
Levelspawn, find, findWithTag, all, count, destroy.
Inputpressed, held, released, axis.
Enginetime dilation, game state and player access.
UICreate, destroy and inspect UserWidgets.
vec3()Create vector values used by transforms and gameplay.
consolelog, info, warn and error output.
For the complete JavaScript reference, use the dedicated JavaScript guide.
9. Lynx Editor
The editor is a separate application built around Dear ImGui with docking. It is the development environment for levels, assets, scripts, input, widgets and game builds.
ViewportPlay/edit the current world and interact with Actors.
OutlinerBrowse Actors and organize them into folders.
DetailsEdit reflected Actor/component properties.
Content BrowserBrowse project assets and create engine resources.
Script EditorEdit JavaScript with engine-aware workflows.
Input SettingsEdit input.json and apply mappings immediately.
Widget EditorBuild UMG-like interfaces from .widget assets.
Build / ReloadCompile and reload the game DLL without restarting the editor.
Input Settings
Input mappings live in input.json. Actions and axes can use keyboard, mouse and gamepad inputs. Changes made through Input Settings are saved and reloaded immediately.
Project and build tools
The editor contains project/build tooling, output console, profiler views, graph editors, JSON/markdown/text editors and project settings. These are editor facilities and are not required by the standalone runtime.
10. UI and Widget system
Lynx has a UMG-like widget tree. A UserWidget is an asset-backed root containing panels and controls. The same system is available from C++ and JavaScript, while HRL remains an implementation detail of the renderer.
Built-in panels include CanvasPanel, VerticalBox, HorizontalBox, Overlay and Border. Controls include TextBlock, Button, Image, Slider, CheckBox, ProgressBar and Spacer.
Widget layouts use slate units and a DPI reference so a design made for 1920×1080 can scale to different viewport sizes. The Widget Editor stores the tree in .widget assets.
11. Assets and project data
Levels
Levels serialize Actors, object ids, reflected properties, scripts and editor metadata such as Outliner folders. Scripts can be attached directly through the Actor's scripts property.
Voxels
assets/voxels.json describes voxel types, including collision and gameplay flags, emissive behavior and destruction rules. The editor and runtime load this data before the level; Reload Game reloads it as well.
Input
input.json contains Action Mappings and Axis Mappings. Named key codes such as KEY_SPACE and KEY_W are supported, while older numeric codes remain accepted.
Widgets and scripts
.widget files describe UI trees. JavaScript files can live anywhere under assets/; a classes/ directory is only a convention.
12. Runtime, host and shipping
Standalone runtime
LynxRuntime.exe
LynxRuntime.exe "C:/path/MyGame"
The runtime plays a project without the editor. The game DLL is searched beside the executable and then in the project's build directory.
Host boundary
The host owns the platform window. GLFW and platform input are kept outside the core engine boundary. The engine receives the relevant opaque handles and frame timing instead of owning the application's window lifecycle.
Release / Ship Game
The release engine build provides LynxRuntime.exe and the required engine DLLs. Ship Game can use a project icon and stores its project-specific settings in .lynx/ship.cfg.
13. Detailed references
ArchitectureEngine, Level, Actor, ECS, Factory, systems and frame lifecycle.
JavaScriptScript model, lifecycle, Actor API, transforms, input and hot reload.
Third-partyLibraries used by Lynx, their roles, layers and upstream licenses.