Usage

SafiEngine is used through its visual editor. You create projects, build scenes by adding entities and components, attach native C++ behaviors for gameplay logic, and test everything with the built-in play mode.

Creating a Project

Launch the editor and use the Project Hub to create a new project or open an existing one.

Adding Entities

Use the Scene Hierarchy panel to add entities to your scene. Right-click in the panel or use the Add Entity button to create a new entity.

Adding Components

Select an entity in the Scene Hierarchy, then use the Inspector panel to configure it. Click Add Component to attach components:

  • Transform — position, rotation, and scale in world space
  • ModelRenderer — attach a 3D model or procedural primitive
  • PointLight / DirectionalLight / SpotLight — add lighting
  • RigidBody + Collider — add physics simulation
  • Camera — define a runtime camera
  • NativeScript — attach C++ gameplay behaviors
  • AudioSource — play sounds
  • ParticleEmitter — spawn particles

Importing Models

Use the Asset Browser panel to browse your project's files. The engine supports .glb (binary glTF) models which include:

  • Positions and normals for geometry
  • Texture coordinates for UV mapping
  • Base color factor from PBR materials
  • Base color textures embedded in the GLB
  • Bone joints and weights for skeletal animation

Drag a model from the Asset Browser into the scene, or select an entity and add a ModelRenderer component pointing to the model path.

Procedural Primitives

You can add built-in 3D shapes without any external model files. Select an entity, add a ModelRenderer component, and choose a primitive type:

  • primitive:box
  • primitive:sphere
  • primitive:plane
  • primitive:cylinder
  • primitive:capsule

Adding Lights

Create an entity and add a light component via Add Component:

Light TypeDescription
PointLightEmits light in all directions from a point. Configure color, intensity, and attenuation.
DirectionalLightSimulates a distant light source (like the sun). Direction is derived from the entity's Transform rotation.
SpotLightCone-shaped light with inner/outer cutoff angles. Direction is derived from Transform rotation.

If no light entities exist, the engine uses a fallback directional fill light.

Playing and Testing

Press the Play button in the toolbar to enter play mode. Physics simulation, native scripts, and audio will activate. Press Stop to return to the editor state — all changes made during play mode are automatically reverted.

Saving Scenes

Save your scene via the File menu:

ActionShortcut
New SceneCtrl+N
Open SceneCtrl+O
Save SceneCtrl+S
Save Scene AsCtrl+Shift+S

Scenes are saved as .scene JSON files.

Native C++ Scripting

Gameplay logic is written in C++ using the Behavior system. Each behavior is a class that extends Behavior with OnStart and OnUpdate methods:

#include "Core/Behavior.h"
#include "Core/Components.h"
#include "Core/Engine.h"
#include <GLFW/glfw3.h>

namespace SafiEngine {

class PlayerBehavior : public Behavior {
public:
  void OnStart(flecs::entity e, Engine &engine) override {
    // Called once when play starts
  }

  void OnUpdate(flecs::entity e, Engine &engine, float dt) override {
    auto &input = engine.GetInput();
    float speed = 4.0f;
    float vx = 0.0f, vz = 0.0f;
    if (input.IsKeyDown(GLFW_KEY_W)) vz -= speed;
    if (input.IsKeyDown(GLFW_KEY_S)) vz += speed;
    if (input.IsKeyDown(GLFW_KEY_A)) vx -= speed;
    if (input.IsKeyDown(GLFW_KEY_D)) vx += speed;
    engine.GetPhysicsWorld().SetLinearVelocity(e.id(), vx, 0.0f, vz);
  }
};

void RegisterPlayerBehavior() {
  BehaviorRegistry::Register("Player",
      [] { return std::make_shared<PlayerBehavior>(); });
}

} // namespace SafiEngine

Add the behavior file to Core/CMakeLists.txt, register it in Behavior.cpp's RegisterAll(), rebuild, and select it from the NativeScript component dropdown in the Inspector.