From e627f0097f78f3c8239b97f34f2c1b6e2aff1dcc Mon Sep 17 00:00:00 2001 From: Axel Meyer Date: Tue, 9 Jun 2026 13:57:20 +0000 Subject: [PATCH] =?UTF-8?q?initial:=20actor=20v0.1.0=20=E2=80=94=20composi?= =?UTF-8?q?tion-wrapper=20+=20movement-speed-contract?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase-A.5 implementation per sporel-meta/docs/superpowers/specs/2026-06-09-phase-A-... Re-Entry from P.0-Actor-Deferral (Trigger 1: Composition-Aktivierung). Slim wrapper: actor.create validates properties.movement_speed > 0, delegates to composition.create. actor.position reads dotted position back as two numbers. actor.move does direct inert-write to position.x + position.y (engine §11 inert-write; Action-routing deferred). DEFERRED in v0.1: Body-Slot-Aggregator, Walk-Capability, Movement-State on entity, Action-mediated move. All have re-entry-trigger notes. Co-Authored-By: Claude Opus 4.7 (1M context) --- LICENSE | 24 ++++++++++ README.md | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++ init.lua | 86 +++++++++++++++++++++++++++++++++ manifest.lib | 1 + 4 files changed, 243 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 init.lua create mode 100644 manifest.lib diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..81c9d65 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2026 Calic. All rights reserved. + +This software is part of the Sporel platform — **Tier 1 (Official / +Proprietary)** content per the Three-Tier Licensing Model documented in +`meta/docs/archive/design/vision.md §Licensing Model` (current source; +migration to `meta/docs/architecture/licensing-model.md` pending). + +⚠ **WIP — Legal review required before public launch.** The terms below +reflect design intent only; the formalized license framework will be +finalized through legal counsel before the first public release. Until +then, this notice serves as a placeholder defending the platform owner's +rights against unintentional re-licensing. + +No license is granted to copy, modify, distribute, sublicense, or otherwise +use this software in any form without prior written permission from the +copyright holder. + +References: +- Tier 1 (this file): all rights reserved, proprietary, sold/distributed + via official channels (Steam, etc.) +- Tier 2 (Semi-Commercial Co-Development): bilateral contracts, revenue- + share — see vision.md §Licensing Model +- Tier 3 (Community Content): CC BY-NC-SA 4.0 + asymmetric CLA — applies + to community-uploaded libs/modules/assets, not this repo diff --git a/README.md b/README.md new file mode 100644 index 0000000..030f2de --- /dev/null +++ b/README.md @@ -0,0 +1,132 @@ +# lib-core.actor + +Thin wrapper over `lib-core.composition` that enforces a baseline-speed +contract for "actor" entities. Provides convenience helpers for +position-read + position-write (inert-mediated). Doesn't track any +ephemeral movement-state (vel/dir) — that stays in `player_control` +or whatever drives the actor each frame. + +**Version:** 0.1.0 +**Lib-ID:** lib-core.actor +**Requires:** lib-core.composition v>=0.1.0 +**Tags:** actor, entity, movement + +## Topology + + +```mermaid +graph LR + this["lib-core.actor"] + lib_core_composition["lib-core.composition"] + this --> lib_core_composition + engine["engine.*"] + this --> engine +``` + + +## Scope (v0.1.0 — Spine) + +Re-Entry from P.0-Actor-Deferral (Trigger 1: Composition-Aktivierung). +v0.1 is a minimal slice; intentional non-goals: + +- **No Body-Slot-Aggregator.** Phase D / J trigger. +- **No Walk-Capability** (per ADR-0002 capabilities-as-derived). + Waits for a second actor-consumer that needs capability-routing. +- **No Movement-State on the entity.** vel / dir / direction-flags are + ephemeral; kept in `player_control` (or whatever driver). Persisted + ones come with a re-entry-trigger. +- **No Action-mediated move.** v0.1 uses engine-§11 inert-write directly. + Action-routing is the "right" path for game-state-weighty mutations + but waits until a "move" Action is registered and event/effect + routing matters. + +## API + +### `actor.create(spec)` + +**Syntax:** `actor.create({template: string, properties: table}) -> entity` + +**Example:** +```lua +-- Caller defines a template via composition first: +composition.define_template{ + id = "player", + properties = { + position = {x = 0, y = 0}, + movement_speed = 200, + sprite_color = engine.render.rgb(200, 60, 80), + sprite_w = 24, + sprite_h = 24, + }, + tags = {"renderable", "player"}, +} + +-- Then actor.create instantiates: +local p = actor.create{ + template = "player", + properties = { + position = {x = 400, y = 300}, + movement_speed = 200, + }, +} +``` + +**Description:** Validates that `properties.movement_speed` is a +positive number, then delegates to `composition.create`. Loud-Error +if `movement_speed` is missing, non-number, or non-positive. + +The caller is responsible for `composition.define_template{id=...}` +before invoking. Actor doesn't auto-define templates. + +### `actor.position(handle)` + +**Syntax:** `actor.position(handle) -> x, y` + +**Description:** Returns the actor's current position as two numbers +(x, y). Reads via `entity:get_property("position.x"/"position.y")`. +Loud-Error if `handle` is nil. + +### `actor.move(handle, dx, dy)` + +**Syntax:** `actor.move(handle, dx: number, dy: number) -> void` + +**Example:** +```lua +-- Typical caller (player_control update-loop): +local speed = actor.movement_speed(player) +local move_dx, move_dy = compute_input_direction() +actor.move(player, move_dx * speed * dt, move_dy * speed * dt) +``` + +**Description:** Adds (dx, dy) to the actor's current position via +direct inert-write. Caller does dt-scaling and any speed-multiplication +upstream. v0.1 uses engine §11 inert-write — Action-routing is a future +re-entry trigger (see Scope above). + +### `actor.movement_speed(handle)` + +**Syntax:** `actor.movement_speed(handle) -> number` + +**Description:** Convenience read of the actor's `movement_speed` +property (in pixels/sec by convention; caller decides the unit). + +## Conventions + +- **Position-Format**: composite-table at authoring-time + (`properties = { position = {x, y} }`), flattened by composition to + scalar properties `position.x` and `position.y`. See Phase-A Spec §5 + A-Q5 revision (2026-06-09). +- **movement_speed**: pixels per second. dt-scaling applied at the + caller, NOT by `actor.move`. + +## References + +- Spec: `meta/docs/superpowers/specs/2026-06-09-phase-A-inactive-entities-composition-actor-reentry-design.md` +- Origin: `meta/docs/superpowers/specs/2026-05-10-p0-actor-deferral.md` + (Trigger 1: Composition-Aktivierung) +- Architecture: `meta/docs/architecture/composition-model.md` (Actor as + Item-with-Body-Slot in Phase D; v0.1 is composition-only wrapper) +- ADR-0001 (engine knows verbs, libs bring nouns) +- ADR-0002 (capabilities as derived properties — Walk-Capability deferred) +- ADR-0010 (read/write asymmetry — v0.1 inert-write escape hatch) +- ADR-0038 (API-Doc-Convention) diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..3b89590 --- /dev/null +++ b/init.lua @@ -0,0 +1,86 @@ +-- ===================================================================== +-- lib-core.actor v0.1.0 — Position + Movement-Speed wrapper over composition +-- See: meta/docs/superpowers/specs/2026-06-09-phase-A-inactive-entities-... +-- +-- v0.1.0 Spine-Cut: +-- - actor.create(spec) — validates 'properties.movement_speed' is set +-- (positive number) then delegates to composition.create. Caller is +-- responsible for composition.define_template{id=