koota 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +131 -12
- package/dist/chunk-TOFVEQXZ.js +1338 -0
- package/dist/index.cjs +37 -7
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/react.cjs +141 -105
- package/dist/react.d.cts +8 -6
- package/dist/react.d.ts +8 -6
- package/dist/react.js +66 -49
- package/package.json +2 -2
- package/react/index.cjs +141 -105
- package/react/index.d.cts +8 -6
- package/react/index.d.ts +8 -6
- package/react/index.js +66 -49
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ world.query(Position, Velocity).updateEach(([position, velocity]) => {
|
|
|
57
57
|
Traits can be used reactively inside of React components.
|
|
58
58
|
|
|
59
59
|
```js
|
|
60
|
-
import { WorldProvider, useQuery,
|
|
60
|
+
import { WorldProvider, useQuery, useTrait } from 'koota/react'
|
|
61
61
|
|
|
62
62
|
// Wrap your app in WorldProvider
|
|
63
63
|
createRoot(document.getElementById('root')!).render(
|
|
@@ -78,7 +78,7 @@ function RocketRenderer() {
|
|
|
78
78
|
|
|
79
79
|
function Rocket({ entity }) {
|
|
80
80
|
// Observes this entity's position trait and reactively updates when it changes
|
|
81
|
-
const position =
|
|
81
|
+
const position = useTrait(entity, Position)
|
|
82
82
|
return (
|
|
83
83
|
<div style={{ position: 'absolute', left: position.x ?? 0, top: position.y ?? 0 }}>
|
|
84
84
|
🚀
|
|
@@ -92,9 +92,10 @@ function Rocket({ entity }) {
|
|
|
92
92
|
Use actions to safely modify Koota from inside of React in either effects or events.
|
|
93
93
|
|
|
94
94
|
```js
|
|
95
|
-
import { createActions } from 'koota
|
|
95
|
+
import { createActions } from 'koota'
|
|
96
|
+
import { useActions } from 'koota/react';
|
|
96
97
|
|
|
97
|
-
const
|
|
98
|
+
const actions = createActions((world) => ({
|
|
98
99
|
spawnShip: (position) => world.spawn(Position(position), Velocity),
|
|
99
100
|
destroyAllShips: (world) => {
|
|
100
101
|
world.query(Position, Velocity).forEach((entity) => {
|
|
@@ -104,7 +105,7 @@ const useMyActions = createActions((world) => ({
|
|
|
104
105
|
}));
|
|
105
106
|
|
|
106
107
|
function DoomButton() {
|
|
107
|
-
const { spawnShip, destroyAllShips } =
|
|
108
|
+
const { spawnShip, destroyAllShips } = useActions(actions);
|
|
108
109
|
|
|
109
110
|
// Spawn three ships on mount
|
|
110
111
|
useEffect(() => {
|
|
@@ -508,16 +509,134 @@ const Mesh = trait(() => THREE.Mesh())
|
|
|
508
509
|
|
|
509
510
|
### React
|
|
510
511
|
|
|
511
|
-
`
|
|
512
|
+
### `useQuery`
|
|
513
|
+
|
|
514
|
+
Reactively updates when entities matching the query changes. Returns a `QueryResult`, which is like an array of entities.
|
|
515
|
+
|
|
516
|
+
```js
|
|
517
|
+
// Get all entities with Position and Velocity traits
|
|
518
|
+
const entities = useQuery(Position, Velocity);
|
|
519
|
+
|
|
520
|
+
// Render them
|
|
521
|
+
return (
|
|
522
|
+
<>
|
|
523
|
+
{entities.map(entity => <Renderer key={entity.id()} entity={entity} />)}
|
|
524
|
+
</>
|
|
525
|
+
);
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### `usQueryFirst`
|
|
529
|
+
|
|
530
|
+
Works like `useQuery` but only returns the first result. Can either be an entity of undefined.
|
|
512
531
|
|
|
513
532
|
```js
|
|
514
|
-
|
|
533
|
+
// Get the first entity with Player and Position traits
|
|
534
|
+
const player = useQueryFirst(Player, Position);
|
|
515
535
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
536
|
+
// Render it if found
|
|
537
|
+
return player ? (
|
|
538
|
+
<Renderer entity={player} />
|
|
539
|
+
) : null;
|
|
520
540
|
|
|
521
|
-
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### `useWorld`
|
|
544
|
+
|
|
545
|
+
Returns the default world. If a world is passed in via `WorldProvider` then this is returned instead. The default world can be gotten at any time with `getDefaultWorld`.
|
|
546
|
+
|
|
547
|
+
```js
|
|
548
|
+
// Get the default world
|
|
549
|
+
const world = useWorld();
|
|
550
|
+
|
|
551
|
+
// Use the world to create an entity on mount
|
|
552
|
+
useEffect(() => {
|
|
553
|
+
const entity = world.spawn()
|
|
554
|
+
return => entity.destroy()
|
|
555
|
+
}, [])
|
|
556
|
+
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### `WorldProvider`
|
|
560
|
+
|
|
561
|
+
The provider for the world context. A world must be created and passed in, which then overrides the default world.
|
|
562
|
+
|
|
563
|
+
```js
|
|
564
|
+
// Create a world and pass it to the provider
|
|
565
|
+
const world = createWorld();
|
|
566
|
+
|
|
567
|
+
// All hooks will now use this world instead of the default
|
|
568
|
+
function App() {
|
|
569
|
+
return (
|
|
570
|
+
<WorldProvider world={world}>
|
|
571
|
+
<Game />
|
|
572
|
+
</WorldProvider>
|
|
573
|
+
);
|
|
522
574
|
}
|
|
575
|
+
|
|
523
576
|
```
|
|
577
|
+
|
|
578
|
+
### `useTrait`
|
|
579
|
+
|
|
580
|
+
Observes an entity, or world, for a given trait and reactively updates when it is added, removed or changes value.
|
|
581
|
+
|
|
582
|
+
```js
|
|
583
|
+
// Get the position trait from an entity and reactively updates
|
|
584
|
+
// when it changes
|
|
585
|
+
const position = useTrait(entity, Position);
|
|
586
|
+
|
|
587
|
+
// If position is removed from entity then it will be undefined
|
|
588
|
+
if (!position) return null
|
|
589
|
+
|
|
590
|
+
// Render the position
|
|
591
|
+
return (
|
|
592
|
+
<div>
|
|
593
|
+
Position: {position.x}, {position.y}
|
|
594
|
+
</div>
|
|
595
|
+
);
|
|
596
|
+
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### `useTraitEffect`
|
|
600
|
+
|
|
601
|
+
Subscribes a callback to a trait on an entity. This callback fires as an effect whenenver it is added, removed or changes value without rerendering.
|
|
602
|
+
|
|
603
|
+
```js
|
|
604
|
+
// Subscribe to position changes on an entity and update a ref
|
|
605
|
+
// without causing a rerender
|
|
606
|
+
useTraitEffect(entity, Position, (position) => {
|
|
607
|
+
if (!position) return;
|
|
608
|
+
meshRef.current.position.copy(position);
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
// Subscribe to world-level traits
|
|
612
|
+
useTraitEffect(world, GameState, (state) => {
|
|
613
|
+
if (!state) return;
|
|
614
|
+
console.log('Game state changed:', state);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### `useActions`
|
|
620
|
+
|
|
621
|
+
Returns actions bound to the world that is context. Use actions created by `createActions`.
|
|
622
|
+
|
|
623
|
+
```js
|
|
624
|
+
// Create actions
|
|
625
|
+
const actions = createActions((world) => ({
|
|
626
|
+
spawnPlayer: () => world.spawn(IsPlayer).
|
|
627
|
+
destroyAllPlayers: () => {
|
|
628
|
+
world.query(IsPlayer).forEach((player) => {
|
|
629
|
+
player.destroy()
|
|
630
|
+
})
|
|
631
|
+
}
|
|
632
|
+
}))
|
|
633
|
+
|
|
634
|
+
// Get actions bound to the world in context
|
|
635
|
+
const { spawnPlayer, destroyAllPlayers } = useActions();
|
|
636
|
+
|
|
637
|
+
// Call actions to modify the world in an effect or handlers
|
|
638
|
+
useEffect(() => {
|
|
639
|
+
spawnPlayer()
|
|
640
|
+
return () => destroyAllPlayers()
|
|
641
|
+
}, [])
|
|
642
|
+
```
|