⚠️ Strict Architecture Rules - READ THIS FIRST
🚨 CRITICAL: Layer Hierarchy Must Be Respected
This is not a suggestion. This is a requirement.
CASCADA Framework enforces strict one-way dependency flow. Breaking these rules will:
- ❌ Break the entire architecture
- ❌ Make Core systems unusable in other projects
- ❌ Create circular dependencies
- ❌ Prevent extracting Core as pnpm package
📐 The Three Layers
┌─────────────────────────────────┐
│ PLATFORM (Base) │ ← Phaser configuration ONLY
│ • No game logic │
│ • No UI components │
│ • Just Phaser setup │
└─────────────┬───────────────────┘
│ uses ↓
┌─────────────▼───────────────────┐
│ CORE (Reusable Systems) │ ← Universal, game-agnostic
│ • UIManager, VueUIBridge │
│ • GameModeManager │
│ • ViewportManager │
│ • Can be extracted as package │
└─────────────┬───────────────────┘
│ uses ↓
┌─────────────▼───────────────────┐
│ GAME (Your Game Logic) │ ← Specific to LINX or your game
│ • LINX territory logic │
│ • Game-specific scenes │
│ • Game-specific UI │
└─────────────────────────────────┘Dependency flow is ONE-WAY only:
GAME → uses CORE → uses PLATFORM✅ ALLOWED Import Patterns
In PLATFORM Layer
// ✅ ALLOWED - External dependencies
import Phaser from "phaser";
import { Game } from "phaser";
// ❌ FORBIDDEN - Cannot import from Core
import { UIManager } from "@core/ui/UIManager"; // ❌ NO!
// ❌ FORBIDDEN - Cannot import from Game
import { TerritoryScene } from "@game/scenes/TerritoryScene"; // ❌ NO!PLATFORM knows nothing about Core or Game existence.
In CORE Layer
// ✅ ALLOWED - External dependencies
import Phaser from "phaser";
import { reactive } from "vue";
// ✅ ALLOWED - Platform imports
import { baseConfig } from "@platform/base.config";
// ✅ ALLOWED - Other Core modules
import { UIManager } from "@core/ui/UIManager";
import { GameModeManager } from "@core/systems/GameModeManager";
// ❌ FORBIDDEN - Cannot import from Game
import { TerritoryScene } from "@game/scenes/TerritoryScene"; // ❌ NO!
import { LINX_CONFIG } from "@game/config/game.config"; // ❌ NO!CORE knows about Platform, but NOT about Game.
In GAME Layer
// ✅ ALLOWED - Everything!
import Phaser from "phaser";
import { baseConfig } from "@platform/base.config";
import { UIManager } from "@core/ui/UIManager";
import { VueUIBridge } from "@core/ui/VueUIBridge";
import { GameModeManager } from "@core/systems/GameModeManager";
import { MyOtherScene } from "@game/scenes/MyOtherScene";
// Game can use Platform, Core, and other Game modulesGAME is the top layer - can use everything below.
🎯 Why This Matters
Reason 1: Core as npm Package
# Extract Core systems
cd src/core
pnpm init
pnpm publish @yourname/cascade-core
# Use in ANY Phaser game:
pnpm install @yourname/cascade-core
import { UIManager, VueUIBridge } from "@yourname/cascade-core";If Core imports from Game → cannot publish Core separately!
Reason 2: Testing Layers Independently
// Test Platform config (no Core/Game needed)
describe("Platform Config", () => {
it("should have correct Phaser settings", () => {
expect(baseConfig.type).toBe(Phaser.AUTO);
});
});
// Test Core systems (only Platform needed)
describe("UIManager", () => {
it("should register components", () => {
const manager = new UIManager(scene);
manager.register("test", element);
expect(manager.isVisible("test")).toBe(false);
});
});
// Test Game (uses Platform + Core)
describe("TerritoryScene", () => {
it("should create nodes", () => {
const scene = new TerritoryScene();
// ... uses Core systems
});
});Each layer tests independently = faster tests, easier debugging.
Reason 3: Multiple Games Share Core
my-games-monorepo/
├── packages/
│ ├── core/ ← Shared Core (UIManager, etc.)
│ ├── platform/ ← Shared Platform (Phaser config)
│ ├── game-rpg/ ← RPG game
│ ├── game-strategy/ ← Strategy game
│ └── game-puzzle/ ← Puzzle gameAll 3 games use SAME Core systems.
If Core imports from Game → cannot share!
🔍 How to Check Your Code
Run Dependency Check
# Check for violations
grep -r "@game" src/core/
grep -r "@core" src/platform/
# Should return NOTHING
# If returns results → YOU BROKE ARCHITECTURE!Visual Studio Code
Install extension: Dependency Cruiser
// .dependency-cruiser.js
module.exports = {
forbidden: [
{
name: 'platform-cannot-import-core',
from: { path: '^src/platform' },
to: { path: '^src/core' }
},
{
name: 'core-cannot-import-game',
from: { path: '^src/core' },
to: { path: '^src/game' }
},
{
name: 'platform-cannot-import-game',
from: { path: '^src/platform' },
to: { path: '^src/game' }
}
]
};📋 CASCADA Inheritance Pattern
Config CASCADA
// 1. PLATFORM defines base
// platform/base.config.ts
export const baseConfig = {
type: Phaser.AUTO,
width: 800,
height: 600,
physics: {
/* ... */
},
};
// 2. GAME extends platform
// game/config/game.config.ts
import { baseConfig } from "@platform/base.config";
export const gameConfig = {
...baseConfig, // ✅ Inherits from Platform
scene: [BootScene, GameScene],
// Game-specific additions
};
// ❌ WRONG - Platform extends Game
import { gameConfig } from "@game/config/game.config";
export const baseConfig = { ...gameConfig }; // NO!System CASCADA
// 1. CORE defines system
// core/ui/UIManager.ts
export class UIManager {
register(id: string, element: HTMLElement) {
// Universal UI management
}
}
// 2. GAME uses Core system
// game/scenes/MyScene.ts
import { UIManager } from "@core/ui/UIManager";
export class MyScene extends Phaser.Scene {
private uiManager = new UIManager(this); // ✅ Uses Core
}
// ❌ WRONG - Core uses Game
// core/ui/UIManager.ts
import { MyScene } from "@game/scenes/MyScene"; // NO!Data Flow CASCADA
User Input (GAME)
↓
UIManager (CORE)
↓
Phaser Scene (PLATFORM)
↓
Phaser Engine (DEPENDENCY)
ONE-WAY FLOW ONLY!🏗️ File Structure Enforcement
Required Structure
src/
├── platform/ ← Layer 1 (Base)
│ ├── base.config.ts
│ ├── game.config.ts
│ └── types/ ← Platform-specific types
│
├── core/ ← Layer 2 (Reusable)
│ ├── ui/
│ ├── systems/
│ ├── models/
│ ├── config/
│ ├── utils/
│ └── types/ ← Core-specific types
│
├── game/ ← Layer 3 (Specific)
│ ├── scenes/
│ ├── ui/
│ ├── config/
│ ├── core/
│ └── types/ ← Game-specific types
│
└── main.ts ← Entry pointNEVER put:
- ❌
src/types/- types belong IN their layers - ❌
src/utils/- utilities belong to Core - ❌
src/components/- UI belongs to Game - ❌
src/lib/- libraries belong to dependencies
🎯 Real Example: Adding New Feature
❌ WRONG WAY - Breaks Architecture
// You want to add "SaveManager"
// ❌ Put in Game layer
src/game/systems/SaveManager.ts
// ❌ Then use in Core
src/core/ui/UIManager.ts:
import { SaveManager } from "@game/systems/SaveManager"; // NO!
// RESULT: Core depends on Game → cannot extract Core!✅ RIGHT WAY - Respects Architecture
// 1. SaveManager is universal → Put in CORE
src/core/systems/SaveManager.ts
// 2. Core can use Core
src/core/ui/UIManager.ts:
import { SaveManager } from "@core/systems/SaveManager"; // ✅ YES!
// 3. Game can use Core
src/game/scenes/MyScene.ts:
import { SaveManager } from "@core/systems/SaveManager"; // ✅ YES!
// RESULT: Clean architecture, Core stays reusable!📊 Decision Tree: Where Does It Go?
Is it game-specific?
Is this code specific to LINX/your game?
YES → Put in GAME layer
├─ Territory mechanics
├─ LINX-specific UI
├─ Game config
└─ Game scenes
NO → Is it universal for any Phaser game?
↓
YES → Put in CORE layer
├─ UIManager (any game needs UI)
├─ EntityRegistry (any game has entities)
├─ GameModeManager (multi-scale is Core feature)
└─ SaveManager (any game can save)
NO → Is it pure Phaser setup?
↓
YES → Put in PLATFORM layer
├─ Phaser config
├─ Physics config
└─ Renderer settings🔧 Common Violations and Fixes
Violation 1: Shared Constants
// ❌ WRONG
// src/constants.ts (root level)
export const GAME_WIDTH = 800;
// PROBLEM: Where does this belong?
// Platform? Core? Game?FIX:
// ✅ RIGHT
// platform/base.config.ts
export const PLATFORM_CONSTANTS = {
DEFAULT_WIDTH: 800,
DEFAULT_HEIGHT: 600,
};
// core/config/constants.ts
export const CORE_CONSTANTS = {
UI_FADE_DURATION: 300,
MODE_TRANSITION: 500,
};
// game/config/game.config.ts
export const GAME_CONSTANTS = {
TERRITORY_SIZE: 50,
MAX_NODES: 100,
};Each layer has its own constants.
Violation 2: Type Sharing
// ❌ WRONG
// src/types/index.ts (root level)
export interface Player {
/* ... */
}
// core/systems/EntityRegistry.ts
import { Player } from "@/types"; // ❌ Where is @/types?FIX:
// ✅ RIGHT
// core/types/index.ts
export interface Entity {
/* Core entity */
}
// game/types/index.ts
export interface Player extends Entity {
/* Game player */
}
// core/systems/EntityRegistry.ts
import { Entity } from "@core/types"; // ✅ Core uses Core types
// game/scenes/GameScene.ts
import { Player } from "@game/types"; // ✅ Game uses Game types
import { Entity } from "@core/types"; // ✅ Game can use Core typesViolation 3: Utility Functions
// ❌ WRONG
// src/utils/math.ts (root level)
export function clamp(value: number, min: number, max: number) {
/* ... */
}FIX:
// ✅ RIGHT - Utility is universal → belongs to CORE
// core/utils/math.ts
export function clamp(value: number, min: number, max: number) {
return Math.max(min, Math.min(max, value));
}
// Any layer can import from Core utils
import { clamp } from "@core/utils/math";🎓 Learning the Pattern
Think Like This:
Question: Where do I put "PlayerInventory"?
Ask yourself:
1. Is it specific to my game?
YES → GAME layer ✅
Example: LINX has territories, not inventory
Another game has inventory
→ Inventory is game-specific → GAME layer
2. Could ANY game use it?
NO → GAME layer ✅
If inventory is specific to your RPG mechanics,
not every game needs inventory → GAME layerQuestion: Where do I put "SaveManager"?
Ask yourself:
1. Is it specific to my game?
NO → Not GAME layer
2. Could ANY game use it?
YES → CORE layer ✅
Every game can save data
→ SaveManager is universal → CORE layerQuestion: Where do I put "Phaser scale config"?
Ask yourself:
1. Is it specific to my game?
NO → Not GAME layer
2. Could ANY game use it?
YES, but it's Phaser setup, not game logic
→ PLATFORM layer ✅
Phaser configuration = PLATFORM responsibility📜 Architecture Contract
PLATFORM Promise
"I will provide Phaser configuration. Nothing more."
// platform/base.config.ts
export const baseConfig: Phaser.Types.Core.GameConfig = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: "game-container",
backgroundColor: "#000000",
scale: {
/* ... */
},
physics: {
/* ... */
},
};
// NO game logic
// NO UI components
// NO game-specific settings
// JUST Phaser setupCORE Promise
"I will provide universal systems that work in ANY Phaser game."
// core/ui/UIManager.ts
// Works in ANY game - RPG, Strategy, Puzzle, FPS
export class UIManager {
// Universal UI management
// No assumptions about game type
// No LINX-specific logic
// No territory-specific logic
}Test: Can I use UIManager in a completely different game?
- If YES → ✅ Correct
- If NO → ❌ Belongs in GAME layer
GAME Promise
"I will implement game-specific logic using Core and Platform."
// game/scenes/TerritoryGameScene.ts
import { UIManager } from "@core/ui/UIManager"; // ✅ Uses Core
import { baseConfig } from "@platform/base.config"; // ✅ Uses Platform
export class TerritoryGameScene extends Phaser.Scene {
// LINX-specific territory logic
// Uses Core systems (UIManager, GameModeManager)
// Extends Platform config
}🚨 Critical Don'ts
❌ DON'T: Cross-Layer Imports
// ❌ Platform imports Core
// platform/base.config.ts
import { UIManager } from "@core/ui/UIManager"; // BREAKS EVERYTHING!
// ❌ Core imports Game
// core/ui/UIManager.ts
import { TerritoryScene } from "@game/scenes/TerritoryScene"; // BREAKS EVERYTHING!
// ❌ Platform imports Game
// platform/base.config.ts
import { GAME_CONFIG } from "@game/config"; // BREAKS EVERYTHING!These violations make Core non-reusable.
❌ DON'T: Put Files in Wrong Layer
// ❌ Game-specific code in Core
// core/systems/TerritoryManager.ts ← Territory is LINX-specific!
// ✅ RIGHT
// game/territory/TerritoryManager.ts ← Game-specific belongs in Game
// ❌ Reusable code in Game
// game/utils/SaveManager.ts ← SaveManager is universal!
// ✅ RIGHT
// core/systems/SaveManager.ts ← Universal belongs in Core❌ DON'T: Create Root-Level Directories
src/
├── utils/ ← ❌ NO! Which layer?
├── types/ ← ❌ NO! Which layer?
├── components/ ← ❌ NO! Which layer?
├── lib/ ← ❌ NO! Which layer?
└── helpers/ ← ❌ NO! Which layer?Every file MUST belong to a layer.
src/
├── platform/types/ ← ✅ YES! Platform types
├── core/utils/ ← ✅ YES! Core utilities
├── game/components/ ← ✅ YES! Game components✅ Checklist Before Committing
Automated Checks (Recommended)
# Run architecture validator
pnpm check:architecture
# ✅ Passed → safe to commit
# ❌ Failed → shows exact violations with file:line
# Full lint (includes architecture + TypeScript)
pnpm lintPre-commit hook runs automatically:
- Git commit → hook runs
pnpm check:architecture - If violations → commit BLOCKED
- If clean → commit proceeds
Manual Checks (Alternative)
If you prefer manual validation:
# 1. No Platform → Core imports
grep -r "@core" src/platform/
# Should return: (nothing)
# 2. No Platform → Game imports
grep -r "@game" src/platform/
# Should return: (nothing)
# 3. No Core → Game imports
grep -r "@game" src/core/
# Should return: (nothing)
# 4. No root-level code
ls src/*.ts | grep -v "main.ts"
# Should return: (nothing except main.ts)If any check fails → FIX BEFORE COMMITTING!
ESLint Integration
ESLint config (eslint.config.js) enforces rules:
// Configured zones:
{
target: './src/platform',
from: './src/core', // ❌ Blocked
}
{
target: './src/core',
from: './src/game', // ❌ Blocked
}IDE integration:
- VS Code shows red squiggles on violations
- Real-time feedback while coding
- Fix before running/committing
🎯 Benefits of Strict Architecture
For Developers
✅ Clear mental model - always know where code belongs
✅ Easy testing - test layers independently
✅ Fast debugging - know which layer has the bug
✅ Safe refactoring - changes in Game don't break Core
For Projects
✅ Reusable Core - extract as pnpm package
✅ Multiple games - share Core between games
✅ Team scalability - different teams work on different layers
✅ Version control - layers can have independent versions
For Users
✅ Smaller bundles - only include needed layers
✅ Better performance - optimized layer loading
✅ Stable Core - Core updates don't break your game
✅ Community packages - use Core from others
📖 Further Reading
- Layer Hierarchy - Deep dive into architecture
- Architecture Overview - Design philosophy
- Project Structure - File organization
🚨 Summary: The Golden Rule
╔══════════════════════════════════════════════════════════╗
║ ║
║ PLATFORM → knows nothing ║
║ ║
║ CORE → knows Platform, not Game ║
║ ║
║ GAME → knows everything (Platform + Core) ║
║ ║
║ ONE-WAY DEPENDENCY FLOW: GAME → CORE → PLATFORM ║
║ ║
║ NEVER GO BACKWARDS! ║
║ ║
╚══════════════════════════════════════════════════════════╝Respect the layers. Respect the architecture. Build great games.
READ THIS BEFORE EVERY NEW FEATURE ⚠️