@wonderyard/vivarium 0.1.0
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/LICENSE +21 -0
- package/README.md +28 -0
- package/README.md.local +93 -0
- package/dist/automaton/types.d.ts +56 -0
- package/dist/automaton/types.js +1 -0
- package/dist/blueprint/base-blueprint.d.ts +10 -0
- package/dist/blueprint/base-blueprint.js +29 -0
- package/dist/blueprint/helpers.d.ts +9 -0
- package/dist/blueprint/helpers.js +32 -0
- package/dist/blueprint/ref-blueprint.d.ts +24 -0
- package/dist/blueprint/ref-blueprint.js +42 -0
- package/dist/blueprint/rule-blueprint.d.ts +18 -0
- package/dist/blueprint/rule-blueprint.js +7 -0
- package/dist/blueprint/types.d.ts +8 -0
- package/dist/blueprint/types.js +1 -0
- package/dist/blueprint/utils.d.ts +4 -0
- package/dist/blueprint/utils.js +5 -0
- package/dist/blueprint/vivarium-blueprint.d.ts +18 -0
- package/dist/blueprint/vivarium-blueprint.js +47 -0
- package/dist/common/constants.d.ts +64 -0
- package/dist/common/constants.js +14 -0
- package/dist/common/utils.d.ts +1 -0
- package/dist/common/utils.js +53 -0
- package/dist/compiler-CEYR17Vv.js +527 -0
- package/dist/constants-Ry69vZz5.js +2565 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +6 -0
- package/dist/rule-blueprint-Df5BKApy.js +50 -0
- package/dist/vivarium/vivarium.d.ts +3 -0
- package/dist/vivarium/vivarium.js +7 -0
- package/dist/vivarium/vivarium.test.d.ts +1 -0
- package/dist/webgpu/compiler.d.ts +27 -0
- package/dist/webgpu/compiler.js +6 -0
- package/dist/webgpu/setup.d.ts +11 -0
- package/dist/webgpu/setup.js +4348 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 OrangeNote
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# vivarium
|
|
2
|
+
|
|
3
|
+
## Work in progress
|
|
4
|
+
|
|
5
|
+
### Install
|
|
6
|
+
|
|
7
|
+
```shell
|
|
8
|
+
pnpm add @wonderyard/vivarium
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Import
|
|
12
|
+
|
|
13
|
+
```TypeScript
|
|
14
|
+
import { vivarium } from "@wonderyard/vivarium";
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Use
|
|
18
|
+
|
|
19
|
+
```TypeScript
|
|
20
|
+
const vi = vivarium();
|
|
21
|
+
|
|
22
|
+
const space = vi.element("space", "black");
|
|
23
|
+
const cat = vi.element("cat", "orange");
|
|
24
|
+
|
|
25
|
+
space.to(cat).count(cat, 3);
|
|
26
|
+
cat.to(cat).count(cat, [2, 3]);
|
|
27
|
+
cat.to(space);
|
|
28
|
+
```
|
package/README.md.local
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# vivarium
|
|
2
|
+
|
|
3
|
+
A _vivarium_ is a set of elements that interact with each other in a grid, changing into other elements over time. With this library you can define your vivarium and see it evolve on your screen.
|
|
4
|
+
|
|
5
|
+
You can start defining your vivarium like this:
|
|
6
|
+
|
|
7
|
+
```TypeScript
|
|
8
|
+
import { vivarium } from "@wonderyard/vivarium";
|
|
9
|
+
|
|
10
|
+
const vi = vivarium();
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Elements
|
|
14
|
+
|
|
15
|
+
An _element_ is the basic bit of your simulation. It can be represented with a little square on your screen.
|
|
16
|
+
|
|
17
|
+
Here's how to define one.
|
|
18
|
+
|
|
19
|
+
```TypeScript
|
|
20
|
+
const cat = vi.element("cat", "orange");
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
We're not drawing it on the screen yet. For now we are just defining what a cat is, so that our system is aware of its existence in the vivarium.
|
|
24
|
+
|
|
25
|
+
## Kinds
|
|
26
|
+
|
|
27
|
+
The second base concept of vivarium is _kinds_. A kind is not an element, it doesn't have a color and so it cannot be directly represented on a screen. However it can be inherited by elements to share common characteristics. It is not necessary to use _kinds_. Consider it an advanced concept that allows you to write less code and achieve more complex. To start, I'll show you how to define one, which is similar to how we define elements.
|
|
28
|
+
|
|
29
|
+
```TypeScript
|
|
30
|
+
const animal = vi.kind("animal");
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Rules
|
|
34
|
+
|
|
35
|
+
The heart of vivarium is made of _rules_. A rule is a way to tell elements how to behave in our vivarium. Every step of the simulation, an element can become another element or stay the same. Let's see a simple rule first:
|
|
36
|
+
|
|
37
|
+
```TypeScript
|
|
38
|
+
const space = vi.element("space", "white");
|
|
39
|
+
const cat = vi.element("cat", "orange");
|
|
40
|
+
|
|
41
|
+
space.to(cat);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The method `to` can be read as "becomes" or "evolves to". So with this last line, what we are saying is: when we will run the system, at every simulation step, every space element will become a cat element. It's like cats appearing out of nowhere, so on the screen we would see every white cell in the grid becoming orange as soon as we start the simulation. A room filled with cats!
|
|
45
|
+
|
|
46
|
+
## Conditions
|
|
47
|
+
|
|
48
|
+
However in a system like that, nothing interesting would happen after the first step. All free spaces are occupied by cats immediately and they will just sit there forever.
|
|
49
|
+
|
|
50
|
+
Let's create a more interesting system, this time by adding a condition to the existing rule.
|
|
51
|
+
|
|
52
|
+
```TypeScript
|
|
53
|
+
space.to(cat).count(cat, 1);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
By calling the method `count` we are stating that every time the simulation attempts to apply the rule `space.to(cat)` it must first count the number of whatever we pass as first parameter (`cat` in this case) in from the neighborhood of `space` and compare that with the second argument (`1` in this case). If the condition is satisfied, that is, the number of cats in the neighborhood of space is exactly 1, then the rule is applied, otherwise it is skipped for the current step.
|
|
57
|
+
|
|
58
|
+
With this rule, we are filling the room bit by bit in an interesting pattern. It almost looks like a net made of cat tails! Eventually the simulation becomes stable and nothing else happens.
|
|
59
|
+
|
|
60
|
+
## Game of Life
|
|
61
|
+
|
|
62
|
+
Probably the most famous cellular automata, Game of Life rules are not that far from what we created just before. There's many ways to implement Game of Life rules. Here's one version:
|
|
63
|
+
|
|
64
|
+
```TypeScript
|
|
65
|
+
// A new cat is born near a family of 3
|
|
66
|
+
space.to(cat).count(cat, 3);
|
|
67
|
+
// Underpopulation: the cat leaves the space because it feels lonely there
|
|
68
|
+
cat.to(space).count(cat, [0, 1]);
|
|
69
|
+
// Overpopulation: too many cats!
|
|
70
|
+
cat.to(space).count(cat, [4, 5, 6, 7, 8]);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Feel free to come up with your own implementation! Vivarium is designed to allow you to define the same thing in multiple ways, depending on the structure and conventions you want to use.
|
|
74
|
+
|
|
75
|
+
Here's an equivalent list of rule declarations:
|
|
76
|
+
|
|
77
|
+
```TypeScript
|
|
78
|
+
// Same as before
|
|
79
|
+
space.to(cat).count(cat, 3);
|
|
80
|
+
// Cat stays there when the number of cats around it is just right
|
|
81
|
+
cat.to(cat).count(cat, [2, 3]);
|
|
82
|
+
// Cat vanishes :'(
|
|
83
|
+
cat.to(space);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Here we compressed the two `cat.to(space)` rules into one inverse rule, and we let it evolve to space otherwise, unconditionally. Try to reason on why this set of rules is equivalent to the previous one and notice two important things:
|
|
87
|
+
|
|
88
|
+
- Rules without conditions are still meaningful, so use them when they might simplify your overall rule syntax.
|
|
89
|
+
- Order of rules matters!
|
|
90
|
+
|
|
91
|
+
## Order of rules
|
|
92
|
+
|
|
93
|
+
Did I mention it already? Order of rules matters! Yes, because the system has to evaluate rules one by one. Whichever rule satisfies its conditions first, will be the one evolving the cell. No more rules are evaluated for that cell until the next simulation step. In other words, rules are declared in order of priority, high to low. The first rule passing the test is the winner. Every other rule is ignored. So it's important that you design your vivarium with this concept in mind, or your rules won't work as expected.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Accept } from '../common/constants';
|
|
2
|
+
export type Neighborhood = "square" | "cross";
|
|
3
|
+
export type RefType = "element" | "kind";
|
|
4
|
+
export type Kind = {
|
|
5
|
+
type: "kind";
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
export type Color = string;
|
|
10
|
+
export type Automaton = {
|
|
11
|
+
neighborhood: Neighborhood;
|
|
12
|
+
elements: Element[];
|
|
13
|
+
kinds: Kind[];
|
|
14
|
+
rules: Rule[];
|
|
15
|
+
};
|
|
16
|
+
export type Element = {
|
|
17
|
+
type: "element";
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
color: string;
|
|
21
|
+
extensions: string[];
|
|
22
|
+
};
|
|
23
|
+
export type Rule = {
|
|
24
|
+
fromId: string;
|
|
25
|
+
fromType: RefType;
|
|
26
|
+
to: string | Point | undefined;
|
|
27
|
+
when: Condition[];
|
|
28
|
+
accept: Accept;
|
|
29
|
+
};
|
|
30
|
+
export type Condition = Count | Is | Chance;
|
|
31
|
+
export type Count = {
|
|
32
|
+
type: "count";
|
|
33
|
+
id: string;
|
|
34
|
+
check: string | Point | undefined;
|
|
35
|
+
count: number[];
|
|
36
|
+
};
|
|
37
|
+
export type Is = {
|
|
38
|
+
type: "is";
|
|
39
|
+
id: string;
|
|
40
|
+
compare: Point | undefined;
|
|
41
|
+
with: string | Point | undefined;
|
|
42
|
+
};
|
|
43
|
+
export type Ratio = {
|
|
44
|
+
part: number;
|
|
45
|
+
whole: number;
|
|
46
|
+
};
|
|
47
|
+
export type Chance = {
|
|
48
|
+
type: "chance";
|
|
49
|
+
id: string;
|
|
50
|
+
ratio: Ratio;
|
|
51
|
+
};
|
|
52
|
+
export type Strategy = "all" | "any" | "one" | "none";
|
|
53
|
+
export type Point = {
|
|
54
|
+
x: number;
|
|
55
|
+
y: number;
|
|
56
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Automaton, Color } from '../automaton/types';
|
|
2
|
+
import { BlueprintContext } from './types';
|
|
3
|
+
export declare abstract class BaseBlueprint {
|
|
4
|
+
protected abstract automaton: Automaton;
|
|
5
|
+
protected abstract context: BlueprintContext;
|
|
6
|
+
protected assertNotCreated(): void;
|
|
7
|
+
protected assertUniqueName(name: string): void;
|
|
8
|
+
protected assertUniqueColor(color: Color): void;
|
|
9
|
+
protected assertNotEmpty(): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
class o {
|
|
2
|
+
assertNotCreated() {
|
|
3
|
+
if (this.context.created)
|
|
4
|
+
throw new Error("Blueprint methods can no longer be called after create");
|
|
5
|
+
}
|
|
6
|
+
assertUniqueName(e) {
|
|
7
|
+
if (e.trim().length === 0)
|
|
8
|
+
throw new Error("Name cannot be empty");
|
|
9
|
+
if (this.automaton.elements.some((t) => t.name === e))
|
|
10
|
+
throw new Error(`Element with name "${e}" already exists`);
|
|
11
|
+
if (this.automaton.kinds.some((t) => t.name === e))
|
|
12
|
+
throw new Error(`Kind with name "${e}" already exists`);
|
|
13
|
+
}
|
|
14
|
+
assertUniqueColor(e) {
|
|
15
|
+
if (e.trim().length === 0)
|
|
16
|
+
throw new Error("Color cannot be empty");
|
|
17
|
+
if (this.automaton.elements.some((t) => t.color === e))
|
|
18
|
+
throw new Error(`Element with color "${e}" already exists`);
|
|
19
|
+
}
|
|
20
|
+
assertNotEmpty() {
|
|
21
|
+
if (!this.automaton.elements.length)
|
|
22
|
+
throw new Error(
|
|
23
|
+
"No elements found in automaton, at least one element is required"
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
o as BaseBlueprint
|
|
29
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Neighborhood } from '../automaton/types';
|
|
2
|
+
export declare class Helpers {
|
|
3
|
+
private neighborhoodName?;
|
|
4
|
+
constructor(neighborhoodName?: Neighborhood | undefined);
|
|
5
|
+
not(value: number | number[]): number[];
|
|
6
|
+
between(min: number, max: number): number[];
|
|
7
|
+
even(): number[];
|
|
8
|
+
odd(): number[];
|
|
9
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class s {
|
|
2
|
+
constructor(r) {
|
|
3
|
+
this.neighborhoodName = r;
|
|
4
|
+
}
|
|
5
|
+
not(r) {
|
|
6
|
+
const e = this.neighborhoodName === "cross" ? /* @__PURE__ */ new Set([0, 1, 2, 3, 4]) : /* @__PURE__ */ new Set([0, 1, 2, 3, 4, 5, 6, 7, 8]);
|
|
7
|
+
return typeof r == "number" ? e.delete(r) : Array.isArray(r) && r.forEach((o) => {
|
|
8
|
+
e.delete(o);
|
|
9
|
+
}), Array.from(e);
|
|
10
|
+
}
|
|
11
|
+
between(r, e) {
|
|
12
|
+
if (r < 0)
|
|
13
|
+
throw new Error("min cannot be less than 0");
|
|
14
|
+
if (e > 8)
|
|
15
|
+
throw new Error("max cannot be more than 8");
|
|
16
|
+
if (e <= r)
|
|
17
|
+
throw new Error("max cannot be less or equal than min");
|
|
18
|
+
const o = [];
|
|
19
|
+
for (let n = r; n <= e; n++)
|
|
20
|
+
o.push(n);
|
|
21
|
+
return o;
|
|
22
|
+
}
|
|
23
|
+
even() {
|
|
24
|
+
return this.neighborhoodName === "cross" ? [0, 2, 4] : [0, 2, 4, 6, 8];
|
|
25
|
+
}
|
|
26
|
+
odd() {
|
|
27
|
+
return this.neighborhoodName === "cross" ? [1, 3] : [1, 3, 5, 7];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
s as Helpers
|
|
32
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Automaton, Element, Kind, RefType } from '../automaton/types';
|
|
2
|
+
import { BaseBlueprint } from './base-blueprint';
|
|
3
|
+
import { RuleBlueprint } from './rule-blueprint';
|
|
4
|
+
import { AnyNeighbor, BlueprintContext } from './types';
|
|
5
|
+
export declare abstract class RefBlueprint extends BaseBlueprint {
|
|
6
|
+
protected automaton: Automaton;
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
type: RefType;
|
|
10
|
+
constructor(automaton: Automaton, ref: Element | Kind);
|
|
11
|
+
to(elementBlueprintOrNeighbor: ElementBlueprint | AnyNeighbor): RuleBlueprint;
|
|
12
|
+
}
|
|
13
|
+
export declare class ElementBlueprint extends RefBlueprint {
|
|
14
|
+
protected context: BlueprintContext;
|
|
15
|
+
type: "element";
|
|
16
|
+
id: string;
|
|
17
|
+
constructor(context: BlueprintContext, automaton: Automaton, element: Element);
|
|
18
|
+
}
|
|
19
|
+
export declare class KindBlueprint extends RefBlueprint {
|
|
20
|
+
protected context: BlueprintContext;
|
|
21
|
+
type: "kind";
|
|
22
|
+
id: string;
|
|
23
|
+
constructor(context: BlueprintContext, automaton: Automaton, kind: Kind);
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { BaseBlueprint as r } from "./base-blueprint.js";
|
|
2
|
+
import { R as n } from "../rule-blueprint-Df5BKApy.js";
|
|
3
|
+
import { toRefIdOrPoint as p } from "./utils.js";
|
|
4
|
+
import { A as u } from "../constants-Ry69vZz5.js";
|
|
5
|
+
class o extends r {
|
|
6
|
+
constructor(e, t) {
|
|
7
|
+
super(), this.automaton = e, this.id = t.id, this.name = t.name, this.type = t.type;
|
|
8
|
+
}
|
|
9
|
+
id;
|
|
10
|
+
name;
|
|
11
|
+
type;
|
|
12
|
+
to(e) {
|
|
13
|
+
this.assertNotCreated();
|
|
14
|
+
const t = {
|
|
15
|
+
fromId: this.id,
|
|
16
|
+
fromType: this.type,
|
|
17
|
+
to: p(e),
|
|
18
|
+
when: [],
|
|
19
|
+
accept: u.ALL
|
|
20
|
+
};
|
|
21
|
+
return this.automaton.rules.push(t), new n(this.context, this.automaton, t);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
class h extends o {
|
|
25
|
+
constructor(e, t, s) {
|
|
26
|
+
super(t, s), this.context = e, this.id = s.id;
|
|
27
|
+
}
|
|
28
|
+
type = "element";
|
|
29
|
+
id;
|
|
30
|
+
}
|
|
31
|
+
class l extends o {
|
|
32
|
+
constructor(e, t, s) {
|
|
33
|
+
super(t, s), this.context = e, this.id = s.id;
|
|
34
|
+
}
|
|
35
|
+
type = "kind";
|
|
36
|
+
id;
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
h as ElementBlueprint,
|
|
40
|
+
l as KindBlueprint,
|
|
41
|
+
o as RefBlueprint
|
|
42
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Automaton, Rule, Strategy } from '../automaton/types';
|
|
2
|
+
import { BaseBlueprint } from './base-blueprint';
|
|
3
|
+
import { RefBlueprint } from './ref-blueprint';
|
|
4
|
+
import { AnyNeighbor, BlueprintContext } from './types';
|
|
5
|
+
export declare class RuleBlueprint extends BaseBlueprint {
|
|
6
|
+
protected context: BlueprintContext;
|
|
7
|
+
protected automaton: Automaton;
|
|
8
|
+
protected rule: Rule;
|
|
9
|
+
constructor(context: BlueprintContext, automaton: Automaton, rule: Rule);
|
|
10
|
+
private condition;
|
|
11
|
+
count(refBlueprintOrNeighbor: RefBlueprint | AnyNeighbor, count?: number | number[]): RuleBlueprintWithAccept;
|
|
12
|
+
is(neighbor: AnyNeighbor, refBlueprintOrNeighbor: RefBlueprint | AnyNeighbor): RuleBlueprintWithAccept;
|
|
13
|
+
chance(part: number, whole?: number): RuleBlueprintWithAccept;
|
|
14
|
+
}
|
|
15
|
+
declare class RuleBlueprintWithAccept extends RuleBlueprint {
|
|
16
|
+
accept(strategy: Strategy): void;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Cross, Square } from '../common/constants';
|
|
2
|
+
export type AnyNeighbor = Cross | Square;
|
|
3
|
+
export type Neighbor<N> = N extends "cross" ? Cross : Square;
|
|
4
|
+
export type ConditionStrategy = "all" | "any" | "one" | "none";
|
|
5
|
+
export type ConditionExpression = (neighborhood: Uint8Array, x: number, y: number) => boolean;
|
|
6
|
+
export type BlueprintContext = {
|
|
7
|
+
created: boolean;
|
|
8
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Automaton, Color, Neighborhood } from '../automaton/types';
|
|
2
|
+
import { BaseBlueprint } from './base-blueprint';
|
|
3
|
+
import { Helpers } from './helpers';
|
|
4
|
+
import { ElementBlueprint, KindBlueprint } from './ref-blueprint';
|
|
5
|
+
import { Cross, Square } from '../common/constants';
|
|
6
|
+
export declare class VivariumBlueprint<N extends Neighborhood = "square"> extends BaseBlueprint {
|
|
7
|
+
private neighborhoodName?;
|
|
8
|
+
protected automaton: Automaton;
|
|
9
|
+
protected context: {
|
|
10
|
+
created: boolean;
|
|
11
|
+
};
|
|
12
|
+
neighbor: N extends "cross" ? typeof Cross : typeof Square;
|
|
13
|
+
helpers: Helpers;
|
|
14
|
+
constructor(neighborhoodName?: N | undefined);
|
|
15
|
+
element(name: string, color: Color, extensions?: KindBlueprint[]): ElementBlueprint;
|
|
16
|
+
kind(name: string): KindBlueprint;
|
|
17
|
+
create(): Automaton;
|
|
18
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { n as o } from "../rule-blueprint-Df5BKApy.js";
|
|
2
|
+
import { BaseBlueprint as n } from "./base-blueprint.js";
|
|
3
|
+
import { Helpers as a } from "./helpers.js";
|
|
4
|
+
import { ElementBlueprint as h, KindBlueprint as m } from "./ref-blueprint.js";
|
|
5
|
+
import { C as u, S as p } from "../constants-Ry69vZz5.js";
|
|
6
|
+
class C extends n {
|
|
7
|
+
constructor(t) {
|
|
8
|
+
super(), this.neighborhoodName = t, this.helpers = new a(this.neighborhoodName), this.neighbor = this.neighborhoodName === "cross" ? u : p, this.automaton = {
|
|
9
|
+
neighborhood: t ?? "square",
|
|
10
|
+
elements: [],
|
|
11
|
+
kinds: [],
|
|
12
|
+
rules: []
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
automaton;
|
|
16
|
+
context = { created: !1 };
|
|
17
|
+
neighbor;
|
|
18
|
+
helpers;
|
|
19
|
+
element(t, e, r = []) {
|
|
20
|
+
this.assertNotCreated(), this.assertUniqueName(t), this.assertUniqueColor(e);
|
|
21
|
+
const s = {
|
|
22
|
+
type: "element",
|
|
23
|
+
id: o(),
|
|
24
|
+
name: t,
|
|
25
|
+
color: e,
|
|
26
|
+
extensions: r.map((i) => i.id)
|
|
27
|
+
};
|
|
28
|
+
return this.automaton.elements.push(s), new h(this.context, this.automaton, s);
|
|
29
|
+
}
|
|
30
|
+
kind(t) {
|
|
31
|
+
this.assertNotCreated(), this.assertUniqueName(t);
|
|
32
|
+
const e = {
|
|
33
|
+
type: "kind",
|
|
34
|
+
id: o(),
|
|
35
|
+
name: t
|
|
36
|
+
};
|
|
37
|
+
return this.automaton.kinds.push(e), new m(this.context, this.automaton, e);
|
|
38
|
+
}
|
|
39
|
+
create() {
|
|
40
|
+
this.assertNotCreated(), this.assertNotEmpty();
|
|
41
|
+
const t = this.automaton;
|
|
42
|
+
return this.context.created = !0, t;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
C as VivariumBlueprint
|
|
47
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Point, Strategy } from '../automaton/types';
|
|
2
|
+
import * as d from "typegpu/data";
|
|
3
|
+
export declare enum Square {
|
|
4
|
+
TOP_LEFT = "TOP_LEFT",
|
|
5
|
+
TOP = "TOP",
|
|
6
|
+
TOP_RIGHT = "TOP_RIGHT",
|
|
7
|
+
LEFT = "LEFT",
|
|
8
|
+
SELF = "SELF",
|
|
9
|
+
RIGHT = "RIGHT",
|
|
10
|
+
BOTTOM_LEFT = "BOTTOM_LEFT",
|
|
11
|
+
BOTTOM = "BOTTOM",
|
|
12
|
+
BOTTOM_RIGHT = "BOTTOM_RIGHT"
|
|
13
|
+
}
|
|
14
|
+
export declare enum Cross {
|
|
15
|
+
TOP = "TOP",
|
|
16
|
+
LEFT = "LEFT",
|
|
17
|
+
SELF = "SELF",
|
|
18
|
+
RIGHT = "RIGHT",
|
|
19
|
+
BOTTOM = "BOTTOM"
|
|
20
|
+
}
|
|
21
|
+
export declare const neighborhoodPoints: Record<Square, Point>;
|
|
22
|
+
export declare enum To {
|
|
23
|
+
ELEMENT_ID = 0,
|
|
24
|
+
POINT = 1
|
|
25
|
+
}
|
|
26
|
+
export declare enum Opcode {
|
|
27
|
+
NOOP = 0,
|
|
28
|
+
COUNT_ELEMENT = 1,
|
|
29
|
+
COUNT_POINT = 2,
|
|
30
|
+
COUNT_KIND = 3,
|
|
31
|
+
IS_ELEMENT = 4,
|
|
32
|
+
IS_POINT = 5,
|
|
33
|
+
IS_KIND = 6,
|
|
34
|
+
CHANCE = 7
|
|
35
|
+
}
|
|
36
|
+
export declare enum Accept {
|
|
37
|
+
ALL = 0,
|
|
38
|
+
ANY = 1,
|
|
39
|
+
ONE = 2,
|
|
40
|
+
NONE = 3
|
|
41
|
+
}
|
|
42
|
+
export declare const acceptMap: Record<Strategy, Accept>;
|
|
43
|
+
export declare const GpuElement: d.WgslStruct<{
|
|
44
|
+
color: d.U32;
|
|
45
|
+
ruleStart: d.U32;
|
|
46
|
+
ruleEnd: d.U32;
|
|
47
|
+
}>;
|
|
48
|
+
export declare const GpuRule: d.WgslStruct<{
|
|
49
|
+
toType: d.U32;
|
|
50
|
+
toId: d.U32;
|
|
51
|
+
toNeighbor: d.Vec2u;
|
|
52
|
+
accept: d.U32;
|
|
53
|
+
conditionsStart: d.U32;
|
|
54
|
+
conditionsEnd: d.U32;
|
|
55
|
+
}>;
|
|
56
|
+
export declare const GpuCondition: d.WgslStruct<{
|
|
57
|
+
opcode: d.U32;
|
|
58
|
+
checkId: d.U32;
|
|
59
|
+
countOrWithId: d.U32;
|
|
60
|
+
checkPointOrComparePoint: d.Vec2u;
|
|
61
|
+
withPoint: d.Vec2u;
|
|
62
|
+
chance: d.F32;
|
|
63
|
+
}>;
|
|
64
|
+
export declare const WORKGROUP_SIZE: [number, number];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { A as o, C as e, a5 as p, a1 as c, a2 as n, a6 as t, S as r, a4 as u, cf as i, a7 as G, n as d } from "../constants-Ry69vZz5.js";
|
|
2
|
+
export {
|
|
3
|
+
o as Accept,
|
|
4
|
+
e as Cross,
|
|
5
|
+
p as GpuCondition,
|
|
6
|
+
c as GpuElement,
|
|
7
|
+
n as GpuRule,
|
|
8
|
+
t as Opcode,
|
|
9
|
+
r as Square,
|
|
10
|
+
u as To,
|
|
11
|
+
i as WORKGROUP_SIZE,
|
|
12
|
+
G as acceptMap,
|
|
13
|
+
d as neighborhoodPoints
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const colorToABGR: (color: string) => number;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const u = (e) => {
|
|
2
|
+
switch (e.toLowerCase()) {
|
|
3
|
+
case "black":
|
|
4
|
+
return "#000000";
|
|
5
|
+
case "silver":
|
|
6
|
+
return "#c0c0c0";
|
|
7
|
+
case "gray":
|
|
8
|
+
return "#808080";
|
|
9
|
+
case "white":
|
|
10
|
+
return "#ffffff";
|
|
11
|
+
case "maroon":
|
|
12
|
+
return "#800000";
|
|
13
|
+
case "red":
|
|
14
|
+
return "#ff0000";
|
|
15
|
+
case "purple":
|
|
16
|
+
return "#800080";
|
|
17
|
+
case "fuchsia":
|
|
18
|
+
return "#ff00ff";
|
|
19
|
+
case "green":
|
|
20
|
+
return "#008000";
|
|
21
|
+
case "lime":
|
|
22
|
+
return "#00ff00";
|
|
23
|
+
case "olive":
|
|
24
|
+
return "#808000";
|
|
25
|
+
case "yellow":
|
|
26
|
+
return "#ffff00";
|
|
27
|
+
case "navy":
|
|
28
|
+
return "#000080";
|
|
29
|
+
case "blue":
|
|
30
|
+
return "#0000ff";
|
|
31
|
+
case "teal":
|
|
32
|
+
return "#008080";
|
|
33
|
+
case "aqua":
|
|
34
|
+
return "#00ffff";
|
|
35
|
+
default:
|
|
36
|
+
return e;
|
|
37
|
+
}
|
|
38
|
+
}, l = (e) => {
|
|
39
|
+
e = u(e);
|
|
40
|
+
const n = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
|
41
|
+
e = e.replace(
|
|
42
|
+
n,
|
|
43
|
+
(d, a, t, f) => a + a + t + t + f + f
|
|
44
|
+
);
|
|
45
|
+
const r = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);
|
|
46
|
+
if (!r)
|
|
47
|
+
throw new Error("Bad color");
|
|
48
|
+
const s = parseInt(r[1], 16), c = parseInt(r[2], 16);
|
|
49
|
+
return 4278190080 | parseInt(r[3], 16) << 16 | c << 8 | s;
|
|
50
|
+
};
|
|
51
|
+
export {
|
|
52
|
+
l as colorToABGR
|
|
53
|
+
};
|