From 5e7abfb56b1b855643fe7de84e09fe395792f407 Mon Sep 17 00:00:00 2001 From: Arek Date: Sun, 8 Nov 2026 14:30:09 +0100 Subject: [PATCH] docs: add input-and-placement OpenSpec change and update AGENTS.md Plan input handling and pattern placement before Game of Life mechanics: keyboard bindings config, mouse placement with preview/rotation, HiDPI scaling, and cell grid. Update AGENTS.md project notes. --- AGENTS.md | 53 +++--------- openspec/changes/archive/.gitkeep | 0 .../input-and-placement/.openspec.yaml | 2 + .../changes/input-and-placement/design.md | 80 +++++++++++++++++++ .../changes/input-and-placement/proposal.md | 34 ++++++++ .../specs/cell-grid/spec.md | 62 ++++++++++++++ .../specs/display-scaling/spec.md | 45 +++++++++++ .../specs/keyboard-bindings/spec.md | 60 ++++++++++++++ .../specs/pattern-placement/spec.md | 61 ++++++++++++++ openspec/changes/input-and-placement/tasks.md | 47 +++++++++++ openspec/config.yaml | 32 ++++++++ openspec/specs/.gitkeep | 0 12 files changed, 436 insertions(+), 40 deletions(-) create mode 100644 openspec/changes/archive/.gitkeep create mode 100644 openspec/changes/input-and-placement/.openspec.yaml create mode 100644 openspec/changes/input-and-placement/design.md create mode 100644 openspec/changes/input-and-placement/proposal.md create mode 100644 openspec/changes/input-and-placement/specs/cell-grid/spec.md create mode 100644 openspec/changes/input-and-placement/specs/display-scaling/spec.md create mode 100644 openspec/changes/input-and-placement/specs/keyboard-bindings/spec.md create mode 100644 openspec/changes/input-and-placement/specs/pattern-placement/spec.md create mode 100644 openspec/changes/input-and-placement/tasks.md create mode 100644 openspec/config.yaml create mode 100644 openspec/specs/.gitkeep diff --git a/AGENTS.md b/AGENTS.md index aa5639b..e7d683e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,49 +1,22 @@ # wlgol -Simple Wayland Game of Life in C11. Draws directly into a shared-memory buffer (no OpenGL/Vulkan). +Wayland Game of Life in C11; renders into a shared-memory buffer (no GL/Vulkan). -- Build definition: `CMakeLists.txt` -- Generated code: `xdg-shell.xml` is vendored; `wayland-scanner` produces `xdg-shell.h` and `xdg-shell.c` inside `build/` -- Source layout: `wlgol.c` is the entry point; `tkeyboard.c`, `tpointer.c`, `hashtable.c` are modules; headers live in `include/`; tests live in `tests/` +## Build & test -## Dependencies +- Configure: `cmake -G Ninja -B build` +- Build: `cmake --build ./build` +- Tests: `ctest --test-dir build` (single target `Hashtable`); or run `./build/test_hashtable` +- Run app: `./build/wlgol` (requires a running Wayland compositor; not runnable headless) -Needs `cmake`, `ninja`, `pkg-config`, `wayland-scanner`, plus the runtime libraries `wayland-client`, `wayland-cursor`, and `xkbcommon`. +Dependencies: `cmake`, `ninja`, `pkg-config`, `wayland-scanner`; libraries `wayland-client`, `wayland-cursor`, `xkbcommon`. -## Common commands +## Generated code -Configure (from repo root): +- `xdg-shell.h` / `xdg-shell.c` are generated by `wayland-scanner` from the vendored `xdg-shell.xml` into `build/include/` and `build/`. Do not edit them; rebuild to regenerate. `CMakeLists.txt` lists the generated `.c` in `SOURCES` and the `.h` as a source to force generation. +- `compile_commands.json` at the repo root is a symlink to `build/compile_commands.json`; configure first. -```bash -cmake -G Ninja -B build -``` - -Build: - -```bash -cmake --build ./build -``` - -Run tests: - -```bash -ctest --test-dir build -``` - -Run a single test directly: - -```bash -./build/test_hashtable -``` - -Run the program (requires a running Wayland compositor): - -```bash -./build/wlgol -``` - -## Notes - -- `compile_commands.json` is generated automatically in the build directory because `CMAKE_EXPORT_COMPILE_COMMANDS` is set in `CMakeLists.txt`. -- The project currently has one CTest target named `Hashtable`. +## Code notes +- Hashtable: `hashtable_new(size)` requires `size > 0` (used as a modulo). `hashtable_destroy` frees keys/entries but not values (caller owns values). `hashtable_set` returns the previous value or `NULL`, indistinguishable from "key absent". +- Entry point is `wlgol.c`; modules `tkeyboard.c`, `tpointer.c`, `hashtable.c`; headers in `include/`. diff --git a/openspec/changes/archive/.gitkeep b/openspec/changes/archive/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/openspec/changes/input-and-placement/.openspec.yaml b/openspec/changes/input-and-placement/.openspec.yaml new file mode 100644 index 0000000..c0ad5ed --- /dev/null +++ b/openspec/changes/input-and-placement/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-11-08 diff --git a/openspec/changes/input-and-placement/design.md b/openspec/changes/input-and-placement/design.md new file mode 100644 index 0000000..e3e6374 --- /dev/null +++ b/openspec/changes/input-and-placement/design.md @@ -0,0 +1,80 @@ +# Design + +## Context + +Current application (`wlgol.c`) renders an animated stripe pattern into a fixed 400x400 shm buffer, handles only Escape, and ignores configure size and output scale. Input modules (`tkeyboard`, `tpointer`) exist but pointer motion/buttons are unimplemented and keyboard callbacks do not carry modifiers. HiDPI is unsupported. See `proposal.md` for motivation. + +## Goals / Non-Goals + +**Goals:** +- Configurable, modifier-aware key bindings with TOML merge over defaults. +- Interactive pattern placement with preview, rotation, click placement, cancellation. +- HiDPI-correct rendering (fractional and integer). +- Cell grid storage/rendering with resize preservation and wall boundaries. + +**Non-Goals:** +- Game of Life simulation rules (future change). +- Text rendering/HUD (status via stdout). +- Persistent grid save/load. +- Fractional scaling on compositors lacking the protocol beyond integer fallback. + +## Decisions + +### D1: TOML config via vendored `tomlc99` +- **Choice:** Vendor `tomlc99` (single .c/.h) for parsing `~/.config/wlgol/keys.conf`. +- **Rationale:** User requested TOML; no system TOML library available; vendoring avoids new system dependency. +- **Alternative:** Hand-rolled subset parser (less code, but TOML edge cases and maintenance burden). + +### D2: Binding representation +- **Choice:** Store bindings as array of `{mods_mask, keysym, action}`. Lookup by exact modifier mask (ignoring lock mods) and keysym on key press. +- **Rationale:** Simple, fast enough for single-threaded event loop. +- **Alternative:** Hash table keyed by (mods, keysym) — premature; linear scan over ~20 bindings is trivial. + +### D3: Keyboard callback carries modifiers +- **Choice:** Extend `keyboard_key_handler_t` to `(..., uint32_t mods, void *user_data)`, computed in `tkeyboard.c` from xkb state. +- **Rationale:** Binding matching needs modifier state; centralizes xkb modifier queries. + +### D4: HiDPI via fractional scale + viewporter +- **Choice:** Prefer `wp_fractional_scale_v1`; render physical buffer = ceil(logical * scale); set buffer_scale=1 and `wp_viewport` destination = logical size. Fallback to `wl_output.scale` integer (treat as scale value). +- **Rationale:** Exact fractional scaling; unifies rendering path through viewporter. +- **Alternative:** Integer-only scaling (simpler but blurry/wrong at 125%/150%). + +### D5: Logical canvas and grid +- **Choice:** Logical surface size from xdg configure (default 400x400). Grid dimensions = logical / 8. Cell size in logical pixels fixed at 8. +- **Rationale:** Consistent interaction across scales; HiDPI keeps physical cell size proportional. + +### D6: Grid storage and resize +- **Choice:** `struct grid { int cols, rows; unsigned char *cells; }` (0/1). On resize, allocate new buffer, copy overlapping region, free old. +- **Rationale:** Preserves user work on window resize; simple. + +### D7: Pattern definitions and rotation +- **Choice:** Each pattern stores base cell offsets and a rotation (0..3). Transform offsets at use time; bounding box computed from transformed offsets. Anchor = top-left of bounding box at cursor cell. +- **Rationale:** Avoids duplicating 4 variants per pattern; rotation stays consistent. + +### D8: Placement state machine +- **Choice:** States `IDLE` and `ARMED`. Key select → ARMED; motion updates preview cell; rotate increments rotation; left click places if in-bounds (stays ARMED); Escape → IDLE. +- **Rationale:** Matches requested UX; tool remains active for repeated placement. + +### D9: Protocols generation +- **Choice:** Vendor/copy `viewporter.xml` and `fractional-scale-v1.xml` into repo (from system wayland-protocols) and generate headers/sources via wayland-scanner in CMake, mirroring xdg-shell. +- **Rationale:** Reproducible builds without depending on system protocol paths. + +## Risks / Trade-offs + +- [Fractional scaling complexity] → Mitigation: isolate in `scale.c`; integer fallback ensures basic functionality. +- [Resize resets grid partially] → Mitigation: preserve overlapping region; document behavior. +- [tomlc99 vendoring licensing] → Mitigation: verify license (MIT) before commit. +- [No font rendering] → Status via stdout; acceptable for this change. +- [Placement near edges] → Mitigation: reject invalid placement; preview indicates invalid state (e.g., red tint). + +## Migration Plan + +1. Add generated protocol files and CMake changes. +2. Vendor tomlc99. +3. Implement modules and integrate into wlgol.c. +4. Update tests (hashtable unchanged; add config/grid unit tests if feasible). +5. Run ctest and build. + +## Open Questions + +None — all blocking decisions resolved during exploration. \ No newline at end of file diff --git a/openspec/changes/input-and-placement/proposal.md b/openspec/changes/input-and-placement/proposal.md new file mode 100644 index 0000000..c5860ad --- /dev/null +++ b/openspec/changes/input-and-placement/proposal.md @@ -0,0 +1,34 @@ +# Proposal + +## Why + +wlgol currently renders an animated stripe pattern and has no Game of Life state, no input handling beyond Escape, and no HiDPI awareness. Before implementing the automaton, the application needs a usable interaction layer: configurable keyboard bindings, mouse-driven placement of patterns with a live preview, and rendering that stays crisp on scaled displays. This change establishes that layer so later GoL mechanics can build on it. + +## What Changes + +- Add configurable keyboard bindings loaded from `~/.config/wlgol/keys.conf` (TOML), merged over built-in defaults, with modifier-aware matching (Ctrl/Shift/Alt/Super). +- Extend keyboard handling to report active modifiers and dispatch bound actions (`quit`, `cancel`, `rotate`, `select:`, `clear`, `pause`, `step`, `speed_up`, `speed_down`, `toggle_grid`). +- Implement mouse tracking and click handling: selecting a tool shows a rotating preview that follows the cursor; `Space` rotates 90°; left click places the pattern (tool stays armed); `Esc` cancels. +- Add a cell grid (8 logical px per cell, wall boundary) with storage, resize-with-preserve, and rendering of alive cells. +- Add four built-in patterns (Glider, Blinker, Block, Toad) with rotation support. +- Add HiDPI scaling (fractional via `wp_fractional_scale` + `wp_viewporter`, fallback to `wl_output.scale`) with logical/physical coordinate conversion. +- Auto-generate a default `keys.conf` on first run if missing. + +## Capabilities + +### New Capabilities + +- `keyboard-bindings`: configurable, modifier-aware key-to-action mapping with defaults and TOML override. +- `pattern-placement`: tool selection, live preview, rotation, click placement, cancellation. +- `display-scaling`: fractional and integer HiDPI scaling with logical/physical conversion. +- `cell-grid`: grid storage, resize handling, wall boundary, alive-cell rendering. + +### Modified Capabilities + +None. + +## Impact + +- Affected code: `wlgol.c`, `tkeyboard.c/h`, `tpointer.c/h`; new modules `config`, `grid`, `pattern`, `scale`, `render`. +- New dependency: vendored `tomlc99` for TOML parsing; generated Wayland protocols `viewporter` and `fractional-scale-v1`. +- Config I/O under `~/.config/wlgol/`; no public API changes. \ No newline at end of file diff --git a/openspec/changes/input-and-placement/specs/cell-grid/spec.md b/openspec/changes/input-and-placement/specs/cell-grid/spec.md new file mode 100644 index 0000000..3e47953 --- /dev/null +++ b/openspec/changes/input-and-placement/specs/cell-grid/spec.md @@ -0,0 +1,62 @@ +# Spec Delta + +## Purpose + +Stores and renders the Game of Life cell grid with a fixed cell size and wall boundaries, independent of future simulation rules. + +## ADDED Requirements + +### Requirement: Grid stores alive and dead cells +The system SHALL maintain a grid of cells, each either alive or dead, addressable by column and row. + +#### Scenario: Cell access +- **WHEN** a cell is set to alive +- **THEN** reading that cell returns alive +- **AND** cells never set remain dead + +### Requirement: Boundary cells are treated as dead +The system SHALL treat any cell outside the grid bounds as dead and shall not store state outside the grid. + +#### Scenario: Out of bounds read +- **WHEN** a cell position outside the grid is queried +- **THEN** the result is dead + +### Requirement: Grid resizes while preserving overlapping cells +The system SHALL preserve cells that remain within bounds when the grid dimensions change, clearing only cells that fall outside the new bounds. + +#### Scenario: Enlarge grid +- **WHEN** the grid grows in either dimension +- **THEN** previously alive cells within the old bounds remain alive + +#### Scenario: Shrink grid +- **WHEN** the grid shrinks in either dimension +- **THEN** cells outside the new bounds are discarded +- **AND** remaining cells keep their state + +### Requirement: Cell size is fixed in logical pixels +The system SHALL use a cell size of 8 logical pixels, so grid dimensions derive from the logical surface size. + +#### Scenario: Dimension calculation +- **WHEN** the logical surface is 400 pixels wide +- **THEN** the grid has 50 columns + +### Requirement: Alive cells are rendered +The system SHALL render alive cells distinctly from dead cells. + +#### Scenario: Render alive cell +- **WHEN** a cell is alive +- **THEN** it is drawn with the alive cell color + +### Requirement: Grid can be cleared +The system SHALL set all cells to dead when the clear action is triggered. + +#### Scenario: Clear grid +- **WHEN** the user triggers the clear action +- **THEN** all cells become dead + +### Requirement: Grid lines can be toggled +The system SHALL show or hide grid lines when the toggle_grid action is triggered. + +#### Scenario: Toggle lines +- **WHEN** the user triggers the toggle_grid action +- **THEN** grid line visibility flips \ No newline at end of file diff --git a/openspec/changes/input-and-placement/specs/display-scaling/spec.md b/openspec/changes/input-and-placement/specs/display-scaling/spec.md new file mode 100644 index 0000000..c21dcef --- /dev/null +++ b/openspec/changes/input-and-placement/specs/display-scaling/spec.md @@ -0,0 +1,45 @@ +# Spec Delta + +## Purpose + +Keeps the application rendering crisp on displays with integer or fractional scaling by converting between logical and physical coordinates. + +## ADDED Requirements + +### Requirement: Fractional scale is applied when available +The system SHALL use the compositor-provided fractional preferred scale for rendering when the fractional scale protocol is available. + +#### Scenario: Fractional display +- **WHEN** the compositor sends a preferred scale of 1.5 +- **THEN** the render buffer is created at 1.5 times the logical size +- **AND** the buffer is displayed at the logical size + +### Requirement: Integer scale is used as fallback +The system SHALL use the output's integer scale when fractional scale is unavailable. + +#### Scenario: No fractional protocol +- **WHEN** the compositor does not support fractional scaling +- **THEN** the render buffer uses the output integer scale +- **AND** the buffer is displayed at the logical size + +### Requirement: Input coordinates remain logical +The system SHALL report mouse positions and grid cells in logical coordinates regardless of the active scale. + +#### Scenario: Scaled click +- **WHEN** the user clicks on a scaled display +- **THEN** the selected grid cell matches the visual location of the cursor + +### Requirement: Rendering uses physical resolution +The system SHALL render all content at physical resolution so that lines and cells stay sharp at the active scale. + +#### Scenario: Sharp cells +- **WHEN** the application runs on a 2x scaled display +- **THEN** cells are drawn with 2 physical pixels per logical pixel + +### Requirement: Scale changes trigger re-render +The system SHALL recreate buffers and re-render when the active scale changes. + +#### Scenario: Scale change +- **WHEN** the compositor changes the preferred scale +- **THEN** the application updates its buffers +- **AND** subsequent frames use the new scale \ No newline at end of file diff --git a/openspec/changes/input-and-placement/specs/keyboard-bindings/spec.md b/openspec/changes/input-and-placement/specs/keyboard-bindings/spec.md new file mode 100644 index 0000000..ed6db22 --- /dev/null +++ b/openspec/changes/input-and-placement/specs/keyboard-bindings/spec.md @@ -0,0 +1,60 @@ +# Spec Delta + +## Purpose + +Allows users to configure keyboard shortcuts that map key combinations to application actions, with sensible built-in defaults when no configuration file exists. + +## ADDED Requirements + +### Requirement: Default bindings are available without configuration +The system SHALL provide built-in default bindings for all documented actions, including digits 1-4 selecting the Glider, Blinker, Block, and Toad patterns, Space rotating, Escape cancelling, and Ctrl+Q quitting. + +#### Scenario: No config file present +- **WHEN** the application starts and `~/.config/wlgol/keys.conf` does not exist +- **THEN** the application uses the built-in default bindings +- **AND** creates the config file with the default contents + +### Requirement: Configuration file overrides defaults by merge +The system SHALL read `~/.config/wlgol/keys.conf` as TOML when it exists and merge its entries over the built-in defaults, so only specified keys change. + +#### Scenario: Partial override +- **WHEN** the config file defines a binding for key "1" only +- **THEN** key "1" uses the configured action +- **AND** all other keys keep their default bindings + +#### Scenario: Full replacement of a key +- **WHEN** the config file defines a binding for a key that has a default +- **THEN** the configured action replaces the default for that key + +### Requirement: Key combinations are modifier-aware +The system SHALL match a binding only when the modifiers required by the binding are active, supporting Ctrl, Shift, Alt, and Super. + +#### Scenario: Modifier required +- **WHEN** the user presses Q while Ctrl is held and a `ctrl+q = quit` binding exists +- **THEN** the quit action is triggered + +#### Scenario: Modifier not held +- **WHEN** the user presses Q without Ctrl while a `ctrl+q = quit` binding exists +- **THEN** the quit action is not triggered by that binding + +### Requirement: Readable key aliases are supported +The system SHALL accept human-readable key names such as space, escape, enter, and arrow names in binding keys. + +#### Scenario: Alias binding +- **WHEN** the config file contains `space = rotate` +- **THEN** pressing the space bar triggers the rotate action + +### Requirement: Malformed entries are ignored +The system SHALL ignore malformed or unrecognized binding entries and continue using defaults for the affected keys. + +#### Scenario: Invalid entry +- **WHEN** the config file contains an entry with an unknown action +- **THEN** that entry is ignored +- **AND** the application still starts successfully + +### Requirement: Actions trigger on key press +The system SHALL dispatch a bound action when the corresponding key is pressed, not on release. + +#### Scenario: Press triggers action +- **WHEN** the user presses a key with a valid binding +- **THEN** the bound action is invoked once for that press \ No newline at end of file diff --git a/openspec/changes/input-and-placement/specs/pattern-placement/spec.md b/openspec/changes/input-and-placement/specs/pattern-placement/spec.md new file mode 100644 index 0000000..2b41e51 --- /dev/null +++ b/openspec/changes/input-and-placement/specs/pattern-placement/spec.md @@ -0,0 +1,61 @@ +# Spec Delta + +## Purpose + +Lets users select a Game of Life pattern, preview it under the mouse cursor, rotate it, and place copies on the grid with a click. + +## ADDED Requirements + +### Requirement: Selecting a pattern arms a placement tool +The system SHALL activate a placement tool for the selected pattern when a `select:` action is triggered, and show a preview following the cursor. + +#### Scenario: Tool activation +- **WHEN** the user triggers `select:glider` +- **THEN** a glider preview appears at the current cursor position +- **AND** the placement tool remains active + +### Requirement: Preview follows cursor motion +The system SHALL update the preview position to track the current mouse cursor cell while a tool is active. + +#### Scenario: Mouse moves +- **WHEN** the user moves the mouse while a tool is active +- **THEN** the preview moves to the cell under the cursor + +### Requirement: Tool can be rotated in 90-degree steps +The system SHALL rotate the active preview by 90 degrees each time the rotate action is triggered. + +#### Scenario: Rotate preview +- **WHEN** the user triggers the rotate action while a tool is active +- **THEN** the preview rotates 90 degrees clockwise +- **AND** remains at the same anchor cell + +### Requirement: Left click places the pattern when valid +The system SHALL write the active pattern's alive cells into the grid at the preview position when the user left-clicks and the pattern fits entirely within the grid. + +#### Scenario: Valid placement +- **WHEN** the user left-clicks while a tool is active and the preview fits in the grid +- **THEN** the pattern's cells become alive in the grid +- **AND** the tool remains active for further placement + +### Requirement: Invalid placement is rejected +The system SHALL not modify the grid when a left click occurs while the preview extends outside the grid. + +#### Scenario: Out of bounds +- **WHEN** the user left-clicks while the preview extends outside the grid +- **THEN** no cells are changed +- **AND** the tool remains active + +### Requirement: Escape cancels the active tool +The system SHALL deactivate the placement tool and remove the preview when the cancel action is triggered. + +#### Scenario: Cancel placement +- **WHEN** the user triggers the cancel action while a tool is active +- **THEN** the preview disappears +- **AND** no further clicks place a pattern until a tool is selected again + +### Requirement: Click without active tool does nothing +The system SHALL ignore left clicks when no placement tool is active. + +#### Scenario: No tool +- **WHEN** the user left-clicks while no tool is active +- **THEN** the grid is unchanged \ No newline at end of file diff --git a/openspec/changes/input-and-placement/tasks.md b/openspec/changes/input-and-placement/tasks.md new file mode 100644 index 0000000..92923a3 --- /dev/null +++ b/openspec/changes/input-and-placement/tasks.md @@ -0,0 +1,47 @@ +# Tasks + +## 1. Protocol generation and build setup + +- [ ] 1.1 Vendor `viewporter.xml` and `fractional-scale-v1.xml` into the repo and add wayland-scanner custom commands in `CMakeLists.txt`, verifying headers generate under `build/include`. +- [ ] 1.2 Add `tomlc99.c`/`tomlc99.h` to the source tree and CMake sources, verifying the project still configures and builds. + +## 2. Configuration module + +- [ ] 2.1 Implement `config.c/h` to load or auto-create `~/.config/wlgol/keys.conf`, parse TOML bindings, and merge with built-in defaults, verifying a sample file round-trips. +- [ ] 2.2 Implement binding string parsing (modifiers + key aliases) and lookup by modifier mask and keysym, verifying unit tests cover merge and modifier matching. + +## 3. Keyboard module + +- [ ] 3.1 Extend `keyboard_key_handler_t` to pass a modifier mask and update `tkeyboard.c` to compute it from xkb state, verifying compilation of all callers. +- [ ] 3.2 Wire keyboard events to config-based binding lookup and action dispatch, verifying Escape and Ctrl+Q trigger their actions. + +## 4. Pointer module + +- [ ] 4.1 Track logical cursor position in `tpointer.c/h` from motion events, verifying position updates on move. +- [ ] 4.2 Dispatch left-click events to the placement controller, verifying clicks are received. + +## 5. Grid module + +- [ ] 5.1 Implement `grid.c/h` with storage, bounds checks, resize-with-preserve, clear, and toggle state, verifying unit tests for resize and bounds. +- [ ] 5.2 Expose grid dimensions derived from logical surface size at 8 px per cell, verifying dimensions update on resize. + +## 6. Pattern module + +- [ ] 6.1 Implement `pattern.c/h` with Glider, Blinker, Block, and Toad offsets and 90-degree rotation transform, verifying rotated offsets and bounds. +- [ ] 6.2 Implement placement validity check (pattern fits within grid), verifying in-bounds and out-of-bounds cases. + +## 7. Scaling module + +- [ ] 7.1 Implement `scale.c/h` to bind fractional scale and viewporter, compute physical buffer size, and convert coordinates, verifying scale changes update buffer size. +- [ ] 7.2 Implement integer-scale fallback via `wl_output`, verifying fallback path builds without fractional protocol. + +## 8. Rendering and application integration + +- [ ] 8.1 Refactor `wlgol.c` to use logical surface size, create scaled shm buffers, and render grid plus alive cells, verifying build succeeds. +- [ ] 8.2 Add placement controller state machine (IDLE/ARMED), preview rendering, rotation, click placement, and cancellation, verifying behavior by manual run. +- [ ] 8.3 Integrate config loading, default file creation, and action dispatch into startup, verifying default config is generated. + +## 9. Verification + +- [ ] 9.1 Build with CMake/Ninja and run `ctest --test-dir build`, verifying all tests pass. +- [ ] 9.2 Run `./build/wlgol` under a Wayland compositor and manually verify placement, rotation, HiDPI scaling, and Esc cancellation. \ No newline at end of file diff --git a/openspec/config.yaml b/openspec/config.yaml new file mode 100644 index 0000000..2805cb6 --- /dev/null +++ b/openspec/config.yaml @@ -0,0 +1,32 @@ +schema: spec-driven + +# Project context (optional) +# Add only constraints that should guide OpenSpec artifacts and workflows. +# Include constraints an agent cannot infer by reading the code. +# Keep general project documentation and discoverable codebase facts out. +# Example: +# context: | +# Designs and tasks must cover Windows, macOS, and Linux +# Write all artifacts in Spanish + +# Per-artifact rules (optional) +# Add custom rules for specific artifacts. +# Example: +# rules: +# proposal: +# - Keep proposals under 500 words +# - Always state what is out of scope +# tasks: +# - Break tasks into chunks of max 2 hours + +# Per-operation guidance (optional) +# Add advisory guidance for how apply and archive work should be conducted. +# This is separate from artifact rules above. +# Example: +# operations: +# apply: +# guidance: +# - Keep test summaries concise +# archive: +# guidance: +# - Summarize the archive outcome before finishing diff --git a/openspec/specs/.gitkeep b/openspec/specs/.gitkeep new file mode 100644 index 0000000..e69de29