Skip to content

Commit ab215e9

Browse files
committed
WIP create agent skills definitions
1 parent b5cfe4c commit ab215e9

File tree

20 files changed

+6194
-0
lines changed

20 files changed

+6194
-0
lines changed

packages/skills/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# @spearwolf/shadow-objects Skills
2+
3+
Agent Skills for the **Shadow Objects Framework** - a reactive library for decoupling business logic from UI rendering.
4+
5+
## Installation
6+
7+
Install all skills:
8+
9+
```bash
10+
npx skills add spearwolf/shadow-objects
11+
```
12+
13+
Or install specific skills:
14+
15+
```bash
16+
npx skills add spearwolf/shadow-objects --skill shadow-objects-basics
17+
npx skills add spearwolf/shadow-objects --skill shadow-objects-context
18+
```
19+
20+
## Available Skills
21+
22+
| Skill | Description |
23+
|-------|-------------|
24+
| [`shadow-objects-basics`](./skills/shadow-objects-basics/) | Fundamentals: Entities, Tokens, Shadow Objects, Kernel, Registry, Web Components setup |
25+
| [`shadow-objects-context`](./skills/shadow-objects-context/) | Context patterns with Provider/Consumer and the type-safe Context Reader pattern |
26+
| [`shadow-objects-signals`](./skills/shadow-objects-signals/) | Reactive programming with Signals, Effects, and Memos |
27+
| [`shadow-objects-lifecycle`](./skills/shadow-objects-lifecycle/) | Lifecycle management, resource cleanup, and the createResource pattern |
28+
| [`shadow-objects-events`](./skills/shadow-objects-events/) | Event communication between View and Shadow World |
29+
30+
## What is Shadow Objects?
31+
32+
Shadow Objects is a reactive library that runs your application logic "in the shadows" (typically a Web Worker), completely decoupled from your UI layer. Think of it like a shadow theater:
33+
34+
- **The Screen (View)**: What the audience sees - your DOM, Canvas, or any UI
35+
- **The Puppets (Entities)**: Abstract representations with structure and properties
36+
- **The Puppeteer (Shadow Objects)**: The logic that controls everything
37+
38+
This separation gives you:
39+
- Clean architecture with separated concerns
40+
- Better performance via Web Worker offloading
41+
- Testable business logic independent of UI
42+
- Reactive state management with Signals
43+
44+
## Resources
45+
46+
- [Shadow Objects Documentation](https://github.com/spearwolf/shadow-objects/tree/main/packages/shadow-objects/docs)
47+
- [Shadow Objects on npm](https://www.npmjs.com/package/@spearwolf/shadow-objects)
48+
- [Agent Skills Specification](https://agentskills.io)
49+
50+
## License
51+
52+
Apache-2.0
Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
---
2+
name: shadow-objects-basics
3+
description: Learn the fundamentals of the Shadow Objects Framework - a reactive library for decoupling business logic from UI. Use this skill when starting a new Shadow Objects project, understanding the architecture (Entities, Tokens, Shadow Objects, Kernel, Registry), or setting up Web Components like <shae-worker>, <shae-ent>, and <shae-prop>.
4+
---
5+
6+
# Shadow Objects Basics
7+
8+
The Shadow Objects Framework separates your application logic from UI rendering. Think of it like a shadow theater: the audience sees the screen (UI), but the real action happens behind the scenes with the puppeteer (your logic).
9+
10+
## When to Use This Skill
11+
12+
Use this skill when:
13+
14+
- Starting a new Shadow Objects project
15+
- Understanding the core architecture
16+
- Setting up Web Components (`<shae-worker>`, `<shae-ent>`, `<shae-prop>`)
17+
- Creating your first Shadow Object
18+
- Configuring the Registry
19+
20+
## The Shadow Theater Model
21+
22+
| Concept | Role | Description |
23+
|---------|------|-------------|
24+
| **Screen** | View | The visible UI (DOM, Canvas) |
25+
| **Puppets** | Entities | Abstract representations with hierarchical structure |
26+
| **Puppeteer** | Shadow Objects | The logic that react on the puppets |
27+
28+
**Key insight**: "Don't script the screen directly. Script the Puppeteer, and the framework projects the state onto the screen automatically."
29+
30+
## The Two Worlds
31+
32+
### Light World (Browser/Main Thread)
33+
34+
- The user-facing UI
35+
- Contains Web Components, DOM elements or other state structures created by the View Component API
36+
- Should hold minimal state
37+
- Sends data downstream, receives events upstream
38+
39+
### Shadow World (Web Worker or Main Thread)
40+
41+
- Where your application logic lives
42+
- The source of truth for state
43+
- Contains the Kernel, Entities, and Shadow Objects
44+
- Runs independently from the UI thread
45+
46+
## Core Concepts
47+
48+
### Token
49+
50+
A string identifier linking View to Logic. Tokens describe *what* something is, not *which specific instance*.
51+
52+
```html
53+
<shae-ent token="my-counter">...</shae-ent>
54+
```
55+
56+
### Entity
57+
58+
The abstract representation of a component in the Shadow World. Entities:
59+
60+
- Form a tree structure (parent/child relationships)
61+
- Hold Properties synced from the View
62+
- Participate in the Context system
63+
- Might have one or more Shadow Objects attached
64+
65+
### Shadow Object
66+
67+
A functional unit of logic attached to an Entity. Shadow Objects are:
68+
69+
- **Reusable**: Domain-specific, works across different UI components
70+
- **Reactive**: Responds to property and context changes automatically
71+
- **Composable**: Multiple Shadow Objects can attach to one Entity
72+
73+
```typescript
74+
function MyShadowObject({ useProperty, createEffect }: ShadowObjectCreationAPI) {
75+
const count = useProperty('count');
76+
77+
createEffect(() => {
78+
console.log('Count changed:', count());
79+
});
80+
}
81+
```
82+
83+
### Kernel
84+
85+
The engine of the Shadow World:
86+
87+
- Manages the Entity tree lifecycle
88+
- Orchestrates Shadow Objects
89+
- Schedules reactive update cycles
90+
91+
### Registry
92+
93+
The configuration that maps Tokens to Shadow Object constructors:
94+
95+
```typescript
96+
export default {
97+
define: {
98+
'counter': CounterLogic,
99+
'analytics': AnalyticsTracker,
100+
},
101+
routes: {
102+
// Composition: 'counter' also loads 'analytics'
103+
'counter': ['analytics'],
104+
}
105+
};
106+
```
107+
108+
## HTML Setup
109+
110+
### Step 1: Import Web Components
111+
112+
```html
113+
<script type="module">
114+
import "@spearwolf/shadow-objects/elements.js";
115+
</script>
116+
```
117+
118+
### Step 2: Create a Shadow Worker Environment
119+
120+
```html
121+
<shae-worker src="./my-logic.js" ns="app">
122+
</shae-worker>
123+
```
124+
125+
| Attribute | Description |
126+
|-----------|-------------|
127+
| `src` | Path to your logic module (aka Shadow Objects Module) |
128+
| `ns` | Optional Namespace (connects related components). If empty, the default namespace is used, which is fine when only one shadow objects environment (worker) is used. |
129+
| `local` | Run on main thread instead of worker |
130+
| `no-structered-clone` | (Only if `local`): Do NOT use `structeredClone()` helper to clone the property and event arguments. |
131+
| `auto-sync` | Sync frequency: `frame`, `30fps`, `100` (ms, interval), `no` |
132+
133+
### Step 3: Create Entities
134+
135+
```html
136+
<shae-ent token="counter" ns="app">
137+
<shae-prop name="count" value="0" type="int"></shae-prop>
138+
<button>Click me</button>
139+
</shae-ent>
140+
```
141+
142+
| Attribute | Description |
143+
|-----------|-------------|
144+
| `token` | Maps to a Registry entry |
145+
| `ns` | Must match `<shae-worker>` namespace |
146+
| `forward-custom-events` | Forward events from Shadow Objects Environment as DOM CustomEvents |
147+
148+
**Important**: `<shae-ent>` elements do NOT need to be DOM children of `<shae-worker>`. They connect via namespace.
149+
150+
### Step 4: Bind Properties
151+
152+
```html
153+
<shae-prop name="score" value="100" type="int"></shae-prop>
154+
<shae-prop name="active" value="true" type="boolean"></shae-prop>
155+
<shae-prop name="config" value='{"level":1}' type="json"></shae-prop>
156+
<shae-prop name="position" value="10 20 30" type="float32array"></shae-prop>
157+
```
158+
159+
Supported types: `string`, `number`, `int`, `boolean`, `json`, `number[]`, `float32array`, `uint8array`
160+
161+
**Important**: `<shae-prop>` elements MUST BE be a DOM children of `<shae-ent>`.
162+
163+
## Creating Your First Shadow Object
164+
165+
See [references/basic-shadow-object.ts](references/basic-shadow-object.ts) for a complete example.
166+
167+
```typescript
168+
export function Counter({
169+
useProperty,
170+
createSignal,
171+
createEffect,
172+
onViewEvent,
173+
dispatchMessageToView
174+
}: ShadowObjectCreationAPI) {
175+
// Read property from View
176+
const initialCount = useProperty<number>('count');
177+
178+
// Create local reactive state
179+
const count = createSignal(initialCount() ?? 0);
180+
181+
// React to changes
182+
createEffect(() => {
183+
dispatchMessageToView('count-changed', { value: count() });
184+
});
185+
186+
// Handle View events
187+
onViewEvent((type, data) => {
188+
if (type === 'increment') {
189+
count.set(count.value + (data?.amount ?? 1));
190+
}
191+
});
192+
}
193+
```
194+
195+
## The ShadowObjectCreationAPI
196+
197+
When a Shadow Object function is called, it receives these tools:
198+
199+
| API | Purpose |
200+
|-----|---------|
201+
| `useProperty(name)` | Read a reactive property from View |
202+
| `useProperties(map)` | Read multiple properties at once |
203+
| `createSignal(initial)` | Create local reactive state |
204+
| `createEffect(fn)` | Run side effects on dependency changes |
205+
| `createMemo(fn)` | Create computed/derived values |
206+
| `createResource(factory, cleanup)` | Manage external resources |
207+
| `onViewEvent(handler)` | Listen to events from View |
208+
| `dispatchMessageToView(type, data)` | Send events to View |
209+
| `provideContext(name, value)` | Provide context for descendants |
210+
| `useContext(name)` | Consume context from ancestors |
211+
| `onDestroy(cleanup)` | Register cleanup on destruction |
212+
| `entity` | Reference to the Entity object |
213+
214+
## Registry Configuration
215+
216+
See [references/registry-config.ts](references/registry-config.ts) for advanced patterns.
217+
218+
### Basic Definition
219+
220+
```typescript
221+
import type { ShadowObjectsModule } from '@spearwolf/shadow-objects';
222+
223+
const mod: ShadowObjectsModule = {
224+
define: {
225+
'counter': Counter,
226+
'logger': Logger,
227+
},
228+
};
229+
230+
export default mod;
231+
```
232+
233+
### Composition with Routes
234+
235+
```typescript
236+
export default {
237+
define: {
238+
'counter': Counter,
239+
'logger': Logger,
240+
'analytics': AnalyticsTracker,
241+
},
242+
routes: {
243+
// Load 'logger' and 'analytics' whenever 'counter' is created
244+
'counter': ['logger', 'analytics'],
245+
},
246+
};
247+
```
248+
249+
### Conditional Routes
250+
251+
```typescript
252+
export default {
253+
define: {
254+
'counter': Counter,
255+
'debug-panel': DebugPanel,
256+
},
257+
routes: {
258+
// 'counter' conditionally loads '@debug' route
259+
'counter': ['@debug'],
260+
// '@debug' resolves to 'debug-panel' only if 'debug' property is truthy
261+
'@debug': ['debug-panel'],
262+
},
263+
};
264+
```
265+
266+
## Best Practices
267+
268+
1. **Keep Shadow Objects focused**: One concern per Shadow Object
269+
2. **Use composition**: Multiple Shadow Objects per Entity for complex behavior
270+
3. **Let the Registry handle routing**: Don't instantiate Shadow Objects manually
271+
4. **Tokens describe types, not instances**: The framework assigns unique IDs internally
272+
5. **Namespace carefully**: Group related app domains with the same `ns` attribute
273+
274+
## Common Pitfalls
275+
276+
| Pitfall | Solution |
277+
|---------|----------|
278+
| Forgetting `ns` attribute | Ensure `<shae-ent>` and `<shae-worker>` share the same namespace |
279+
| Modifying shared state | Data is cloned across Worker boundary. Use events for updates. |
280+
| Direct DOM manipulation | Use `dispatchMessageToView` to send state to View |
281+
| Missing cleanup | Use `onDestroy` for external resources (see lifecycle skill) |
282+
| Synchronous expectations | The Shadow Objects Environment and the View generally run asynchronously to each other. Communication takes place exclusively from the View to the Shadow Objects Environment via property changes or events. Communication from the Shadow Object Environment to the View takes place only via events. |
283+
284+
## Complete Example
285+
286+
See [references/html-setup.html](references/html-setup.html) for a full working example.
287+
288+
```html
289+
<!DOCTYPE html>
290+
<html>
291+
<head>
292+
<script type="module">
293+
import "@spearwolf/shadow-objects/elements.js";
294+
</script>
295+
</head>
296+
<body>
297+
<shae-worker src="./counter-logic.js" ns="app"></shae-worker>
298+
299+
<shae-ent token="counter" ns="app" forward-custom-events="count-changed">
300+
<shae-prop name="count" value="0" type="int"></shae-prop>
301+
<button id="inc">+1</button>
302+
<span id="display">0</span>
303+
</shae-ent>
304+
305+
<script>
306+
const ent = document.querySelector('shae-ent');
307+
const display = document.querySelector('#display');
308+
309+
document.querySelector('#inc').addEventListener('click', () => {
310+
ent.viewComponent?.dispatchShadowObjectsEvent('increment', { amount: 1 });
311+
});
312+
313+
ent.addEventListener('count-changed', (e) => {
314+
display.textContent = e.detail.value;
315+
});
316+
</script>
317+
</body>
318+
</html>
319+
```
320+
321+
## Next Steps
322+
323+
After mastering the basics, explore these related skills:
324+
325+
- **shadow-objects-context**: Share state between Entities with Provider/Consumer patterns
326+
- **shadow-objects-signals**: Deep dive into reactive programming with Signals and Effects
327+
- **shadow-objects-lifecycle**: Manage resources and understand the Shadow Object lifecycle
328+
- **shadow-objects-events**: Advanced event communication patterns

0 commit comments

Comments
 (0)