summaryrefslogtreecommitdiff
path: root/ARCHITECTURE_PLAN.md
blob: f2ec38ca26370a985a5d9b1b776e7bffcc9f980f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# YASL Modern Architecture Plan

This document outlines the transition of YASL to **Approach A: Inverted Lifecycle & Unified Event Architecture**, designed specifically to serve both high-performance game development and reactive desktop applications (IDEs and editors like `examples/notepad.c`).

---

## 1. Motivation & Core Goals

### The Problem in YASL 0.1
1. **Split-Brain Event Model**: Window lifecycle and drawing use callbacks, but input events are queued in a surface ring buffer requiring a manual `dispatch -> poll -> flush` pump.
2. **Platform Live-Resize Quirks**: On macOS (`inLiveResize`) and Wayland (`xdg_surface.configure`), drawing must be strictly synchronized to the OS event to avoid freezing, visual stutter, or black borders.
3. **Game vs. IDE Divergence**:
   - Games need continuous, VSync-paced ticks (60/120/144+ Hz) and direct GPU presentation (Metal/Vulkan).
   - IDEs need reactive, on-demand redraws (0% CPU when idle), rich text input (IME, UTF-8, autorepeat), multi-window support, and cross-thread communication (LSP/file watchers).
4. **Stack Overhead**: Presenting a CPU frame currently requires passing a 1,044-byte stack struct (`yasl_damage_list`).

---

## 2. Architecture Overview

```
┌────────────────────────────────────────────────────────┐
│  Layer 2: Specialized Helpers (Opt-in)                 │
│  - File Descriptor Watcher (LSP, Sockets, Pipes)       │
│  - Cross-Thread Event Dispatcher (yasl_post_event)     │
│  - Mouse Relative Mode (Pointer Lock for 3D/Games)     │
├────────────────────────────────────────────────────────┤
│  Layer 1: Unified App Runner (include/yasl/app.h)       │
│  - yasl_run(const struct yasl_app_desc *desc)          │
│  - Dual-mode pacing: YASL_PACING_CONTINUOUS vs ON_DEMAND│
│  - Decoupled frame target (CPU software vs GPU native) │
├────────────────────────────────────────────────────────┤
│  Layer 0: Core Native Surfaces & Dispatchers           │
│  - Wayland / X11 / Cocoa display & surface backends    │
└────────────────────────────────────────────────────────┘
```

---

## 3. Phased Execution Plan

### Phase 1: Define Public Interface (`include/yasl/app.h` & modernized types)
1. **Unified Event Pipeline (`yasl_event`)**:
   - Merge input and window events into a single enum:
     - `YASL_EVENT_KEY`, `YASL_EVENT_TEXT`
     - `YASL_EVENT_MOUSE_MOTION`, `YASL_EVENT_MOUSE_BUTTON`, `YASL_EVENT_MOUSE_SCROLL`
     - `YASL_EVENT_WINDOW_RESIZE`, `YASL_EVENT_WINDOW_SCALE_CHANGED`, `YASL_EVENT_WINDOW_CLOSE_REQUEST`, `YASL_EVENT_WINDOW_FOCUS`
     - `YASL_EVENT_USER` (custom payloads from background threads)
   - Add `bool repeat` to `yasl_key_event` to distinguish game keypresses from editor autorepeat.
2. **Dual-Target Frame Context (`yasl_frame_context`)**:
   - Provide `ctx->cpu` (software buffer) and `ctx->gpu` (native layer/surface).
   - Lightweight presentation: `yasl_frame_present_cpu(ctx, dirty_rects, count)` where `NULL` dirty rects indicate full presentation without a 1 KB stack structure.
3. **Pacing Modes**:
   - `YASL_PACING_CONTINUOUS`: Drives `frame()` every display refresh for games.
   - `YASL_PACING_ON_DEMAND`: Sleeps at 0% CPU when idle; wakes on events, timers, or `yasl_surface_request_frame()`.
4. **App Descriptor & Runner**:
   - Define `struct yasl_app_desc` with `init`, `event`, `frame`, and `quit`.
   - Declare `int yasl_run(const struct yasl_app_desc *desc);`.

### Phase 2: Implement Core Runner & Cross-Thread Messaging (`src/common/app.c`)
1. **The Lifecycle Pump (`yasl_run`)**:
   - Initialize display and event loop, invoke `desc->init()`.
   - Run the unified event loop:
     - Drain native inputs and dispatch clean `const yasl_event *` into `desc->event()`.
     - Automatically synchronize macOS live-resize (`inLiveResize`) and Wayland configure passes to call `desc->frame()`.
     - Regulate pacing: continuous ticks for games vs. reactive idle sleep for desktop apps.
2. **Cross-Thread Event Posting (`yasl_post_event`)**:
   - Implement thread-safe event enqueueing backed by a mutex-protected ringbuffer and loop wake pipe (`yasl_loop_kick`).
   - Allows background threads (LSP, compilers, physics, asset loaders) to post `YASL_EVENT_USER` safely to the main thread.

### Phase 3: Add Key Capabilities for Games & Desktop UI
1. **Relative Mouse Mode (`yasl_surface_set_mouse_mode`)**:
   - Implement `YASL_MOUSE_RELATIVE` (pointer lock / virtualized motion deltas) for games and 3D viewports.
2. **Background File Descriptor Watching (`yasl_app_watch_fd`)**:
   - Register pipes/sockets (e.g., LSP stdin/stdout) directly with the main loop.

### Phase 4: Verification, Examples & Testing
1. **`examples/game.c`**:
   - Continuous 60/144 FPS game loop, animated graphics, raw WASD input, and relative mouse control.
2. **`examples/notepad.c`**:
   - Comprehensive text editor example demonstrating YASL's capabilities:
     - Reactive rendering (0% CPU at idle, redrawing only when dirty).
     - UTF-8 text insertion, backspace, enter, and cursor navigation with autorepeat.
     - Blinking text caret driven by a timer.
     - Scale-aware text rendering and dynamic window resizing.
     - Background async task (e.g., word count / syntax check / LSP task) posting results via `yasl_post_event`.
3. **Automated Tests**:
   - Add test suites in `tests/` verifying `yasl_run`, event propagation, cross-thread posting, and pacing modes.
   - Verify all 18 existing backend tests pass without regressions.