Skip to content

Commit 30b758c

Browse files
committed
update README
- backup previous README to README.old.md
1 parent 4fbe2f3 commit 30b758c

2 files changed

Lines changed: 266 additions & 142 deletions

File tree

packages/shadow-objects/README.md

Lines changed: 112 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,154 +1,124 @@
11
_hi! welcome to .._
2-
# shadow-objects 🧛
3-
4-
## Introduction
5-
6-
_Shadow-objects_ is a standalone, reactive entity←component framework 🔥
7-
8-
The original idea is visualized in this overview:
9-
10-
![architecture overview](https://raw.githubusercontent.com/spearwolf/shadow-objects/main/packages/shadow-objects/docs/architecture%402x.png)
11-
12-
> _ents_ is short for latin _"entitatis"_, which translates to _"shadow entities"_
13-
14-
> [!IMPORTANT]
15-
> _Dear adventurer, be warned: everything here is highly experimental and in active development and constant flux!_
16-
17-
The components are created in the view space. Hierarchical. In your browser. There is a JavaScript API for this. But to keep things simple, there are also ready-to-use web components.
18-
19-
```html
20-
<shae-worker-env local? src="./my-personal-shadow-objects.js" />
21-
22-
<shae-ent ns? token="foo">
23-
<shae-ent ns? token="bar">
24-
<shae-prop name="myNumbers" value="1 2 3" type="integer[]" />
25-
</shae-ent>
26-
</shae-ent>
27-
```
28-
29-
In the shadows, the _shadow objects_ come and go with the entities. An entity can cover many shadows. But all are united by the entity _token_. That token, which is specified by the _view components_.
30-
31-
The _shadow object module_ stores which shadow objects are hidden behind a token. Either a _function_ or a _class_.
32-
33-
```js
34-
shadowObjects.define('token', function() {
35-
console.log('The simplest shadow object ever.');
36-
});
37-
38-
@ShadowObject('token')
39-
class Foo {
40-
constructor({
41-
entity,
42-
provideContext,
43-
useContext,
44-
useProperty,
45-
onDestroy,
46-
}: ShadowObjectParams) {
47-
console.log('hello');
48-
49-
onDestroy(() => {
50-
console.log('bye');
51-
});
52-
}
2+
# Shadow Objects Framework 🧛
3+
4+
The **Shadow Objects Framework** is a library for managing application state and logic that runs "in the dark" (in a worker or separate context), mirroring a view hierarchy (like the DOM). It decouples business logic and state management from the UI rendering layer.
5+
6+
## Core Concepts
7+
8+
### 1. Entities
9+
An **Entity** is the fundamental unit in the framework. It represents a node in the hierarchy, mirroring a view component (e.g., a Web Component or a DOM element).
10+
- **Hierarchy**: Entities have parents and children, forming a tree structure.
11+
- **Properties**: Entities hold reactive properties that sync with the view.
12+
- **Context**: Entities participate in a hierarchical context system (dependency injection).
13+
14+
### 2. Shadow Objects
15+
A **Shadow Object** is a functional unit of logic attached to an Entity.
16+
- **Logic Containers**: They contain the state, effects, and business logic for a specific feature.
17+
- **Lifecycle**: They are automatically created and destroyed by the **Kernel** based on the Entity's **Token**.
18+
- **Reactivity**: They use **Signals** and **Effects** (via `@spearwolf/signalize`) to react to changes in properties or context.
19+
20+
### 3. The Kernel
21+
The **Kernel** is the brain of the framework.
22+
- **Manages Entities**: Handles creation, destruction, and hierarchy updates of Entities.
23+
- **Orchestrates Shadow Objects**: Instantiates the correct Shadow Objects for each Entity based on its Token and the Registry.
24+
- **Message Dispatch**: Handles communication between the View (UI) and the Shadow World.
25+
26+
### 4. The Registry
27+
The **Registry** maps **Tokens** to **Shadow Object Constructors**.
28+
- **Tokens**: Strings that identify what logic an Entity should have (e.g., `"my-component"`).
29+
- **Routes**: Defines rules for composing multiple Shadow Objects. For example, a token can "route" to other tokens, causing multiple Shadow Objects to be instantiated for a single Entity.
30+
- **Conditional Routing**: Routes can be triggered based on the presence of specific "truthy" properties on the Entity (e.g., `@myProp` routes only if `myProp` is set).
31+
32+
## Lifecycle
33+
34+
1. **Creation**: When an Entity is created (e.g., a Web Component connects), the Kernel looks up its Token in the Registry.
35+
2. **Instantiation**: The Kernel instantiates all Shadow Objects associated with that Token (and its routes).
36+
3. **Execution**: The Shadow Object function runs, setting up signals, effects, and context providers.
37+
4. **Updates**:
38+
* **Properties**: When view properties change, the Entity's signals update, triggering any dependent effects in the Shadow Object.
39+
* **Context**: If a parent Entity changes a provided context, child Shadow Objects consuming that context automatically update.
40+
5. **Destruction**: When an Entity is removed or its Token changes, the Kernel destroys the associated Shadow Objects, cleaning up all signals and effects.
41+
42+
## API: Writing Shadow Objects
43+
44+
Shadow Objects are defined as functions (or classes) that receive a `ShadowObjectParams` object.
45+
46+
```typescript
47+
import { ShadowObjectParams } from "@spearwolf/shadow-objects";
48+
49+
export function MyShadowObject({
50+
useProperty,
51+
useProperties,
52+
useContext,
53+
provideContext,
54+
useResource,
55+
createEffect,
56+
on
57+
}: ShadowObjectParams) {
58+
59+
// 1. Read Properties from the View
60+
const getTitle = useProperty("title");
61+
// or bulk access:
62+
const props = useProperties({
63+
title: "title",
64+
isEnabled: "enabled"
65+
});
66+
67+
// 2. Consume Context from Parents
68+
const getTheme = useContext("theme");
69+
70+
// 3. Manage Resources (Lifecycle)
71+
// Automatically creates/destroys the resource when dependencies change
72+
const myService$ = useResource(() => {
73+
const title = props.title();
74+
if (!title) return;
75+
return new MyService(title);
76+
}, (service) => service.dispose());
77+
78+
// 4. Provide Context to Children
79+
// Can pass a value or a signal directly
80+
provideContext("myService", myService$);
81+
82+
// 5. Side Effects
83+
createEffect(() => {
84+
console.log("Title changed to:", props.title());
85+
});
86+
87+
// 6. Event Listeners
88+
on(entity, "some-event", (data) => { /* ... */ });
5389
}
5490
```
5591

56-
> [!WARNING]
57-
> Sorry, at this point there should be a precise and crisp introduction to the concepts of the framework, but unfortunately this is not currently available.
58-
> Instead of that, a few insights into the implementation will follow
92+
### Key API Methods
5993

60-
## 📖 Shadow Objects CHEAT SHEET
94+
* **`useProperty(name)`**: Returns a signal reader for a specific property on the Entity.
95+
* **`useProperties(map)`**: Returns an object of signal readers for multiple properties.
96+
* **`useContext(name)`**: Returns a signal reader for a value provided by a parent Entity.
97+
* **`provideContext(name, value)`**: Makes a value (or signal) available to descendant Entities.
98+
* **`useResource(factory, cleanup)`**: A helper to create and manage objects that need explicit cleanup (like Three.js objects or subscriptions).
99+
* **`createEffect(callback)`**: Runs a side effect whenever accessed signals change.
100+
* **`createSignal(initialValue)`**: Creates a local reactive state.
61101

62-
There are two ways to create a _shadow object component_: either as a _function_ or as a _class_:
102+
## Architecture Diagram
63103

64-
### Create Shadow Object by FUNCTION
104+
```mermaid
105+
graph TD
106+
View[View / DOM] -->|Messages| Kernel
107+
Kernel -->|Updates| EntityTree[Entity Tree]
65108
66-
```js
67-
import { onDestroy, type ShadowObjectParams, type Entity } from "@spearwolf/shadow-objects/shadow-objects.js";
109+
subgraph "Shadow World"
110+
EntityTree
111+
Entity[Entity]
112+
SO[Shadow Object]
68113
69-
function MyShadowObject(params: ShadowObjectParams) {
70-
//
71-
// ... PUT YOUR IMPLEMENTATION HERE ...
72-
//
73-
74-
// Return an object. This step is optional.
75-
return {
76-
// All methods here are reactive and correspond to entity events of the same name!
114+
EntityTree --> Entity
115+
Entity -->|Has| SO
77116
78-
[onDestroy](entity: Entity) {
79-
// Called when the shadow object is destroyed.
80-
// This is one of the predefined events that a shadow object can receive.
117+
SO -->|Reads| Props[Properties]
118+
SO -->|Reads/Writes| Context
119+
SO -->|Runs| Logic[Business Logic]
120+
end
81121
82-
// This can happen when the entity is destroyed or the shadow object component
83-
// is removed from the entity (e.g., by changing the entity token, view properties, and/or routing)
84-
},
85-
86-
fooBar(plah) {
87-
/* is called when the entity receives a 'fooBar' event */
88-
},
89-
};
90-
}
122+
Logic -->|Updates| Signals
123+
Signals -->|Triggers| Effects
91124
```
92-
93-
### Create Shadow Object by CLASS
94-
95-
Essentially the same as above, but as a `class`:
96-
97-
```js
98-
import { onDestroy, type ShadowObjectParams, type Entity } from "@spearwolf/shadow-objects/shadow-objects.js";
99-
100-
class MyShadowObject {
101-
constructor(params: ShadowObjectParams) {
102-
//
103-
// ... INITIALIZE SHADOW OBJECT ...
104-
//
105-
}
106-
107-
[onDestroy](entity: Entity) {
108-
// ...
109-
}
110-
111-
fooBar(plah) {
112-
// ...
113-
}
114-
}
115-
```
116-
117-
### Shadow Object Construction API
118-
119-
The parameters that a shadow object receives when it is created contain all the important API methods for exchanging data and events with the _view_ and also with the _shadow entity hierarchy and context_.
120-
121-
[The interface `ShadowObjectsParams` is defined here](./src/types.ts)
122-
123-
#### Properties
124-
125-
__entity__: The shadow entity.
126-
127-
#### Methods
128-
129-
| Name | Call Signature | Description |
130-
|------|----------------|-------------|
131-
| __useProperty__ | `useProperty(name, isEqual?): SignalReader` | Read access to the property value from the view |
132-
| __useContext__ | `useContext(name, isEqual?): SignalReader` | Get the value for a named context. The context is derived from the shadow entity hierarchy and the shadow object's position within it. |
133-
| __useParentContext__ | `useParentContext(name, isEqual?): SignalReader` | Unlike the `useContext` method, this method skips the context of the _current_ shadow entity and directly requests the context of the parent entity. This is useful when you want to provide a custom context that depends on the parent context. |
134-
| __provideContext__ | `provideContext(name, initialValue?, isEqual?): Signal` | Specify a context. This context overrides (if set) the context of the same name from the entity's parent hierarchy. The context applies to the current entity and all child entities. |
135-
| __provideGlobalContext__ | `provideGlobalContext(name, initialValue?, isEqual?): Signal` | Define a context that applies to _all_ entities, regardless of hierarchy. |
136-
| __createEffect__ | `createEffect(...): Effect` | see [@spearwolf/signalize#createEffect()](https://github.com/spearwolf/signalize) |
137-
| __createSignal__ | `createSignal(...): Signal` | see [@spearwolf/signalize#createSignal()](https://github.com/spearwolf/signalize) |
138-
| __createMemo__ | `createMemo(...): SignalReader` | see [@spearwolf/signalize#createMemo()](https://github.com/spearwolf/signalize) |
139-
| __on__ | `on(...): UnsubscribeCallback` | see [@spearwolf/eventize#on()](https://github.com/spearwolf/eventize) |
140-
| __once__ | `once(...): UnsubscribeCallback` | see [@spearwolf/eventize#once()](https://github.com/spearwolf/eventize) |
141-
| __onDestroy__ | `onDestroy(callback)` | Called when the shadow object is destroyed. |
142-
143-
144-
## Documentation
145-
146-
TODO ... add documentation here ... !
147-
148-
Here is the big class graph overview:
149-
![class graph overview](https://raw.githubusercontent.com/spearwolf/shadow-objects/main/packages/shadow-objects/src/view/ClassGraphOverview.drawio.svg)
150-
151-
More in-depth docs here:
152-
- [ShadowEnv](https://github.com/spearwolf/shadow-objects/blob/main/packages/shadow-objects/src/view/README.md)
153-
- [ComponentContext](https://github.com/spearwolf/shadow-objects/blob/main/packages/shadow-objects/src/view/ComponentContext.md)
154-
- [ViewComponent](https://github.com/spearwolf/shadow-objects/blob/main/packages/shadow-objects/src/view/ViewComponent.md)

0 commit comments

Comments
 (0)