This diagram illustrates the layered architecture of LunyScript, showing how portable game logic runs across multiple game engines.
Click diagram to view full size ⤢
%%{init: {'theme':'base', 'themeVariables': {
'fontSize':'16px',
'edgeLabelBackground':'#ffffff',
'labelBoxBorderColor':'#999'
}}}%%
graph TB
subgraph User[" "]
UserTitle["<b>👤 Game Developer</b>"]
UserCode["Game Logic Code<br/>(Portable C#)"]
end
subgraph LunyScript[" "]
LSTitle["<b>🎮 LunyScript Layer</b><br/><i>Write Once, Run Anywhere</i>"]
FluentAPI["Fluent API<br/>When.Collision.With('Enemy').Begins(...)"]
CoreLogic["Script Execution Engine<br/>• Coroutine Scheduler<br/>• State Machines<br/>• Behavior Trees<br/>• Event Dispatcher"]
end
subgraph Luny[" "]
LunyTitle["<b>⚙️ Luny Abstractions</b><br/><i>Pure Interfaces & Contracts</i>"]
Interfaces["Core Interfaces<br/>• ICoroutineScheduler<br/>• IStateMachine<br/>• IBehaviorTree<br/>• IEventDispatcher"]
Contracts["Behavioral Contracts<br/>• Execution Order<br/>• Semantic Rules<br/>• Zero Engine Dependencies"]
end
subgraph EAL[" "]
EALTitle["<b>🔧 Engine Abstraction Layer</b><br/><i>Luny.EAL</i>"]
EALInterfaces["Engine Interfaces<br/>• IPhysics<br/>• IAudio<br/>• ISceneGraph<br/>• IInput"]
EALObservers["Event Observers<br/>• Collision<br/>• Input<br/>• Lifecycle"]
end
subgraph Adapters[" "]
AdapterTitle["<b>🔌 Engine Adapters</b><br/><i>Platform-Specific Glue</i>"]
UnityAdapter["Unity Adapter<br/>LunyScript.Unity"]
GodotAdapter["Godot Adapter<br/>LunyScript.Godot"]
end
subgraph Engines[" "]
EngineTitle["<b>🎯 Game Engines</b>"]
Unity["Unity<br/>• MonoBehaviour<br/>• Physics<br/>• Audio"]
Godot["Godot<br/>• Node System<br/>• Signals<br/>• Resources"]
end
UserCode -->|" uses "| FluentAPI
FluentAPI -->|" delegates to "| CoreLogic
CoreLogic -->|" implements "| Interfaces
Interfaces -.->|" defines contracts "| Contracts
CoreLogic -->|" calls "| EALInterfaces
EALInterfaces -.->|" observes "| EALObservers
EALObservers -.->|" implemented by "| UnityAdapter
EALObservers -.->|" implemented by "| GodotAdapter
UnityAdapter -->|" integrates with "| Unity
GodotAdapter -->|" integrates with "| Godot
classDef userLayer fill:#e1f5ff,stroke:#0077cc,stroke-width:2px,color:#2d3748
classDef lunyScriptLayer fill:#d4edda,stroke:#28a745,stroke-width:2px,color:#2d3748
classDef lunyLayer fill:#fff3cd,stroke:#ffc107,stroke-width:2px,color:#2d3748
classDef ealLayer fill:#ffe5cc,stroke:#ff8c00,stroke-width:2px,color:#2d3748
classDef adapterLayer fill:#f8d7da,stroke:#dc3545,stroke-width:2px,color:#2d3748
classDef engineLayer fill:#e2e3e5,stroke:#6c757d,stroke-width:2px,color:#2d3748
classDef titleStyle fill:none,stroke:none,color:#2d3748,font-size:20px
class UserCode userLayer
class FluentAPI,CoreLogic lunyScriptLayer
class Interfaces,Contracts lunyLayer
class EALInterfaces,EALObservers ealLayer
class UnityAdapter,GodotAdapter adapterLayer
class Unity,Godot engineLayer
class UserTitle,LSTitle,LunyTitle,EALTitle,AdapterTitle,EngineTitle titleStyle
When.Collision.With("Enemy").Begins(
Audio.Play("hit"),
DecrementVariable(health),
If(IsVariableLessOrEqual(health, 0), EndGame())
);
Examples:
Examples:
LunyScript’s architecture enables other developers to build their own cross-engine frameworks by reusing and extending the abstraction layers and engine adapters.
Click diagram to view full size ⤢
%%{init: {'theme':'base', 'themeVariables': {
'fontSize':'16px',
'edgeLabelBackground':'#ffffff',
'labelBoxBorderColor':'#999'
}}}%%
graph TB
subgraph User["<b>👥 Framework Users</b>"]
UserCode["Game Developers using<br/>LunyScript or Custom Frameworks"]
end
subgraph Frameworks[" "]
FrameworkTitle["<b>🎮 Cross-Engine Frameworks</b>"]
LunyScript["LunyScript<br/><i>Declarative Gameplay API</i>"]
CustomFW["Your Framework<br/><i>Custom Domain-Specific API</i>"]
end
subgraph Luny[" "]
LunyTitle["<b>⚙️ Shared Foundation</b>"]
Abstractions["Luny Abstractions<br/>Core Interfaces & Contracts"]
EAL["Engine Abstraction Layer<br/>IPhysics, IAudio, IInput, ISceneGraph"]
end
subgraph EngineLayer[" "]
EngineTitle["<b>🎯 Engine Integration</b>"]
Adapters["Engine Adapters + Game Engines<br/>Unity, Godot, Future Engines"]
end
UserCode -->|uses| LunyScript
UserCode -->|uses| CustomFW
LunyScript -->|built on| Abstractions
LunyScript -->|calls| EAL
CustomFW -->|built on| Abstractions
CustomFW -->|calls| EAL
EAL -->|implemented by| Adapters
Abstractions -.->|defines contracts for| EAL
classDef userLayer fill:#e1f5ff,stroke:#0077cc,stroke-width:2px,color:#2d3748
classDef frameworkLayer fill:#d4edda,stroke:#28a745,stroke-width:2px,color:#2d3748
classDef foundationLayer fill:#fff3cd,stroke:#ffc107,stroke-width:2px,color:#2d3748
classDef engineLayer fill:#e2e3e5,stroke:#6c757d,stroke-width:2px,color:#2d3748
classDef titleStyle fill:none,stroke:none,color:#2d3748,font-size:20px
classDef customHighlight fill:#ffe5cc,stroke:#ff8c00,stroke-width:3px,color:#2d3748
class UserCode userLayer
class LunyScript frameworkLayer
class CustomFW customHighlight
class Abstractions,EAL foundationLayer
class Adapters engineLayer
class FrameworkTitle,LunyTitle,EngineTitle titleStyle
1. LunyScript provides the foundation:
2. You build on top:
3. Benefits for framework developers:
Example: A Visual Novel Framework
// Your custom framework built on LunyScript foundation
public class VisualNovelScene : LunyScriptBehavior
{
protected override void OnReady()
{
// Use EAL for audio/input
When(ButtonClicked("Choice1"),
Audio.Play("choice_sound"),
LoadScene("chapter2")
);
// Use Luny Abstractions for state management
var dialogueState = StateMachine.Create()
.State("Intro", ShowDialogue("Welcome..."))
.State("Choice", ShowChoices())
.Transition("Intro", "Choice", After(5));
}
}
Same game logic runs on Unity and Godot (and future engines)
Declarative API reduces boilerplate by >=70% compared to native engine code
No need to learn engine-specific patterns - focus on game logic
Switch engines without rewriting gameplay code - avoid vendor lock-in
Write in C# (Lua) - same API across all languages
| Layer | Change Frequency | Why |
|---|---|---|
| Luny | Low | Core abstractions rarely change once established |
| LunyScript | Medium | Grows with new features, core logic stable |
| EAL | Low-Medium | Engine interfaces evolve as LunyScript features expand |
| Adapters | High | Evolves with engine API changes, but low effort |
Under Consideration:
// This exact code works in Unity and Godot
protected override void OnReady()
{
var score = Variables.Set("Score", 0);
HUD.BindVariable(score);
When.Collision.With("Coin").Begins(
IncrementVariable(score),
Audio.Play("coin_pickup")
);
}
Same code, multiple engines, zero changes. 🎉
Note: The goal is to have LunyScript user code in an engine-agnostic subclass, but this has not been fully evaluated in regards to editor integration and user’s workflow.