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 throughgraphos-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 inapp/World.ts. app/World.tsis auto-generated — do NOT modify it manually.- Import types from
app/World.tsfor 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
Graphicsand 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()fromgraphos-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(Clientclass,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.tsfor 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
WeakMapso resources follow object lifecycle without manual ownership coupling. - If lifecycle-level initialization or disposal is required, subscribe to
spawn/change/despawnevents fromClient.
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.tsis never modified. - Rendering rule: immediate-mode redraw paths use PixiJS
Graphicsclear-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
Clientevents (spawn,change,despawn) withSpawnEvent/ChangeEvent/DespawnEventtyping. - 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/despawnevent wiring onClientbefore adding workaround state in presentation. - Type mismatch on
app/World.tstypes: re-readapp/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 fromapp/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.