Concord Flash is the second generation of the Concord engine: a native Forward+ Vulkan 3D engine for Windows. It keeps the first generation's user-facing syntax, but rewrites the render backend, deepens the ECS model, and deliberately cuts complexity that never earned its keep.
Status: the engine foundation is verified. Windowing, the Vulkan frame lifecycle, the ECS core, and the two-DLL architecture are operational. When staged SPIR-V artifacts are built, the procedural Box depth/forward path uses a per-frame UBO for camera, ambient, and bounded directional/point/spot lights, plus a fixed-grid tile light-list compute pass. Directional shadow mapping and an internal KHR ray-generation pipeline are also available: each frame slot owns isolated device-address geometry, BLAS/TLAS, SBT, and output resources. Devices or swapchains without the required capabilities fall back to the Forward+ raster path automatically. Imported model data, GPU skinning, and skinned shadow draws are available; CPU pose blending, state-machine transitions, joint masks, and layered override/additive animation live in
engine/animation(see docs/动画混合与状态机.md). APIs, file formats, and runtime behavior may change without any compatibility guarantee.
<Concord/CRender.h> exposes a small, Vulkan-header-free pass ABI for code
generated by ConcordScript or hand-written C++. Register a callback with
Concord::RegisterVulkanPass; Render.dll invokes it during command recording
at BeforeScene or AfterScene, in ascending order. The callback receives
VulkanPassContext, including opaque device, command-buffer, swapchain image,
descriptor-set, and optional acceleration-structure handles. Convert handles
with Concord::VulkanHandle<VkType>(value) in a translation unit that includes
the Vulkan SDK. Callbacks may record commands but must not submit or end the
engine-owned command buffer. Initialize and Shutdown are lifecycle-only:
they report VulkanPassInvalidImageIndex and zero per-frame attachment,
descriptor, and acceleration-structure handles.
The generated ConcordScriptShaders.cmake helper can compile inline and
external shader sidecars with per-shader DEFINES, INCLUDE_DIRS, and
OPTIONS. Each item is passed as a separate compiler argument, so paths with
spaces remain valid and the output name changes when options change. The same
configuration is retained in the generated JSON manifest for reflection and
pipeline tooling.
The first generation of Concord was built on bgfx, trading a cross-platform rendering abstraction for portability across Windows, macOS, and Linux. That abstraction itself created three problems the second generation set out to solve:
- The cost of indirection. bgfx's cross-backend design meant any Vulkan-specific capability (dynamic rendering, explicit frame synchronization, precise memory layout) had to first ask "does bgfx support this?" instead of just being written. The second generation programs against Vulkan directly, trading cross-platform reach the first generation never used for full control over the render pipeline.
- Modules split too finely. The first generation split the engine into
30+
C*.hfacade headers and several independent DLLs (CEngine.dll/CAudio.dll/CGUI.dll/CSystem.dll/CTime.dll), many of which had a facade with no real content this early in the project. The second generation only builds a facade header once a module actually has code, and splits DLLs along real coupling boundaries (runtime vs. render backend) rather than one per module. - Scene and ECS were two parallel states. The first generation's
Scene::Spawnproduced node objects that owned their own data, whileEcs::Worldwas a completely separate component database — neither knew the other existed. Using ECS meant giving up the node API, and vice versa.
This is the central improvement. Scene::Spawn<T> and Scene::Query<...>
now share the same component storage — the object-oriented spawn syntax is
just a thin shell over the data-oriented query:
// Object-oriented view: spawn an archetype, then chain a custom component onto it.
scene.Spawn<Object::Box>({.material = {.albedo = COLOR_RGB(224, 64, 64)}})
.Add<Spin>(Spin{.degreesPerSecond = 60.0f});
// Data-oriented view: compose an entity component by component, no archetype at all.
scene.CreateEntity()
.Add<Transform>(Transform{.position = {4.0f, 1.5f, 1.0f}})
.Add<MeshRenderer>(MeshRenderer{});
// One query sees both — because they were always the same data.
scene.Query<Transform, MeshRenderer>([](Entity, Transform& t, MeshRenderer& m) { ... });See docs/场景与ECS.md for the full model (Chinese; English translation pending).
| First generation | Concord Flash |
|---|---|
scene.Spawn<Object::Box>(Object::BoxDesc{...}) repeats the type name |
scene.Spawn<Object::Box>({...}), T::Desc is deduced |
.material = {.surface = {.albedo = ...}} nests two levels |
.material = {.albedo = ...}, flattened to one |
| 30+ facade headers, some for empty modules | Facade headers only for modules that actually exist, added as needed |
Concord::Sleep(20000) to keep the window alive |
game.Run(), a real main loop |
| Every primitive has its own stateful Desc + Node pair | Node becomes a stateless "recipe"; all state lives in the ECS |
The engine splits into two DLLs: ConcordFlashGameEngineRuntime.dll
(lifecycle, ECS, scene, window) and ConcordFlashGameEngineRender.dll
(the Vulkan backend). Runtime obtains a render backend instance through a
self-registering factory and never references Vulkan symbols directly —
keeping the dependency between the two DLLs one-directional, and letting the
render backend be replaced or upgraded independently without recompiling the
whole runtime. See docs/渲染架构.md for details.
#include <Concord/CApplication.h>
#include <Concord/CCamera.h>
#include <Concord/CLight.h>
#include <Concord/CObject.h>
#include <Concord/CScene.h>
int main()
{
Concord::Game game;
Concord::Window window({.title = "My Game", .resolution = {1280, 720}});
game.AttachWindow(window);
Concord::Scene scene;
scene.Spawn<Concord::Object::Camera>({.position = {0.0f, 2.0f, -5.0f}});
scene.Spawn<Concord::Object::SunLight>({.elevationDegrees = 45.0f});
scene.Spawn<Concord::Object::Box>({.transform = {.position = {0.0f, 1.0f, 0.0f}}});
game.LoadScene(scene);
game.Run();
}Full syntax and architecture documentation lives under docs/ (currently written in Chinese; English translations are planned):
- Quick Start
- Application & Window
- Scene & ECS
- Components & Archetypes
- Systems & Scheduling
- Render Architecture
- Model Import & Skeletal Animation
- Build & Dependencies
Engineering standards (naming, file layout, the per-file line limit, etc.)
live in AGENTS.md at the repository root.
Concord Flash is licensed under the Mozilla Public License 2.0:
modifying an engine source file requires publishing that file's changes, but
a game built with the engine is entirely unaffected and can be distributed
closed-source. Third-party dependencies keep their own original licenses;
see the subdirectories under src/3rd/.
Concord Flash is developed by Datatype Team (datatype.me), a full-stack development team founded by Simalth Wang, the original creator of Concord. The previous maintainer, Lattice Games, no longer updates the first generation of the engine; all active development now happens here, under Datatype Team.

