GraphOS Skill: graph-world-pixijs
Develop the game presentation layer in the current workspace using TypeScript and PixiJS (interpreting your pixi.js request as PixiJS), and integrate with graph-world logic-layer rules.
Scope Boundary
- Implement presentation only (rendering, animation, camera, UI, visual input feedback, asset loading and display).
- Do not directly modify logic-layer artifacts such as World model, Context, Variant, System, Event, or EventSystem in this skill.
- If a request requires logic-layer changes, hand off to graph-world first, then continue presentation implementation.
- STRICT RULE: Never import or reference logic-layer source files directly (e.g.
src/ of the world package). All logic-layer access MUST go through graphos-world-client.
Logic Layer Access via graphos-world-client
All presentation code accesses the running logic layer exclusively through the graphos-world-client npm package. Direct imports from logic-layer source folders are forbidden.
Installation
npm install graphos-world-client
Standard Usage Pattern
import { Client } from 'graphos-world-client';
const client = new Client();
function update() {
for (const object of client.objects()) {
// Read object state and drive PixiJS rendering here
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
Object Types
- Object types returned by
client.objects() are defined in app/World.ts.
app/World.ts is auto-generated — do NOT modify it manually.
- Import types from
app/World.ts for TypeScript type safety in presentation code.
import type { SomeObjectType } from './World';
Rules
- Only read object state from
client.objects() inside the render loop; do not cache stale snapshots across frames unless intentionally diffing.
- Never call logic-layer APIs to mutate state from the presentation layer — mutation is the logic layer's responsibility.
- If
client.objects() does not expose a field you need, request the logic-layer change through graph-world first.
- Default to immediate-mode rendering for dynamic geometry: in each frame, clear PixiJS
Graphics and redraw based on current logic object state and object-to-object relationships.
- If per-object rendering resources are needed (for example sprite, graphics wrapper, text, animation handles), store them in
WeakMap<IObject, ResourceHandle> keyed by the logic object reference.
Lifecycle Events via Client
If presentation needs object lifecycle hooks (create/update/destroy), listen to Client events instead of introducing logic-layer coupling.
Available event classes from graphos-world-client:
export declare class SpawnEvent extends Event {
readonly object: IObject;
constructor(object: IObject);
}
export declare class DespawnEvent extends Event {
readonly object: IObject;
constructor(object: IObject);
}
export declare class ChangeEvent extends Event {
readonly object: IObject;
readonly changes: Partial<IObject>;
constructor(object: IObject, changes: Partial<IObject>);
}
Runtime event names are spawn, despawn, and change:
import { Client, SpawnEvent, DespawnEvent, ChangeEvent } from 'graphos-world-client';
const client = new Client();
client.addEventListener('spawn', (event) => {
const e = event as SpawnEvent;
// Initialize presentation resources for e.object if needed
});
client.addEventListener('change', (event) => {
const e = event as ChangeEvent;
// React to changed fields in e.changes
});
client.addEventListener('despawn', (event) => {
const e = event as DespawnEvent;
// Cleanup resources associated with e.object
});
Directory and Output Constraints
- Presentation source code must be under ./app/.
- Build output must be under ./dist/app/.
- Do not place presentation implementation into logic-layer folders or Graph generated folders.
When to Use
- You need to implement or refactor game visuals, scenes, character presentation, UI components, or effects.
- You need to map existing logic states to the visual layer.
- You need to improve rendering structure, performance, or maintainability without changing graph logic models.
Required Decision Routing
- First decide whether the task includes logic-layer changes.
- If yes: pause presentation coding and run graph-world first to complete logic updates and closed-loop verification.
- If no: continue this skill workflow.
- After logic updates are complete, return to this skill for presentation adaptation.
Workflow
Step 0: Task Split and Boundary Confirmation
- Split requirements into presentation requirements and logic requirements.
- Explicitly list read-only dependencies (available Context, Variant, Event) and open questions.
- Confirm this implementation touches only ./app/ plus minimal required build configuration.
Completion checks:
- It is clear whether graph-world must run first.
- In-scope and out-of-scope presentation items are explicit.
Step 1: Presentation Architecture Design (app only)
- Organize scene, view, component, and asset modules inside ./app/.
- Define a state-mapping layer that converts logic state to view state without introducing new business rules.
- Keep input handling presentation-only (for example button highlight and animation triggers), without adding business decisions.
Design requirements:
- Keep component responsibilities focused and avoid a monolithic scene class.
- Separate render update flow from data-mapping flow for testability and replacement.
- Use explicit TypeScript types for view models and rendering interfaces.
Completion checks:
- ./app/ has clear module layering.
- No logic-layer rules are implemented in presentation code.
Step 2: PixiJS + TypeScript Implementation
- Implement scene bootstrap, asset loading, render loop, and UI mounting.
- Access object state exclusively via
client.objects() from graphos-world-client. Never import from logic-layer source directories.
- Import object type definitions from
app/World.ts (auto-generated; read-only).
- Bind object state to PixiJS presentation objects (Sprite, Container, Graphics, UI components).
- Add necessary animation and transitions so state changes are visible and traceable.
- Keep presentation as a pure consumer: read state and render only, do not rewrite state-machine logic.
Library convention:
- This skill defaults to a PixiJS-based stack (compatible with your pixi.js wording).
- Logic-layer bridge:
graphos-world-client (Client class, client.objects() iterator).
Implementation requirements:
- Prefer composition over deep inheritance.
- Keep frame-update cost controlled and avoid creating repeated objects every frame.
- Add minimal and focused comments only on critical rendering paths.
- Use TypeScript types from
app/World.ts for all object state fields accessed in rendering.
- For relationship-heavy dynamic visuals, prefer a
Graphics.clear() + redraw flow per frame (immediate mode) over long-lived retained geometry.
- For retained PixiJS resources, associate objects and resources with
WeakMap so resources follow object lifecycle without manual ownership coupling.
- If lifecycle-level initialization or disposal is required, subscribe to
spawn / change / despawn events from Client.
Completion checks:
- Core presentation requirements run from ./app/.
- All logic-layer reads go through
graphos-world-client, not direct source imports.
- No new logic-layer entities or graph structure changes are introduced.
Step 3: Build and Output Verification
- Ensure build target outputs to ./dist/app/.
- Run build and verify output path, entry file, and asset references.
- If build pipeline conflicts with existing project settings, make minimal and scoped adjustments only.
Completion checks:
- Artifacts are generated in ./dist/app/.
- Non-presentation modules are not impacted.
Step 4: Integration and Regression Check
- Integrate using logic states provided by graph-world.
- Validate key scenarios: initialization, state transitions, event feedback, and fallback presentation.
- If new or changed logic state is required:
- Stop additional presentation patching.
- Record the contract gap and hand off to graph-world.
- Resume integration after logic updates are complete.
Completion checks:
- Presentation and logic contracts are aligned.
- Logic gaps are explicitly handed off and not bypassed in this skill.
Quality Criteria
- Correct boundary: presentation code does not carry business decisions.
- Correct paths: source in ./app/ and build output in ./dist/app/.
- Client-only access: all logic-layer state is read through
graphos-world-client; no direct imports from logic-layer source folders.
- Type safety: object types from
app/World.ts (auto-generated) are used throughout presentation code; app/World.ts is never modified.
- Rendering rule: immediate-mode redraw paths use PixiJS
Graphics clear-and-redraw based on current object state and relationships.
- Resource binding: object-scoped rendering resources may use
WeakMap<IObject, ...> and are cleaned up on despawn.
- Lifecycle hooks: lifecycle-sensitive presentation behavior listens to
Client events (spawn, change, despawn) with SpawnEvent / ChangeEvent / DespawnEvent typing.
- Contract alignment: naming and semantics are consistent with graph-world Context, Variant, and Event.
- Maintainability: clear modules, explicit typing, readable critical render paths.
- Verifiability: at least one successful build and key integration flow validation.
Failure Recovery
- Build fails: inspect TypeScript and asset paths in ./app/ first, then minimal build config.
client.objects() returns unexpected or missing fields: stop presentation patching, identify the missing contract, and hand off to graph-world to expose the field.
- Immediate-mode redraw performance degrades: keep immediate mode for dynamic links/relations, but move static layers to retained containers and profile draw-call hotspots.
- Lifecycle mismatch (missing init/cleanup timing): verify
spawn / change / despawn event wiring on Client before adding workaround state in presentation.
- Type mismatch on
app/World.ts types: re-read app/World.ts (do not edit it); adjust presentation code to match the generated types.
- Integration fails due to logic gap: immediately route back to decision step and hand off to graph-world.
- Requirement out of scope: split out-of-scope logic items into graph-world follow-up tasks, and deliver only feasible presentation work here.
Example Requests
- Use TypeScript + PixiJS in ./app to implement battle scene HUD and hit animation, without changing the logic layer.
- Refactor rendering layer to map existing player state to UI while keeping output in ./dist/app.
- I need one new state field for presentation usage first through graph-world, then continue presentation work.
- Render all objects from
client.objects() as PixiJS sprites, using types from app/World.ts.
Scope Migration
- This file is currently a repository-scoped skill at skills/graph-world-pixijs/SKILL.md.
- For personal global reuse, copy the same skill to a user skill directory, for example ~/.copilot/skills/graph-world-pixijs/SKILL.md or ~/.agents/skills/graph-world-pixijs/SKILL.md.
1---2name: graph-world-pixijs3description: TypeScript + PixiJS (pixi.js intent) game presentation workflow for GraphOS. Use when implementing rendering, UI, animation, scene composition, camera, and view-state binding in ./app with build output to ./dist/app. Depends on graph-world for any logic-layer or graph model changes.4---56# GraphOS Skill: graph-world-pixijs78Develop the game presentation layer in the current workspace using TypeScript and PixiJS (interpreting your pixi.js request as PixiJS), and integrate with graph-world logic-layer rules.910## Scope Boundary1112- Implement presentation only (rendering, animation, camera, UI, visual input feedback, asset loading and display).13- Do not directly modify logic-layer artifacts such as World model, Context, Variant, System, Event, or EventSystem in this skill.14- If a request requires logic-layer changes, hand off to graph-world first, then continue presentation implementation.15- **STRICT RULE: Never import or reference logic-layer source files directly (e.g. `src/` of the world package). All logic-layer access MUST go through `graphos-world-client`.**1617## Logic Layer Access via graphos-world-client1819All presentation code accesses the running logic layer exclusively through the `graphos-world-client` npm package. Direct imports from logic-layer source folders are forbidden.2021### Installation2223```bash24npm install graphos-world-client25```2627### Standard Usage Pattern2829```typescript30import { Client } from 'graphos-world-client';3132const client = new Client();3334function update() {35 for (const object of client.objects()) {36 // Read object state and drive PixiJS rendering here37 }38 requestAnimationFrame(update);39}4041requestAnimationFrame(update);42```4344### Object Types4546- Object types returned by `client.objects()` are defined in `app/World.ts`.47- `app/World.ts` is **auto-generated** — do NOT modify it manually.48- Import types from `app/World.ts` for TypeScript type safety in presentation code.4950```typescript51import type { SomeObjectType } from './World';52```5354### Rules55561. Only read object state from `client.objects()` inside the render loop; do not cache stale snapshots across frames unless intentionally diffing.572. Never call logic-layer APIs to mutate state from the presentation layer — mutation is the logic layer's responsibility.583. If `client.objects()` does not expose a field you need, request the logic-layer change through graph-world first.594. Default to immediate-mode rendering for dynamic geometry: in each frame, clear PixiJS `Graphics` and redraw based on current logic object state and object-to-object relationships.605. If per-object rendering resources are needed (for example sprite, graphics wrapper, text, animation handles), store them in `WeakMap<IObject, ResourceHandle>` keyed by the logic object reference.6162### Lifecycle Events via Client6364If presentation needs object lifecycle hooks (create/update/destroy), listen to `Client` events instead of introducing logic-layer coupling.6566Available event classes from `graphos-world-client`:6768```typescript69export declare class SpawnEvent extends Event {70 readonly object: IObject;71 constructor(object: IObject);72}73export declare class DespawnEvent extends Event {74 readonly object: IObject;75 constructor(object: IObject);76}77export declare class ChangeEvent extends Event {78 readonly object: IObject;79 readonly changes: Partial<IObject>;80 constructor(object: IObject, changes: Partial<IObject>);81}82```8384Runtime event names are `spawn`, `despawn`, and `change`:8586```typescript87import { Client, SpawnEvent, DespawnEvent, ChangeEvent } from 'graphos-world-client';8889const client = new Client();9091client.addEventListener('spawn', (event) => {92 const e = event as SpawnEvent;93 // Initialize presentation resources for e.object if needed94});9596client.addEventListener('change', (event) => {97 const e = event as ChangeEvent;98 // React to changed fields in e.changes99});100101client.addEventListener('despawn', (event) => {102 const e = event as DespawnEvent;103 // Cleanup resources associated with e.object104});105```106107## Directory and Output Constraints108109- Presentation source code must be under ./app/.110- Build output must be under ./dist/app/.111- Do not place presentation implementation into logic-layer folders or Graph generated folders.112113## When to Use114115- You need to implement or refactor game visuals, scenes, character presentation, UI components, or effects.116- You need to map existing logic states to the visual layer.117- You need to improve rendering structure, performance, or maintainability without changing graph logic models.118119## Required Decision Routing1201211. First decide whether the task includes logic-layer changes.122 - If yes: pause presentation coding and run graph-world first to complete logic updates and closed-loop verification.123 - If no: continue this skill workflow.1242. After logic updates are complete, return to this skill for presentation adaptation.125126## Workflow127128### Step 0: Task Split and Boundary Confirmation1291301. Split requirements into presentation requirements and logic requirements.1312. Explicitly list read-only dependencies (available Context, Variant, Event) and open questions.1323. Confirm this implementation touches only ./app/ plus minimal required build configuration.133134Completion checks:135- It is clear whether graph-world must run first.136- In-scope and out-of-scope presentation items are explicit.137138### Step 1: Presentation Architecture Design (app only)1391401. Organize scene, view, component, and asset modules inside ./app/.1412. Define a state-mapping layer that converts logic state to view state without introducing new business rules.1423. Keep input handling presentation-only (for example button highlight and animation triggers), without adding business decisions.143144Design requirements:145- Keep component responsibilities focused and avoid a monolithic scene class.146- Separate render update flow from data-mapping flow for testability and replacement.147- Use explicit TypeScript types for view models and rendering interfaces.148149Completion checks:150- ./app/ has clear module layering.151- No logic-layer rules are implemented in presentation code.152153### Step 2: PixiJS + TypeScript Implementation1541551. Implement scene bootstrap, asset loading, render loop, and UI mounting.1562. Access object state exclusively via `client.objects()` from `graphos-world-client`. Never import from logic-layer source directories.1573. Import object type definitions from `app/World.ts` (auto-generated; read-only).1584. Bind object state to PixiJS presentation objects (Sprite, Container, Graphics, UI components).1595. Add necessary animation and transitions so state changes are visible and traceable.1606. Keep presentation as a pure consumer: read state and render only, do not rewrite state-machine logic.161162Library convention:163- This skill defaults to a PixiJS-based stack (compatible with your pixi.js wording).164- Logic-layer bridge: `graphos-world-client` (`Client` class, `client.objects()` iterator).165166Implementation requirements:167- Prefer composition over deep inheritance.168- Keep frame-update cost controlled and avoid creating repeated objects every frame.169- Add minimal and focused comments only on critical rendering paths.170- Use TypeScript types from `app/World.ts` for all object state fields accessed in rendering.171- For relationship-heavy dynamic visuals, prefer a `Graphics.clear()` + redraw flow per frame (immediate mode) over long-lived retained geometry.172- For retained PixiJS resources, associate objects and resources with `WeakMap` so resources follow object lifecycle without manual ownership coupling.173- If lifecycle-level initialization or disposal is required, subscribe to `spawn` / `change` / `despawn` events from `Client`.174175Completion checks:176- Core presentation requirements run from ./app/.177- All logic-layer reads go through `graphos-world-client`, not direct source imports.178- No new logic-layer entities or graph structure changes are introduced.179180### Step 3: Build and Output Verification1811821. Ensure build target outputs to ./dist/app/.1832. Run build and verify output path, entry file, and asset references.1843. If build pipeline conflicts with existing project settings, make minimal and scoped adjustments only.185186Completion checks:187- Artifacts are generated in ./dist/app/.188- Non-presentation modules are not impacted.189190### Step 4: Integration and Regression Check1911921. Integrate using logic states provided by graph-world.1932. Validate key scenarios: initialization, state transitions, event feedback, and fallback presentation.1943. If new or changed logic state is required:195 - Stop additional presentation patching.196 - Record the contract gap and hand off to graph-world.197 - Resume integration after logic updates are complete.198199Completion checks:200- Presentation and logic contracts are aligned.201- Logic gaps are explicitly handed off and not bypassed in this skill.202203## Quality Criteria204205- Correct boundary: presentation code does not carry business decisions.206- Correct paths: source in ./app/ and build output in ./dist/app/.207- Client-only access: all logic-layer state is read through `graphos-world-client`; no direct imports from logic-layer source folders.208- Type safety: object types from `app/World.ts` (auto-generated) are used throughout presentation code; `app/World.ts` is never modified.209- Rendering rule: immediate-mode redraw paths use PixiJS `Graphics` clear-and-redraw based on current object state and relationships.210- Resource binding: object-scoped rendering resources may use `WeakMap<IObject, ...>` and are cleaned up on despawn.211- Lifecycle hooks: lifecycle-sensitive presentation behavior listens to `Client` events (`spawn`, `change`, `despawn`) with `SpawnEvent` / `ChangeEvent` / `DespawnEvent` typing.212- Contract alignment: naming and semantics are consistent with graph-world Context, Variant, and Event.213- Maintainability: clear modules, explicit typing, readable critical render paths.214- Verifiability: at least one successful build and key integration flow validation.215216## Failure Recovery217218- Build fails: inspect TypeScript and asset paths in ./app/ first, then minimal build config.219- `client.objects()` returns unexpected or missing fields: stop presentation patching, identify the missing contract, and hand off to graph-world to expose the field.220- Immediate-mode redraw performance degrades: keep immediate mode for dynamic links/relations, but move static layers to retained containers and profile draw-call hotspots.221- Lifecycle mismatch (missing init/cleanup timing): verify `spawn` / `change` / `despawn` event wiring on `Client` before adding workaround state in presentation.222- Type mismatch on `app/World.ts` types: re-read `app/World.ts` (do not edit it); adjust presentation code to match the generated types.223- Integration fails due to logic gap: immediately route back to decision step and hand off to graph-world.224- Requirement out of scope: split out-of-scope logic items into graph-world follow-up tasks, and deliver only feasible presentation work here.225226## Example Requests227228- Use TypeScript + PixiJS in ./app to implement battle scene HUD and hit animation, without changing the logic layer.229- Refactor rendering layer to map existing player state to UI while keeping output in ./dist/app.230- I need one new state field for presentation usage first through graph-world, then continue presentation work.231- Render all objects from `client.objects()` as PixiJS sprites, using types from `app/World.ts`.232233## Scope Migration234235- This file is currently a repository-scoped skill at skills/graph-world-pixijs/SKILL.md.236- For personal global reuse, copy the same skill to a user skill directory, for example ~/.copilot/skills/graph-world-pixijs/SKILL.md or ~/.agents/skills/graph-world-pixijs/SKILL.md.