A Modern Desktop Game Engine for the Web Era
Build stunning games with visual scripting, real-time 3D rendering, and a professional-grade editor — all powered by modern web technologies.
Linden Engine is a modern desktop game engine built with ElectronJS, TypeScript, React, and WebGPU. Inspired by industry-leading engines like Unreal Engine and Unity, Linden Engine provides an intuitive visual editor, powerful scripting capabilities, and cross-platform support — all wrapped in a web-first architecture.
Whether you're a solo indie developer, a student learning game development, or a team building the next big hit, Linden Engine gives you the tools to bring your creative vision to life.
With Linden Engine, you can:
- Create games visually using Blueprint visual scripting (no coding required!)
- Build in real-time with a professional 3D viewport and live editing
- Script with TypeScript for advanced gameplay logic with hot-reload support
- Design materials with a node-based material editor
- Animate characters using a state machine animator
- Create cinematics with a timeline-based sequencer
- Deploy everywhere — Windows, macOS, Linux, and Web
Note: Linden Engine is currently in active development (v0.1 Alpha). Features and APIs may change. We welcome contributions and feedback from the community!
Create game logic without writing code using our Blueprint visual scripting system — inspired by Unreal Engine's Blueprints.
- Event-driven: BeginPlay, Tick, Input events
- Flow control: Branch, Loops, Sequences, Gates
- Math & Logic: Add, Multiply, Compare, Random
- Game actions: Spawn actors, Play sounds, Move objects
- Variables: Store and manipulate data visually
A complete editing environment with all the tools you need:
- Scene Viewport: Real-time 3D rendering with transform gizmos
- Hierarchy Panel: Organize entities in a tree structure
- Inspector Panel: Edit properties and add components
- Asset Browser: Manage textures, models, sounds, and scripts
- Console: Debug output and error tracking
- Material Editor: Node-based shader authoring
- Animator: State machine for character animations
- Sequencer: Timeline-based cinematic editing
- ECS (Entity Component System): Scalable and performant game world management
- WebGPU Rendering: Next-gen graphics with Three.js fallback
- TypeScript: Type-safe scripting with full IDE support
- Hot Reload: See changes instantly without restarting
- Plugin System: Extend the engine with custom features
Build once, deploy everywhere:
- ✅ Desktop: Windows, macOS, Linux (via Electron)
- ✅ Web: Export to HTML5 for browser playback
- 🚧 Mobile: Android & iOS support (coming soon)
Getting Started
Features & Guides
API Reference
Community & Support
Before you begin, ensure you have the following installed:
- Node.js (v18 or higher) - Download here
- npm (v9 or higher) - Comes with Node.js
- Git - Download here
- Visual Studio Code (recommended) - Download here
Optional but recommended:
- TypeScript knowledge - For advanced scripting
- Basic 3D concepts - Understanding of vectors, transforms, etc.
git clone https://github.com/AlStartlight/LindenEngine.git
cd LindenEnginenpm installThis will install all required packages including:
- React 18 & React DOM
- Three.js (3D rendering)
- Electron (desktop app)
- TypeScript
- Tailwind CSS
- And more...
npm run devIf everything is set up correctly, you should see:
VITE v5.0.8 ready in 423 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
Open your browser and navigate to http://localhost:5173 to see the editor!
There are two ways to run Linden Engine:
npm run devThen open your browser to http://localhost:5173
Pros:
- Faster hot-reload
- Easier debugging with browser DevTools
- No Electron overhead
npm run electron-devThis will open the editor in a native desktop window.
Pros:
- Native window controls
- Better performance
- File system access
- Production-ready experience
Let's create a simple scene with a rotating cube:
npm run dev- In the Hierarchy panel (left side), right-click in empty space
- Select "Create Empty"
- Name it "Rotating Cube"
- Select the "Rotating Cube" entity in the Hierarchy
- In the Inspector panel (right side), click "+ Add Component"
- Choose "Mesh Renderer"
- In the Mesh Renderer properties, select "Cube" as the mesh type
- Click "+ Add Component" again
- Choose "📝 Blueprint"
- Click "Edit Blueprint" button to open the Blueprint Editor
In the Blueprint Editor:
- From the left palette, drag "Event Tick" to the canvas
- Drag "Get Actor Location" and place it to the right
- Drag "Rotate" node and connect it
- Set rotation values:
- X:
0 - Y:
1(rotate on Y-axis) - Z:
0
- X:
- Drag "Set Actor Location" and connect the execution flow
Your blueprint should look like this:
[Event Tick] ──exec──> [Get Transform] ──transform──> [Rotate] ──transform──> [Set Transform]
↑
[Y = 1.0]
- Click the Play button (▶) in the top toolbar
- Your cube should now rotate smoothly!
- Click Stop (⏹) to stop playback
Congratulations! You've created your first interactive scene in Linden Engine! 🎉
# Build everything (frontend + desktop app)
npm run build:all
# Build frontend only
npm run build
# Build Electron app only
npm run build:electron
# Create distributable packages
npm run electron-builderAfter building, you'll find:
| Type | Location | Description |
|---|---|---|
| Web build | dist/ |
Static files ready to deploy |
| Desktop app | dist-electron/ |
Electron bundles |
| Installers | release/ |
Platform-specific installers |
Deploy your game to any static hosting service:
# Build for web
npm run build
# Deploy to Netlify (example)
npm install -g netlify-cli
netlify deploy --prod --dir=dist
# Or deploy to Vercel
npm install -g vercel
vercel --prodCreate installers for all platforms:
# Build installers
npm run electron-builder
# Find installers in: release/
# - LindenEngine-Setup-0.1.0.exe (Windows)
# - LindenEngine-0.1.0.dmg (macOS)
# - LindenEngine-0.1.0.AppImage (Linux)LindenEngine/
├── 📂 editor/ # React-based editor UI
│ ├── 📂 ui/ # Toolbar, buttons, modals
│ ├── 📂 viewport/ # 3D viewport component
│ ├── 📂 panels/ # Editor panels
│ │ ├── HierarchyPanel.tsx
│ │ ├── InspectorPanel.tsx
│ │ ├── AssetBrowser.tsx
│ │ ├── BlueprintEditor.tsx
│ │ ├── MaterialEditor.tsx
│ │ ├── AnimatorEditor.tsx
│ │ └── SequencerEditor.tsx
│ └── EditorLayout.tsx # Main layout component
│
├── 📂 engine/ # Core engine code
│ ├── 📂 core/ # Engine lifecycle & initialization
│ ├── 📂 ecs/ # Entity Component System
│ │ ├── Entity.ts
│ │ ├── Component.ts
│ │ └── World.ts
│ ├── 📂 renderer/ # WebGPU + Three.js renderer
│ ├── 📂 physics/ # Physics engine (Rapier)
│ ├── 📂 scripting/ # Script system & lifecycle
│ ├── 📂 blueprints/ # Blueprint visual scripting
│ │ ├── BlueprintGraph.ts
│ │ ├── BlueprintNode.ts
│ │ └── BlueprintComponent.ts
│ ├── 📂 assets/ # Asset loader & cache
│ └── 📂 utils/ # Utilities & helpers
│
├── 📂 electron/ # Electron main process
│ └── main.ts
│
├── 📂 plugins/ # Plugin system
├── 📂 shared/ # Shared utilities
├── 📂 public/ # Static assets
├── 📂 docs/ # Documentation
│ └── BLUEPRINT_GUIDE.md
│
├── 📄 package.json
├── 📄 tsconfig.json
├── 📄 vite.config.ts
└── 📄 README.md
Linden Engine uses an Entity Component System architecture for optimal performance and flexibility.
// 🎮 Entities = Containers for components
const player = new Entity('Player')
// 📦 Components = Data containers
player.addComponent(new Transform())
player.addComponent(new MeshRenderer('character.gltf'))
player.addComponent(new RigidBody())
player.addComponent(new BlueprintComponent(playerBlueprint))
// ⚙️ Systems = Logic that operates on entities
world.addSystem(new PhysicsSystem())
world.addSystem(new RenderSystem())
world.addSystem(new ScriptSystem())Benefits of ECS:
- 🚀 High performance through data-oriented design
- 🔧 Flexible composition over inheritance
- 🎯 Easy to add/remove features at runtime
- 📊 Cache-friendly memory layout
┌─────────────┐
│ Initialize │ Load renderer, create world, init systems
└──────┬──────┘
│
┌──────▼──────┐
│ Start │ Execute BeginPlay events
└──────┬──────┘
│
┌──────▼──────┐
│ Update Loop │ ◄───┐
│ │ │
│ - Physics │ │
│ - Scripts │ │ 60 FPS
│ - Rendering│ │
│ - Input │ │
└──────┬──────┘ │
│ │
└─────────────┘
│
┌──────▼──────┐
│ Stop │ Cleanup, save state
└──────┬──────┘
│
┌──────▼──────┐
│ Dispose │ Free resources
└─────────────┘
export class GameScript implements IGameScript {
// 🎬 Called once during initialization
async onInit(context: ScriptContext) {
console.log('Script initialized')
}
// 🔄 Called every frame (~60 FPS)
onUpdate(deltaTime: number) {
// Game logic here
}
// ⚙️ Called at fixed intervals (for physics)
onFixedUpdate(deltaTime: number) {
// Physics calculations here
}
// 🧹 Called when script is destroyed
onDestroy() {
console.log('Cleanup')
}
// 🔥 Hot reload support!
async onReload(context: ScriptContext) {
// Reinitialize after code changes
}
}Blueprints allow you to create game logic visually without writing code. Perfect for designers, artists, and anyone who wants to prototype quickly!
- Select an entity in the Hierarchy
- Add Blueprint Component from the Inspector
- Click "Edit Blueprint" to open the editor
- Drag nodes from the palette to the canvas
- Connect nodes by dragging from output pins to input pins
- Test immediately by clicking Play
| Category | Nodes | Color |
|---|---|---|
| Events | BeginPlay, Tick, Input, Collision | 🔴 Red |
| Flow Control | Branch, Sequence, Loop, Delay, Gate | 🔵 Blue |
| Math | Add, Subtract, Multiply, Divide, Lerp | 🟡 Yellow |
| Comparison | Equal, Greater, Less | 🟢 Green |
| Actions | Print, Spawn, Destroy, Move, Rotate | 🟣 Purple |
| Variables | Get, Set | 🟢 Green |
[Event Tick]
│ exec
▼
[Get Axis Value (Horizontal)]
│ float
▼
[Multiply: Speed]
│ float
▼
[Add Movement Input]
Create stunning visuals with our node-based material editor — similar to Unreal Engine's Material Editor or Unity's Shader Graph.
- PBR Materials: Albedo, Metallic, Roughness, Normal maps
- Math Operations: Add, Multiply, Lerp, Clamp
- Texture Sampling: UV mapping, tiling, offset
- Vertex Manipulation: Displace, morph, animate
- Real-time Preview: See changes instantly
[Time] ──> [Sine] ──> [Multiply: 0.1] ──> [Vertex Offset]
│
▼
[Base Color] ──> [Lerp] ──> [Output]
▲
│
[Fresnel: Edge Color]
Create character animations with a state machine animator — similar to Unity's Animator or Unreal's Animation Blueprint.
- State Machine: Define animation states and transitions
- Blend Trees: Smooth blending between animations
- Parameters: Boolean, Float, Integer, Trigger
- Conditions: Control transitions with logic
- Animation Events: Trigger code at specific frames
┌──────┐
│ Idle │ ◄─────────────────┐
└───┬──┘ │
│ Speed > 0 │ Speed = 0
▼ │
┌──────────┐ │
│ Running │ ──────────────┘
└──────────┘
│ Jump Trigger
▼
┌──────────┐
│ Jumping │
└──────────┘
Create cinematic sequences and cutscenes with our timeline-based sequencer — similar to Unreal's Sequencer or Unity's Timeline.
- Timeline Editor: Drag and arrange keyframes
- Multiple Tracks: Transform, Animation, Audio, Events
- Keyframe Animation: Animate any property over time
- Camera Cuts: Switch between cameras
- Audio Sync: Sync animations to music/sound effects
Track 1 (Camera): [Dolly In] ────────────────> [Pan to Character]
Track 2 (Character): [Idle] ──> [Wave Animation] ──────────────────>
Track 3 (Audio): [Music Start] ──────────────> [Fade Out]
Track 4 (Events): [TriggerDialogue] ────────────> [EndCutscene]
For advanced users, Linden Engine supports full TypeScript scripting with hot-reload and type safety.
import { IGameScript, ScriptContext } from '@engine/scripting/ScriptSystem'
import { Vector3Utils } from '@engine/utils/index'
export class PlayerController implements IGameScript {
private speed = 5
private jumpForce = 10
private isGrounded = false
async onInit(context: ScriptContext) {
console.log('Player initialized!')
}
onUpdate(deltaTime: number) {
const input = this.getInput()
// Calculate movement
const moveDirection = Vector3Utils.normalize({
x: input.horizontal,
y: 0,
z: input.vertical
})
// Apply movement
const rigidbody = context.entity.getComponent('RigidBody')
if (rigidbody) {
rigidbody.velocity = Vector3Utils.multiply(
moveDirection,
this.speed
)
}
// Jump
if (input.jump && this.isGrounded) {
rigidbody?.applyForce({ x: 0, y: this.jumpForce, z: 0 })
this.isGrounded = false
}
}
onDestroy() {
console.log('Player destroyed')
}
private getInput() {
return {
horizontal: 0,
vertical: 0,
jump: false
}
}
}import { Entity } from '@engine/ecs/Entity'
import { PlayerController } from './PlayerController'
const player = new Entity('Player')
player.addComponent(new ScriptComponent(PlayerController))Extend Linden Engine with custom plugins! Add new components, systems, editors, and more.
import { EnginePlugin } from '@engine/core/Plugin'
import { LindenEngine } from '@engine/core/Engine'
export class MyAwesomePlugin implements EnginePlugin {
name = 'MyAwesomePlugin'
version = '1.0.0'
async onLoad(engine: LindenEngine) {
console.log('🔌 Plugin loaded!')
// Register custom components
engine.registerComponent('MyComponent', MyComponent)
// Register custom systems
engine.registerSystem('MySystem', MySystem)
}
async onUnload(engine: LindenEngine) {
console.log('🔌 Plugin unloaded!')
}
registerComponents() {
return [MyComponent, AnotherComponent]
}
registerSystems() {
return [MySystem]
}
}import { LindenEngine } from '@engine/core/Engine'
import { MyAwesomePlugin } from './plugins/MyAwesomePlugin'
const engine = new LindenEngine()
await engine.loadPlugin(new MyAwesomePlugin())import { LindenEngine } from '@engine/core/Engine'
const engine = new LindenEngine({
canvas: document.getElementById('viewport'),
width: 1920,
height: 1080,
useWebGPU: true
})
// Initialize engine
await engine.initialize()
// Start game loop
engine.start()
// Pause execution
engine.pause()
// Resume execution
engine.resume()
// Stop engine
engine.stop()
// Cleanup resources
engine.dispose()// Get the world (contains all entities)
const world = engine.getWorld()
// Get the renderer
const renderer = engine.getRenderer()
// Get performance monitor
const monitor = engine.getPerformanceMonitor()
// Get input system
const input = engine.getInputSystem()import { Entity } from '@engine/ecs/Entity'
import { Transform } from '@engine/ecs/Component'
// Create entity
const player = new Entity('Player')
// Get/set transform
const transform = player.getTransform()
transform.position = { x: 0, y: 0, z: 0 }
transform.rotation = { x: 0, y: 90, z: 0 }
transform.scale = { x: 1, y: 1, z: 1 }
// Add to world
world.addEntity(player)// Add component
const meshRenderer = player.addComponent(new MeshRenderer())
// Get component
const rigidbody = player.getComponent('RigidBody')
// Check if component exists
if (player.hasComponent('Collider')) {
// Do something
}
// Remove component
player.removeComponent('OldComponent')
// Get all components
const allComponents = player.getComponents()| Component | Description |
|---|---|
Transform |
Position, rotation, scale |
MeshRenderer |
3D mesh rendering |
Camera |
Camera view and projection |
Light |
Directional, point, spot lights |
RigidBody |
Physics simulation |
Collider |
Collision detection |
AudioSource |
3D positional audio |
BlueprintComponent |
Visual scripting |
import { World } from '@engine/ecs/World'
const world = new World()
// Add entity
world.addEntity(entity)
// Get entity by ID
const entity = world.getEntity('entity-id-123')
// Get all entities
const allEntities = world.getEntities()
// Find entities with specific components
const renderables = world.getEntitiesWithComponents('Transform', 'MeshRenderer')
// Remove entity
world.removeEntity('entity-id-123')import { System } from '@engine/ecs/System'
import { World } from '@engine/ecs/World'
export class RotationSystem extends System {
name = 'RotationSystem'
onUpdate(world: World, deltaTime: number) {
// Get all entities with Transform
const entities = world.getEntitiesWithComponents('Transform')
for (const entity of entities) {
const transform = entity.getComponent('Transform')
// Rotate on Y-axis
transform.rotation.y += 45 * deltaTime
}
}
}
// Register system
world.addSystem(new RotationSystem())Monitor your game's performance in real-time:
const monitor = engine.getPerformanceMonitor()
// Get current FPS
const fps = monitor.getFPS()
// Get average FPS
const avgFps = monitor.getAverageFPS()
// Measure specific code
monitor.startMeasure('physics')
// ... physics code here
const elapsed = monitor.endMeasure('physics')
console.log(`Physics took ${elapsed}ms`)
// Print all stats
monitor.printStats()Output:
Performance Stats:
FPS: 60.00 (avg: 59.83)
Frame Time: 16.67ms
Physics: 2.34ms
Rendering: 8.12ms
Scripts: 1.45ms
Linden Engine is actively developed. Here's what's coming:
- ECS architecture foundation
- WebGPU renderer with Three.js fallback
- Professional editor UI (Hierarchy, Inspector, Viewport)
- Blueprint visual scripting system
- Material node editor
- Animator state machine
- Sequencer timeline editor
- TypeScript scripting with hot-reload
- Electron desktop app
- Asset import pipeline (GLTF, FBX, OBJ)
- Physics engine (Rapier integration)
- Audio system (3D positional audio)
- Particle system
- UI Canvas system
- Input management (keyboard, mouse, gamepad)
- Terrain system
- Networking (WebSocket multiplayer)
- Build export wizard
- Scene serialization/deserialization
- Prefab system
- Undo/Redo system
- Mobile support (iOS, Android)
- Visual shader editor
- Advanced post-processing effects
- Lua scripting support
- Marketplace for assets and plugins
- Cloud collaboration
- AI-powered tools
Want to contribute? See our Contributing Guide below!
We welcome contributions from everyone! Whether you're fixing bugs, adding features, improving docs, or sharing ideas — your help is appreciated.
- Report bugs - Open an issue with reproduction steps
- Suggest features - Share your ideas in Discussions
- Fix bugs - Submit a PR with a bug fix
- Add features - Implement new features (check Roadmap first)
- Improve docs - Fix typos, add examples, write guides
- Share feedback - Let us know what you think!
-
Fork the repository
Click the "Fork" button on GitHub
-
Clone your fork
git clone https://github.com/YOUR_USERNAME/LindenEngine.git cd LindenEngine -
Create a branch
git checkout -b feature/my-awesome-feature
-
Make your changes
- Write clean, documented code
- Follow existing code style
- Add tests if applicable
- Update documentation
-
Test your changes
npm run dev npm run build
-
Commit your changes
git add . git commit -m "Add awesome feature"
-
Push to your fork
git push origin feature/my-awesome-feature
-
Create a Pull Request
Go to the original repo and click "New Pull Request"
- Use TypeScript for all new code
- Follow ESLint and Prettier rules
- Use meaningful variable names
- Add JSDoc comments for public APIs
- Keep functions small and focused
- Write tests for new features
type(scope): brief description
Longer description if needed...
Fixes #123
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code formattingrefactor: Code restructuringtest: Adding testschore: Maintenance tasks
Example:
feat(blueprints): add delay node
Added a Delay node to the Blueprint editor that pauses
execution for a specified duration.
Closes #45
Join our growing community!
- Discord - Chat with other developers (coming soon)
- GitHub Discussions - Ask questions, share projects
- Twitter - Follow for updates (coming soon)
- YouTube - Tutorials and devlogs (coming soon)
Be respectful, inclusive, and kind. We're all here to learn and build cool things together!
Linden Engine is licensed under the MIT License.
You're free to:
- ✅ Use commercially
- ✅ Modify the source code
- ✅ Distribute
- ✅ Use privately
See LICENSE file for full details.
Linden Engine wouldn't be possible without these amazing open-source projects:
- Three.js - 3D rendering library
- React - UI framework
- Electron - Desktop app framework
- TypeScript - Type-safe JavaScript
- Vite - Build tool
- Tailwind CSS - Styling framework
- Zustand - State management
Special thanks to:
- Unreal Engine & Unity - For inspiration
- Three.js community - For excellent 3D web tools
- All contributors - For making this project better!
Is Linden Engine free?
Yes! Linden Engine is completely free and open-source under the MIT License. You can use it for personal or commercial projects.
What platforms can I build for?
Currently:
- Desktop (Windows, macOS, Linux)
- Web (HTML5)
Coming soon:
- Mobile (iOS, Android)
Can I use Linden Engine for commercial games?
Absolutely! The MIT License allows commercial use without any royalties or fees.
How does it compare to Unity/Unreal?
Pros:
- Lightweight and fast
- Web-first architecture
- Easy to extend with TypeScript
- No installation size bloat
Cons:
- Still in alpha (fewer features)
- Smaller ecosystem
- Not as battle-tested
Linden Engine is perfect for:
- Web games
- Prototyping
- Learning game development
- Small to medium projects
Can I contribute even if I'm a beginner?
Yes! We welcome contributions from developers of all skill levels. Start with:
- Fixing typos in documentation
- Reporting bugs
- Suggesting features
- Sharing your projects
Get Started Now | Read the Docs | Join Discord
Made with ❤️ by the Linden Engine community