Skip to content

Commit c33bf96

Browse files
readme ✨
1 parent 4ac541e commit c33bf96

File tree

1 file changed

+123
-2
lines changed

1 file changed

+123
-2
lines changed

README.md

+123-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,128 @@
11
# bevy_mod_js_scripting
22

3-
Work in progress javascript scripting integration into bevy.
4-
Proper readme coming soon.
3+
`bevy_mod_js_scripting` is an experimental scripting integration crate for writing javascript/typescript scripts and running them
4+
in `bevy` with full access to the ECS values like components and resources.
5+
6+
7+
## Example
8+
9+
```ts
10+
// type safe access to resources and values
11+
type Scoreboard = { score: number };
12+
const Scoreboard: BevyType<Scoreboard> = { typeName: "breakout::Scoreboard" };
13+
14+
// script-local variables can be used for easy cross-frame state
15+
let i = 0;
16+
17+
function run() {
18+
// increment score every 60 frames
19+
if(i % 60 == 0) {
20+
let score = world.resource(Scoreboard)!;
21+
score.score += 1;
22+
// logging works via `trace`, `debug`, `info`, `warn`, `error`
23+
info(score.score);
24+
}
25+
26+
// query components
27+
for (const item of world.query(Transform, Aabb)) {
28+
let [transform, aabb] = item.components;
29+
info("Translation:", transform.translation.toString());
30+
info("AABB Center:", aabb.center.toString());
31+
32+
// call methods on value references (requires app code setup, see headless.rs)
33+
let normalized = transform.scale.normalize();
34+
}
35+
}
36+
37+
export default {
38+
// execute the `run` function in the update stage
39+
update: run,
40+
}
41+
```
42+
43+
More examples can be found in the [examples](./examples/) folder.
44+
Also check out the [punchy wiki page](https://github.com/fishfolks/punchy/wiki/Scripting) on scripting, which uses `bevy_mod_js_scripting`.
45+
46+
## Current Status
47+
48+
Currently supported operations are
49+
- resource access (`world.resource(Time)`)
50+
- world information (`world.components`, `world.resources`, `world.entities`)
51+
- queries (`world.query(Ball, Velocity).map(({ entity, components }) => components[1])`)
52+
- component insertion (`world.insert(value)`)
53+
- dealing with ecs value references (`Value.create`, `Value.patch`)
54+
55+
## Design decisions
56+
57+
<details>
58+
<summary>Types</summary>
59+
60+
In `bevy_ecs`, the common methods for dealing with ECS values all take a type parameter, like
61+
```rs
62+
world.resource::<T>(); // or
63+
world.query<(Entity, &Component)>();
64+
```
65+
Ideally we would be able to write
66+
```ts
67+
let time = world.resource<Time>();
68+
```
69+
as well in typescript, but since typescript just transpiles to javascript without adding any new runtime capabilities, we cannot associate any runtime values with the `Time` type.
70+
71+
72+
Instead, what we need to do is write `type` definition with an associated variable of type `BevyType<T>`, which contains the referenced type's type name.
73+
74+
```ts
75+
type Transform = {
76+
translation: Vec3,
77+
rotation: Quat,
78+
scale: Vec3,
79+
};
80+
const Transform: BevyType<Transform> = {
81+
typeName: "bevy_transform::components::global_transform::GlobalTransform"
82+
};
83+
84+
// `world.resource` is typed so that typescript can infer `transform` to be of type `Transform | undefined`
85+
let transform = world.resource(Transform);
86+
```
87+
88+
Similarly, queries list their types like
89+
```ts
90+
for (item of world.query(Ball, Velocity)) {
91+
info(item.entity);
92+
let [_ball, velocity] = item.components;
93+
// velocity is properly typed
94+
}
95+
```
96+
97+
Currently, there is a pregenerated list of bevy types in [./types/bevy_types.ts](./types/bevy_types.ts), and you can also just define your own ones.
98+
99+
</details>
100+
<details>
101+
<summary>Javascript Values & ECS Value references</summary>
102+
103+
When you call `world.resource` (or any other method returning references to ECS values), what you get is not just a simple javascript object corresponding to the rust value, but instead a `Proxy` which defers all accesses/modifications to the actual value inside the bevy world.
104+
105+
Only leaf values, like `transform.translation.x`, which can be natively represented as a javascript primitive, are automatically converted to/from the rust representation on gets and sets.
106+
107+
This means that
108+
```ts
109+
let transform = world.resource(Transform);
110+
let translation = transform.translation;
111+
// typeof translation.x == "number"
112+
translation.x = 3.0;
113+
```
114+
115+
If you want to create a new value reference, for example for inserting a new resource, the current APIs to do that are `Value.create` and `Value.patch`.
116+
117+
```ts
118+
let transform = Value.create(Transform);
119+
let vec3 = Value.create(Vec3, { x: 0.0, y: 1.0, z: 2.0 });
120+
transform.translation = vec3;
121+
world.insertResource(Transform, transform);
122+
```
123+
124+
Expect to see changes in this area as we figure out the best way to deal with the interaction of javascript objects and value references.
125+
</details>
5126

6127
## Web support
7128

0 commit comments

Comments
 (0)