docs: migrate README to API-Doc-Convention (S2-cascade.libs)
Restructured per ADR-0038: Abstract + bold-list Badges + Topology H2 + H3-API-Subsections (one per public function) + Conventions/Consumer pattern/CHANGELOG/References. Topology auto-populated via Sporel.exe --lint --fix. Pre-commit hook installed via --install-hooks. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
13
.githooks/pre-commit
Normal file
13
.githooks/pre-commit
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
# Sporel API-Doc-Convention pre-commit hook.
|
||||
SPOREL_EXE="${SPOREL_EXE:-$(command -v Sporel.exe 2>/dev/null || command -v sporel 2>/dev/null)}"
|
||||
if [ -z "$SPOREL_EXE" ]; then
|
||||
echo "INFO: Sporel.exe not on PATH. Skipping lint." >&2
|
||||
exit 0
|
||||
fi
|
||||
"$SPOREL_EXE" --lint="$(pwd)" --fix
|
||||
RC=$?
|
||||
if git diff --cached --name-only | grep -qx 'README.md'; then
|
||||
git add README.md
|
||||
fi
|
||||
exit $RC
|
||||
131
README.md
131
README.md
@@ -1,45 +1,111 @@
|
||||
# lib-core.player_control
|
||||
|
||||
P.0 player movement lib. Single player with top-left position + size +
|
||||
speed. Reads input direction via `lib-core.input`, applies 4-corner-AABB
|
||||
collision against `lib-core.maps.is_walkable`, all-or-nothing block
|
||||
(no wall-sliding).
|
||||
Single-player movement lib. Top-left position + size + speed, reads input-direction via `lib-core.input`, applies 4-corner-AABB collision against `lib-core.maps.is_walkable`. All-or-nothing block (no wall-sliding in v0.1.0).
|
||||
|
||||
- Lib-ID: `lib-core.player_control`
|
||||
- Version: `0.1.0`
|
||||
- Spec: `meta/docs/superpowers/specs/2026-05-09-p0-lib-player_control-design.md`
|
||||
**Version:** 0.1.0
|
||||
**Lib-ID:** lib-core.player_control
|
||||
**Requires:** lib-core.maps v>=0.1.1, lib-core.input v>=0.4.0
|
||||
**Tags:** player, movement, aabb, collision
|
||||
|
||||
Forward-compat stubs (DEPRECATED-MVP) for wall-sliding, actor-integration,
|
||||
sprite-rendering, click-to-move, drag-select, animation, velocity/momentum,
|
||||
walls-collision, multi-player.
|
||||
## Topology
|
||||
|
||||
<!-- topology:start (auto-generated; do not edit) -->
|
||||
```mermaid
|
||||
graph LR
|
||||
this["lib-core.player_control"]
|
||||
lib_core_maps["lib-core.maps"]
|
||||
this --> lib_core_maps
|
||||
lib_core_input["lib-core.input"]
|
||||
this --> lib_core_input
|
||||
engine["engine.*"]
|
||||
this --> engine
|
||||
```
|
||||
<!-- topology:end -->
|
||||
|
||||
## API
|
||||
- `player.set_position(x, y)` — top-left, pixel-coords
|
||||
- `player.position() → {x, y}` — top-left
|
||||
- `player.set_size(w, h)` — bounding box (default 24x24)
|
||||
- `player.size() → {w, h}`
|
||||
- `player.set_speed(px_per_sec)` — default 200
|
||||
- `player.speed() → number`
|
||||
- `player.bind_movement(left_action, right_action, up_action, down_action)`
|
||||
- `player.update(dt)` — reads bound actions, predicts next pos, AABB-collision-check, mutates position
|
||||
|
||||
### `player.set_position(x, y)`
|
||||
**Syntax:** `player.set_position(x: number, y: number) -> void`
|
||||
|
||||
**Example:**
|
||||
```lua
|
||||
player.set_position(244, 244)
|
||||
```
|
||||
|
||||
**Description:** Sets the player's top-left position in pixel-coords. Lua `error(...)` on non-number args.
|
||||
|
||||
### `player.position()`
|
||||
**Syntax:** `player.position() -> {x: number, y: number}`
|
||||
|
||||
**Description:** Returns the current top-left position. Compute center as `p.x + size.w/2`, `p.y + size.h/2`.
|
||||
|
||||
### `player.set_size(w, h)`
|
||||
**Syntax:** `player.set_size(w: number, h: number) -> void`
|
||||
|
||||
**Description:** Sets the AABB bounding-box size in pixels. Default 24x24.
|
||||
|
||||
### `player.size()`
|
||||
**Syntax:** `player.size() -> {w: number, h: number}`
|
||||
|
||||
**Description:** Returns current bounding-box size.
|
||||
|
||||
### `player.set_speed(s)`
|
||||
**Syntax:** `player.set_speed(s: number) -> void`
|
||||
|
||||
**Description:** Sets move-speed in px/sec. Default 200.
|
||||
|
||||
### `player.speed()`
|
||||
**Syntax:** `player.speed() -> number`
|
||||
|
||||
**Description:** Returns current speed.
|
||||
|
||||
### `player.bind_movement(left, right, up, down)`
|
||||
**Syntax:** `player.bind_movement(left: string, right: string, up: string, down: string) -> void`
|
||||
|
||||
**Example:**
|
||||
```lua
|
||||
input.bind("move_left", { "a", "left" })
|
||||
input.bind("move_right", { "d", "right" })
|
||||
input.bind("move_up", { "w", "up" })
|
||||
input.bind("move_down", { "s", "down" })
|
||||
player.bind_movement("move_left", "move_right", "move_up", "move_down")
|
||||
```
|
||||
|
||||
**Description:** Registers 4 input-action names for the player's WASD-style direction. Until called, `update(dt)` is a silent no-op.
|
||||
|
||||
### `player.update(dt)`
|
||||
**Syntax:** `player.update(dt: number) -> void`
|
||||
|
||||
**Example:**
|
||||
```lua
|
||||
function update(ctx, dt)
|
||||
player.update(dt)
|
||||
end
|
||||
```
|
||||
|
||||
**Description:** Reads bound actions, computes direction-vector via `lib-core.input.direction`, predicts next position, runs 4-corner-AABB walkability check against the current map, and mutates position only if all corners walkable (all-or-nothing block; no wall-sliding in v0.1.0). Silent no-op until `bind_movement` is called.
|
||||
|
||||
## Conventions
|
||||
- Position is top-left corner of player AABB (matches engine.render.draw_rect).
|
||||
|
||||
- Position is top-left of the AABB (matches `engine.render.draw_rect` origin).
|
||||
- Center calculation lives in caller: `cx = position.x + size.w/2`.
|
||||
- All-or-nothing block on collision (no wall-sliding in P.0).
|
||||
- Module owns rendering (lib has no draw fn). Module composes camera-follow.
|
||||
- All-or-nothing block on collision (no wall-sliding in v0.1.0).
|
||||
- Module owns rendering (lib has no `draw` fn). Module composes camera-follow.
|
||||
- Silent no-op for `update()` before `bind_movement` (debug-friendly).
|
||||
- Lua `error(...)` for setter misuse (caller-bug fast-fail).
|
||||
- Y-down-positive per ADR-0031.
|
||||
|
||||
## Consumer pattern
|
||||
|
||||
```lua
|
||||
local player = require("lib-core.player_control")
|
||||
local input = require("lib-core.input")
|
||||
local camera = require("lib-core.camera")
|
||||
|
||||
input.bind("move_left", { engine.input.KEY_A, engine.input.KEY_LEFT })
|
||||
input.bind("move_right", { engine.input.KEY_D, engine.input.KEY_RIGHT })
|
||||
input.bind("move_up", { engine.input.KEY_W, engine.input.KEY_UP })
|
||||
input.bind("move_down", { engine.input.KEY_S, engine.input.KEY_DOWN })
|
||||
input.bind("move_left", { "a", "left" })
|
||||
input.bind("move_right", { "d", "right" })
|
||||
input.bind("move_up", { "w", "up" })
|
||||
input.bind("move_down", { "s", "down" })
|
||||
|
||||
player.set_position(244, 244)
|
||||
player.bind_movement("move_left", "move_right", "move_up", "move_down")
|
||||
@@ -48,13 +114,24 @@ function update(ctx, dt)
|
||||
player.update(dt)
|
||||
local p = player.position()
|
||||
local s = player.size()
|
||||
camera.set_target(p.x + s.w/2, p.y + s.h/2) -- camera follows player center
|
||||
camera.set_target(p.x + s.w/2, p.y + s.h/2)
|
||||
end
|
||||
|
||||
function render(ctx)
|
||||
-- draw map first, then player on top
|
||||
local p = player.position()
|
||||
local s = player.size()
|
||||
engine.render.draw_rect(p.x, p.y, s.w, s.h, engine.render.rgb(200, 60, 80))
|
||||
end
|
||||
```
|
||||
|
||||
## CHANGELOG
|
||||
|
||||
### v0.1.0 (P.0)
|
||||
- Initial release: position/size/speed + bind_movement + per-frame update with 4-corner-AABB collision.
|
||||
|
||||
## References
|
||||
|
||||
- Spec v0.1.0 (P.0): `meta/docs/superpowers/specs/2026-05-09-p0-lib-player_control-design.md`
|
||||
- ADR-0001 (engine knows verbs, libs bring nouns)
|
||||
- ADR-0031 (pixel-convention: Y-down-positive)
|
||||
- ADR-0038 (API-Doc-Convention)
|
||||
|
||||
3
scripts/install-hooks.sh
Normal file
3
scripts/install-hooks.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
git config core.hooksPath .githooks
|
||||
echo "Hooks activated."
|
||||
Reference in New Issue
Block a user