Skip to content

Commit 6aa3bb9

Browse files
readme ✨
1 parent 4ac541e commit 6aa3bb9

File tree

1 file changed

+121
-2
lines changed

1 file changed

+121
-2
lines changed

README.md

+121-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,126 @@
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+
In `bevy_ecs`, the common methods for dealing with ECS values all take a type parameter, like
60+
```rs
61+
world.resource::<T>(); // or
62+
world.query<(Entity, &Component)>();
63+
```
64+
Ideally we would be able to write
65+
```ts
66+
let time = world.resource<Time>();
67+
```
68+
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.
69+
70+
71+
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.
72+
73+
```ts
74+
type Transform = {
75+
translation: Vec3,
76+
rotation: Quat,
77+
scale: Vec3,
78+
};
79+
const Transform: BevyType<Transform> = {
80+
typeName: "bevy_transform::components::global_transform::GlobalTransform"
81+
};
82+
83+
// `world.resource` is typed so that typescript can infer `transform` to be of type `Transform | undefined`
84+
let transform = world.resource(Transform);
85+
```
86+
87+
Similarly, queries list their types like
88+
```ts
89+
for (item of world.query(Ball, Velocity)) {
90+
info(item.entity);
91+
let [_ball, velocity] = item.components;
92+
// velocity is properly typed
93+
}
94+
```
95+
96+
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.
97+
98+
</details>
99+
<details>
100+
<summary>Javascript Values & ECS Value references</summary>
101+
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.
102+
103+
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.
104+
105+
This means that
106+
```ts
107+
let transform = world.resource(Transform);
108+
let translation = transform.translation;
109+
// typeof translation.x == "number"
110+
translation.x = 3.0;
111+
```
112+
113+
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`.
114+
115+
```ts
116+
let transform = Value.create(Transform);
117+
let vec3 = Value.create(Vec3, { x: 0.0, y: 1.0, z: 2.0 });
118+
transform.translation = vec3;
119+
world.insertResource(Transform, transform);
120+
```
121+
122+
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.
123+
</details>
5124

6125
## Web support
7126

0 commit comments

Comments
 (0)