@fundamental-engine/three 0.4.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 +131 -0
- package/dist/agents.d.ts +73 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +114 -0
- package/dist/agents.js.map +1 -0
- package/dist/backend.d.ts +33 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +120 -0
- package/dist/backend.js.map +1 -0
- package/dist/bodies.d.ts +79 -0
- package/dist/bodies.d.ts.map +1 -0
- package/dist/bodies.js +137 -0
- package/dist/bodies.js.map +1 -0
- package/dist/host.d.ts +23 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +62 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/layer.d.ts +115 -0
- package/dist/layer.d.ts.map +1 -0
- package/dist/layer.js +173 -0
- package/dist/layer.js.map +1 -0
- package/dist/particles.d.ts +58 -0
- package/dist/particles.d.ts.map +1 -0
- package/dist/particles.js +127 -0
- package/dist/particles.js.map +1 -0
- package/dist/project.d.ts +111 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +95 -0
- package/dist/project.js.map +1 -0
- package/dist/samplers.d.ts +81 -0
- package/dist/samplers.d.ts.map +1 -0
- package/dist/samplers.js +143 -0
- package/dist/samplers.js.map +1 -0
- package/package.json +64 -0
package/dist/bodies.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meshes as bodies — the 3D form of field-ui's core idea ("every element is a body"). A
|
|
3
|
+
* `THREE.Object3D` registers as a field body: it bends the field (bodies are force sources), the
|
|
4
|
+
* swarm responds to it, and the field's local density bends *it* back through feedback. And because
|
|
5
|
+
* a body **carries a data record**, a mesh can be a meaningful agent — a bloom carrying its genome,
|
|
6
|
+
* a hive accumulating honey — not just a force.
|
|
7
|
+
*
|
|
8
|
+
* It needs no core change: the engine builds a body from anything implementing the small element
|
|
9
|
+
* contract (`getAttribute` / `hasAttribute` / `dataset` / `getBoundingClientRect`), so each body is a
|
|
10
|
+
* lightweight non-DOM "virtual element" whose rect is the mesh's position projected onto the field
|
|
11
|
+
* plane, refreshed live as the mesh moves. Feedback is routed to the body via a custom sink, so
|
|
12
|
+
* `density` / `load` / `lit` land on the mesh (drive a uniform, accumulate a value) instead of CSS.
|
|
13
|
+
*/
|
|
14
|
+
import { Vector3 } from 'three';
|
|
15
|
+
const _w = new Vector3();
|
|
16
|
+
class BodyImpl {
|
|
17
|
+
object;
|
|
18
|
+
data;
|
|
19
|
+
channels = {};
|
|
20
|
+
el;
|
|
21
|
+
onFeedback;
|
|
22
|
+
registry;
|
|
23
|
+
constructor(registry, object, spec) {
|
|
24
|
+
this.registry = registry;
|
|
25
|
+
this.object = object;
|
|
26
|
+
this.data = spec.data;
|
|
27
|
+
this.onFeedback = spec.onFeedback;
|
|
28
|
+
const tokens = Array.isArray(spec.tokens) ? spec.tokens.join(' ') : String(spec.tokens);
|
|
29
|
+
const attrs = { 'data-body': tokens, ...prefixed(spec.attrs) };
|
|
30
|
+
if (spec.strength != null)
|
|
31
|
+
attrs['data-strength'] = String(spec.strength);
|
|
32
|
+
if (spec.range != null)
|
|
33
|
+
attrs['data-range'] = String(spec.range);
|
|
34
|
+
if (spec.spin != null)
|
|
35
|
+
attrs['data-spin'] = String(spec.spin);
|
|
36
|
+
if (spec.angle != null)
|
|
37
|
+
attrs['data-angle'] = String(spec.angle);
|
|
38
|
+
if (spec.feedback ?? true)
|
|
39
|
+
attrs['data-feedback'] = '';
|
|
40
|
+
const half = (spec.sizePx ?? 20) / 2;
|
|
41
|
+
const self = this;
|
|
42
|
+
this.el = {
|
|
43
|
+
// the scanner reads tint from `el.dataset.color` (not getAttribute), so it lives here
|
|
44
|
+
dataset: spec.color != null ? { color: spec.color } : {},
|
|
45
|
+
getAttribute: (n) => attrs[n] ?? null,
|
|
46
|
+
hasAttribute: (n) => n in attrs,
|
|
47
|
+
getBoundingClientRect: () => {
|
|
48
|
+
const f = registry.projectToField(self.object);
|
|
49
|
+
return {
|
|
50
|
+
left: f.x - half,
|
|
51
|
+
top: f.y - half,
|
|
52
|
+
right: f.x + half,
|
|
53
|
+
bottom: f.y + half,
|
|
54
|
+
width: half * 2,
|
|
55
|
+
height: half * 2,
|
|
56
|
+
x: f.x - half,
|
|
57
|
+
y: f.y - half,
|
|
58
|
+
toJSON: () => ({}),
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
__body: this,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** routed from the registry's sink — store the channels and notify. */
|
|
65
|
+
receive(channels) {
|
|
66
|
+
this.channels = channels;
|
|
67
|
+
this.onFeedback?.(channels, this);
|
|
68
|
+
}
|
|
69
|
+
remove() {
|
|
70
|
+
this.registry.remove(this);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function prefixed(attrs) {
|
|
74
|
+
if (!attrs)
|
|
75
|
+
return {};
|
|
76
|
+
const out = {};
|
|
77
|
+
for (const [k, v] of Object.entries(attrs))
|
|
78
|
+
out[k.startsWith('data-') ? k : `data-${k}`] = v;
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Manages the mesh-bodies for one field. Provides the `root` the host scans and the `sink` that
|
|
83
|
+
* routes feedback to meshes; a `FieldLayer` wires both. Add via `layer.addBody(...)`.
|
|
84
|
+
*/
|
|
85
|
+
export class FieldBodyRegistry {
|
|
86
|
+
bodies = [];
|
|
87
|
+
projection;
|
|
88
|
+
onChange = () => { };
|
|
89
|
+
constructor(projection) {
|
|
90
|
+
this.projection = projection;
|
|
91
|
+
}
|
|
92
|
+
/** project a scene object's world position onto the field plane (field pixels). */
|
|
93
|
+
projectToField(object) {
|
|
94
|
+
object.getWorldPosition(_w);
|
|
95
|
+
return this.projection.toField(_w);
|
|
96
|
+
}
|
|
97
|
+
/** internal — the FieldLayer re-points this if the projection changes. */
|
|
98
|
+
setProjection(projection) {
|
|
99
|
+
this.projection = projection;
|
|
100
|
+
}
|
|
101
|
+
/** internal — the FieldLayer wires this to `field.scan()` so adds/removes re-register. */
|
|
102
|
+
setOnChange(fn) {
|
|
103
|
+
this.onChange = fn;
|
|
104
|
+
}
|
|
105
|
+
/** the scan root the host hands the engine: `[data-body]` queries return the live mesh-bodies. */
|
|
106
|
+
get root() {
|
|
107
|
+
const self = this;
|
|
108
|
+
return {
|
|
109
|
+
querySelectorAll: (sel) => (sel.startsWith('[data-body]') ? self.bodies.map((b) => b.el) : []),
|
|
110
|
+
querySelector: () => null,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/** the feedback sink the field writes through — lands density/load/lit on the body's mesh. */
|
|
114
|
+
get sink() {
|
|
115
|
+
return ((el, channels) => {
|
|
116
|
+
el.__body?.receive(channels);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
add(object, spec) {
|
|
120
|
+
const body = new BodyImpl(this, object, spec);
|
|
121
|
+
this.bodies.push(body);
|
|
122
|
+
this.onChange();
|
|
123
|
+
return body;
|
|
124
|
+
}
|
|
125
|
+
remove(body) {
|
|
126
|
+
const i = this.bodies.indexOf(body);
|
|
127
|
+
if (i >= 0) {
|
|
128
|
+
this.bodies.splice(i, 1);
|
|
129
|
+
this.onChange();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** every registered body (read-only). */
|
|
133
|
+
all() {
|
|
134
|
+
return this.bodies;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=bodies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bodies.js","sourceRoot":"","sources":["../src/bodies.ts"],"names":[],"mappings":"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"}
|
package/dist/host.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `threeHost` — the `FieldHost` for a WebGL scene. The engine is renderer-agnostic: it reaches the
|
|
3
|
+
* environment (viewport, animation frame, visibility, input) only through an injected host. This is
|
|
4
|
+
* the host a Three.js embedding wires — close to `browserHost()`, but the field's viewport comes
|
|
5
|
+
* from the projection (the field's own pixel space), not `window.innerWidth`, and page-scroll
|
|
6
|
+
* coupling is off by default (a 3D field has no document scroll unless you opt in).
|
|
7
|
+
*
|
|
8
|
+
* `@fundamental-engine/three` is an authoring surface, so unlike `@fundamental-engine/core` it may touch the DOM — the
|
|
9
|
+
* browser globals here are the same ones any Three.js app already depends on.
|
|
10
|
+
*/
|
|
11
|
+
import type { FieldHost, HostViewport } from '@fundamental-engine/core';
|
|
12
|
+
export interface ThreeHostOptions {
|
|
13
|
+
/** field-space viewport (CSS pixels) + device-pixel ratio. Wire this to your `FieldProjection`. */
|
|
14
|
+
viewport: () => HostViewport;
|
|
15
|
+
/** the subtree scanned for `[data-body]` bodies; omit for a field with no DOM bodies. */
|
|
16
|
+
root?: ParentNode;
|
|
17
|
+
/** opt page scroll into the field (drives `scrollV()` / the `scrolling` gate); default off. */
|
|
18
|
+
scrollY?: () => number;
|
|
19
|
+
/** total scrollable height when scroll is opted in; defaults to the viewport height. */
|
|
20
|
+
scrollHeight?: () => number;
|
|
21
|
+
}
|
|
22
|
+
export declare function threeHost(opts: ThreeHostOptions): FieldHost;
|
|
23
|
+
//# sourceMappingURL=host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAQxE,MAAM,WAAW,gBAAgB;IAC/B,mGAAmG;IACnG,QAAQ,EAAE,MAAM,YAAY,CAAC;IAC7B,yFAAyF;IACzF,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;IACvB,wFAAwF;IACxF,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,CA2C3D"}
|
package/dist/host.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `threeHost` — the `FieldHost` for a WebGL scene. The engine is renderer-agnostic: it reaches the
|
|
3
|
+
* environment (viewport, animation frame, visibility, input) only through an injected host. This is
|
|
4
|
+
* the host a Three.js embedding wires — close to `browserHost()`, but the field's viewport comes
|
|
5
|
+
* from the projection (the field's own pixel space), not `window.innerWidth`, and page-scroll
|
|
6
|
+
* coupling is off by default (a 3D field has no document scroll unless you opt in).
|
|
7
|
+
*
|
|
8
|
+
* `@fundamental-engine/three` is an authoring surface, so unlike `@fundamental-engine/core` it may touch the DOM — the
|
|
9
|
+
* browser globals here are the same ones any Three.js app already depends on.
|
|
10
|
+
*/
|
|
11
|
+
/** A scan root that exposes no `[data-body]` elements — the default for a synthetic / 3D field. */
|
|
12
|
+
const EMPTY_ROOT = {
|
|
13
|
+
querySelectorAll: () => [],
|
|
14
|
+
querySelector: () => null,
|
|
15
|
+
};
|
|
16
|
+
export function threeHost(opts) {
|
|
17
|
+
const root = opts.root ?? EMPTY_ROOT;
|
|
18
|
+
const events = root.addEventListener
|
|
19
|
+
? root
|
|
20
|
+
: typeof document !== 'undefined'
|
|
21
|
+
? document
|
|
22
|
+
: null;
|
|
23
|
+
return {
|
|
24
|
+
root,
|
|
25
|
+
viewport: opts.viewport,
|
|
26
|
+
scrollY: opts.scrollY ?? (() => 0),
|
|
27
|
+
scrollHeight: opts.scrollHeight ?? (() => Math.max(1, opts.viewport().height)),
|
|
28
|
+
reducedMotion: () => typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches,
|
|
29
|
+
hidden: () => typeof document !== 'undefined' && document.hidden,
|
|
30
|
+
raf: (cb) => requestAnimationFrame(cb),
|
|
31
|
+
cancelRaf: (id) => cancelAnimationFrame(id),
|
|
32
|
+
createCanvas: () => document.createElement('canvas'),
|
|
33
|
+
onResize: (cb) => {
|
|
34
|
+
window.addEventListener('resize', cb, { passive: true });
|
|
35
|
+
return () => window.removeEventListener('resize', cb);
|
|
36
|
+
},
|
|
37
|
+
// a 3D field is not coupled to document scroll by default — opt in via host options if wanted.
|
|
38
|
+
onScroll: () => () => { },
|
|
39
|
+
onVisibility: (cb) => {
|
|
40
|
+
if (typeof document === 'undefined')
|
|
41
|
+
return () => { };
|
|
42
|
+
document.addEventListener('visibilitychange', cb);
|
|
43
|
+
return () => document.removeEventListener('visibilitychange', cb);
|
|
44
|
+
},
|
|
45
|
+
onInput: (cb) => {
|
|
46
|
+
const evs = ['pointermove', 'pointerdown', 'wheel', 'keydown', 'touchstart'];
|
|
47
|
+
for (const e of evs)
|
|
48
|
+
window.addEventListener(e, cb, { passive: true });
|
|
49
|
+
return () => {
|
|
50
|
+
for (const e of evs)
|
|
51
|
+
window.removeEventListener(e, cb);
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
onBodyEvent: (type, cb) => {
|
|
55
|
+
if (!events)
|
|
56
|
+
return () => { };
|
|
57
|
+
events.addEventListener(type, cb);
|
|
58
|
+
return () => events.removeEventListener(type, cb);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=host.js.map
|
package/dist/host.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@fundamental-engine/three` — the Three.js door to the reciprocal field.
|
|
3
|
+
*
|
|
4
|
+
* The same engine the `<field-root>` custom element and `@fundamental-engine/{vanilla,react}` wrap, bound to a
|
|
5
|
+
* WebGL scene instead of the DOM. Two paths, composable:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Particle bridge** (`createFieldLayer`) — run the engine headless and render its swarm as a
|
|
8
|
+
* `THREE.Points` layer you add to your scene. The fast path to the field in 3D.
|
|
9
|
+
* 2. **RenderBackend** (`threeBackend`) — implement the engine's structural drawing seam so the
|
|
10
|
+
* diagnostic overlays (streamlines, field-lines, grid, contours) draw as scene geometry. Inject
|
|
11
|
+
* via `createThreeField({ overlayBackend })`.
|
|
12
|
+
*
|
|
13
|
+
* `three` is a peer dependency — you bring your own version. The `FieldProjection` seam keeps the
|
|
14
|
+
* coordinate model swappable: `PlaneProjection` ships now; a volumetric mode slots in later.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { createFieldLayer, PlaneProjection } from '@fundamental-engine/three';
|
|
18
|
+
* const layer = createFieldLayer({ projection: new PlaneProjection({ relief: 2 }), accent: '#4da3ff' });
|
|
19
|
+
* scene.add(layer.object);
|
|
20
|
+
* // render loop: layer.tick(); renderer.render(scene, camera);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export { FieldLayer, createFieldLayer, createThreeField } from './layer.ts';
|
|
24
|
+
export type { FieldLayerOptions, ThreeFieldOptions } from './layer.ts';
|
|
25
|
+
export { threeHost } from './host.ts';
|
|
26
|
+
export type { ThreeHostOptions } from './host.ts';
|
|
27
|
+
export { threeBackend } from './backend.ts';
|
|
28
|
+
export type { ThreeBackend, ThreeBackendOptions } from './backend.ts';
|
|
29
|
+
export { ParticlePool } from './particles.ts';
|
|
30
|
+
export type { ParticlePoolOptions, ParticleStyle } from './particles.ts';
|
|
31
|
+
export { PlaneProjection, VolumeProjection } from './project.ts';
|
|
32
|
+
export type { FieldProjection, PlaneProjectionOptions, VolumeProjectionOptions } from './project.ts';
|
|
33
|
+
export { FieldBodyRegistry } from './bodies.ts';
|
|
34
|
+
export type { FieldBody, FieldBodySpec } from './bodies.ts';
|
|
35
|
+
export { vectorField, streamlineTubes, traceStreamline } from './samplers.ts';
|
|
36
|
+
export type { FieldSampler, FieldVisual, VectorFieldOptions, StreamlineTubesOptions } from './samplers.ts';
|
|
37
|
+
export { FieldAgent } from './agents.ts';
|
|
38
|
+
export type { FieldAgentOptions } from './agents.ts';
|
|
39
|
+
export { forceAt, netField } from '@fundamental-engine/core';
|
|
40
|
+
export type { FieldHandle, FieldOptions, Particle, Body } from '@fundamental-engine/core';
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC5E,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjE,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAErG,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC9E,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAE3G,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIrD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@fundamental-engine/three` — the Three.js door to the reciprocal field.
|
|
3
|
+
*
|
|
4
|
+
* The same engine the `<field-root>` custom element and `@fundamental-engine/{vanilla,react}` wrap, bound to a
|
|
5
|
+
* WebGL scene instead of the DOM. Two paths, composable:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Particle bridge** (`createFieldLayer`) — run the engine headless and render its swarm as a
|
|
8
|
+
* `THREE.Points` layer you add to your scene. The fast path to the field in 3D.
|
|
9
|
+
* 2. **RenderBackend** (`threeBackend`) — implement the engine's structural drawing seam so the
|
|
10
|
+
* diagnostic overlays (streamlines, field-lines, grid, contours) draw as scene geometry. Inject
|
|
11
|
+
* via `createThreeField({ overlayBackend })`.
|
|
12
|
+
*
|
|
13
|
+
* `three` is a peer dependency — you bring your own version. The `FieldProjection` seam keeps the
|
|
14
|
+
* coordinate model swappable: `PlaneProjection` ships now; a volumetric mode slots in later.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { createFieldLayer, PlaneProjection } from '@fundamental-engine/three';
|
|
18
|
+
* const layer = createFieldLayer({ projection: new PlaneProjection({ relief: 2 }), accent: '#4da3ff' });
|
|
19
|
+
* scene.add(layer.object);
|
|
20
|
+
* // render loop: layer.tick(); renderer.render(scene, camera);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export { FieldLayer, createFieldLayer, createThreeField } from "./layer.js";
|
|
24
|
+
export { threeHost } from "./host.js";
|
|
25
|
+
export { threeBackend } from "./backend.js";
|
|
26
|
+
export { ParticlePool } from "./particles.js";
|
|
27
|
+
export { PlaneProjection, VolumeProjection } from "./project.js";
|
|
28
|
+
// Meshes as bodies — register an Object3D as a field body carrying a data record.
|
|
29
|
+
export { FieldBodyRegistry } from "./bodies.js";
|
|
30
|
+
// Native 3D field visuals — vector grids + streamline tubes from FieldHandle.sample().
|
|
31
|
+
export { vectorField, streamlineTubes, traceStreamline } from "./samplers.js";
|
|
32
|
+
// FieldAgent — an Object3D that rides the field: the creatures primitive (bees, fish, drones).
|
|
33
|
+
export { FieldAgent } from "./agents.js";
|
|
34
|
+
// Re-export the field samplers from core so a Three.js consumer building its own field visuals
|
|
35
|
+
// (3D streamline tubes, vector grids, density) has them without a second import.
|
|
36
|
+
export { forceAt, netField } from '@fundamental-engine/core';
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEjE,kFAAkF;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,uFAAuF;AACvF,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE9E,+FAA+F;AAC/F,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,+FAA+F;AAC/F,iFAAiF;AACjF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/layer.d.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `FieldLayer` — the field as a Three.js object. It runs the engine headless (`render: 'none'`) on a
|
|
3
|
+
* `threeHost`, owns a `ParticlePool`, and on every `tick()` syncs the live swarm onto a
|
|
4
|
+
* `THREE.Points` you add to your scene via `layer.object`. It implements the full `FieldHandle`
|
|
5
|
+
* surface (delegating to the wrapped engine), so `burst` / `flowTo` / `setFormation` / `seed` drive
|
|
6
|
+
* the 3D layer exactly as they drive the DOM field.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const layer = createFieldLayer({ projection: new PlaneProjection({ relief: 2 }), accent: '#4da3ff' });
|
|
10
|
+
* scene.add(layer.object);
|
|
11
|
+
* // render loop:
|
|
12
|
+
* layer.tick(); // engine self-steps via rAF; tick() pulls the latest swarm
|
|
13
|
+
* renderer.render(scene, camera);
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* The engine self-advances on the host's animation frame; `tick()` only reads the current state into
|
|
17
|
+
* the geometry, so it is safe to call from any render loop at any cadence.
|
|
18
|
+
*/
|
|
19
|
+
import type { AtomPayload, FieldHandle, FieldOptions, FlowOptions, HostViewport, ThreadLink } from '@fundamental-engine/core';
|
|
20
|
+
import { Group } from 'three';
|
|
21
|
+
import type { Object3D, WebGLRenderer } from 'three';
|
|
22
|
+
import { type FieldProjection } from './project.ts';
|
|
23
|
+
import { ParticlePool, type ParticleStyle } from './particles.ts';
|
|
24
|
+
import { FieldBodyRegistry, type FieldBody, type FieldBodySpec } from './bodies.ts';
|
|
25
|
+
export interface FieldLayerOptions extends Omit<FieldOptions, 'host' | 'render'> {
|
|
26
|
+
/** the 2D↔3D mapping; defaults to a centered `PlaneProjection`. */
|
|
27
|
+
projection?: FieldProjection;
|
|
28
|
+
/** a renderer to read the device-pixel ratio from (used when `dpr` is not given). */
|
|
29
|
+
renderer?: WebGLRenderer;
|
|
30
|
+
/** explicit device-pixel ratio override. */
|
|
31
|
+
dpr?: number;
|
|
32
|
+
/** `[data-body]` scan root; omit for a field with no DOM bodies. */
|
|
33
|
+
root?: ParentNode;
|
|
34
|
+
/** a canvas to satisfy the engine signature; one is created for you when omitted. */
|
|
35
|
+
canvas?: HTMLCanvasElement;
|
|
36
|
+
/** max particles the GPU buffers hold; defaults to ~1.25× the seeded pool. */
|
|
37
|
+
capacity?: number;
|
|
38
|
+
/** swarm appearance. */
|
|
39
|
+
style?: ParticleStyle;
|
|
40
|
+
}
|
|
41
|
+
export declare class FieldLayer implements FieldHandle {
|
|
42
|
+
/** add this to your scene; it holds the swarm `Points` (and future overlay objects). */
|
|
43
|
+
readonly object: Group;
|
|
44
|
+
/** the swarm pool — `pool.points`, `pool.size`, `pool.dispose()`. */
|
|
45
|
+
readonly pool: ParticlePool;
|
|
46
|
+
/** the active 2D↔3D mapping. */
|
|
47
|
+
readonly projection: FieldProjection;
|
|
48
|
+
/** the mesh-bodies registered on this field — `layer.addBody(...)` is the ergonomic entry. */
|
|
49
|
+
readonly bodies: FieldBodyRegistry;
|
|
50
|
+
private readonly field;
|
|
51
|
+
constructor(opts?: FieldLayerOptions);
|
|
52
|
+
/**
|
|
53
|
+
* Register a scene object as a field body — it bends the field, the swarm responds, and feedback
|
|
54
|
+
* (density/load/lit) flows back to it. The body carries `spec.data`, so a mesh can be a meaningful
|
|
55
|
+
* agent (a bloom with its genome, a hive accruing honey), not just a force. Returns a handle whose
|
|
56
|
+
* `.data`, `.channels`, and `.remove()` you use; the body tracks the mesh as it moves.
|
|
57
|
+
*/
|
|
58
|
+
addBody(object: Object3D, spec: FieldBodySpec): FieldBody;
|
|
59
|
+
/** sync the swarm geometry from the engine's current particle state; returns the live count. */
|
|
60
|
+
tick(): number;
|
|
61
|
+
scan(): void;
|
|
62
|
+
rescan(): void;
|
|
63
|
+
setAccent(hex: string): void;
|
|
64
|
+
setPalette(palette: string | readonly string[]): void;
|
|
65
|
+
setFormation(name: string): void;
|
|
66
|
+
setAttention(on: boolean): void;
|
|
67
|
+
setCausality(on: boolean): void;
|
|
68
|
+
setHeatmap(on: boolean): void;
|
|
69
|
+
setRender(mode: Parameters<FieldHandle['setRender']>[0]): void;
|
|
70
|
+
setOverlay(mode: Parameters<FieldHandle['setOverlay']>[0]): void;
|
|
71
|
+
setVisible(on: boolean): void;
|
|
72
|
+
threads(list: ThreadLink[] | null): void;
|
|
73
|
+
burst(x: number, y: number, hex?: string): void;
|
|
74
|
+
flowTo(x: number, y: number, flowOpts?: FlowOptions): void;
|
|
75
|
+
clearFlow(): void;
|
|
76
|
+
seed(atoms: readonly AtomPayload[]): void;
|
|
77
|
+
atomAt(x: number, y: number): AtomPayload | null;
|
|
78
|
+
focusAt(x: number, y: number): AtomPayload | null;
|
|
79
|
+
clearFocus(): void;
|
|
80
|
+
particleCount(): number;
|
|
81
|
+
readParticles(out: Float32Array): number;
|
|
82
|
+
energy(): {
|
|
83
|
+
kinetic: number;
|
|
84
|
+
thermal: number;
|
|
85
|
+
total: number;
|
|
86
|
+
count: number;
|
|
87
|
+
};
|
|
88
|
+
sample(x: number, y: number): {
|
|
89
|
+
x: number;
|
|
90
|
+
y: number;
|
|
91
|
+
};
|
|
92
|
+
scrollV(): number;
|
|
93
|
+
setBackground(mode: Parameters<FieldHandle['setBackground']>[0]): void;
|
|
94
|
+
/** stop the engine, release host listeners, and free the swarm's GPU resources. */
|
|
95
|
+
destroy(): void;
|
|
96
|
+
}
|
|
97
|
+
/** Construct a `FieldLayer`. The ergonomic entry point — mirrors `mountField()` for Three.js. */
|
|
98
|
+
export declare function createFieldLayer(opts?: FieldLayerOptions): FieldLayer;
|
|
99
|
+
export interface ThreeFieldOptions extends Omit<FieldOptions, 'host'> {
|
|
100
|
+
/** field-space viewport (CSS pixels) + dpr — wire to your `FieldProjection`. */
|
|
101
|
+
viewport: () => HostViewport;
|
|
102
|
+
/** `[data-body]` scan root; omit for a field with no DOM bodies. */
|
|
103
|
+
root?: ParentNode;
|
|
104
|
+
/** a canvas to satisfy the engine signature; one is created for you when omitted. */
|
|
105
|
+
canvas?: HTMLCanvasElement;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Lower-level builder: `createField` wired to a `threeHost`, returning the raw `FieldHandle` (no
|
|
109
|
+
* pool, no scene object). Use this when you want the engine on a WebGL scene but will draw it
|
|
110
|
+
* yourself — e.g. injecting `overlayBackend: threeBackend(...)` to render the diagnostic overlays,
|
|
111
|
+
* or sampling `forceAt` / `netField` for your own field visuals. `createFieldLayer` is the
|
|
112
|
+
* batteries-included path; this is the seam under it. (Parallels `createBrowserField`.)
|
|
113
|
+
*/
|
|
114
|
+
export declare function createThreeField(opts: ThreeFieldOptions): FieldHandle;
|
|
115
|
+
//# sourceMappingURL=layer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layer.d.ts","sourceRoot":"","sources":["../src/layer.ts"],"names":[],"mappings":"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"}
|
package/dist/layer.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `FieldLayer` — the field as a Three.js object. It runs the engine headless (`render: 'none'`) on a
|
|
3
|
+
* `threeHost`, owns a `ParticlePool`, and on every `tick()` syncs the live swarm onto a
|
|
4
|
+
* `THREE.Points` you add to your scene via `layer.object`. It implements the full `FieldHandle`
|
|
5
|
+
* surface (delegating to the wrapped engine), so `burst` / `flowTo` / `setFormation` / `seed` drive
|
|
6
|
+
* the 3D layer exactly as they drive the DOM field.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const layer = createFieldLayer({ projection: new PlaneProjection({ relief: 2 }), accent: '#4da3ff' });
|
|
10
|
+
* scene.add(layer.object);
|
|
11
|
+
* // render loop:
|
|
12
|
+
* layer.tick(); // engine self-steps via rAF; tick() pulls the latest swarm
|
|
13
|
+
* renderer.render(scene, camera);
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* The engine self-advances on the host's animation frame; `tick()` only reads the current state into
|
|
17
|
+
* the geometry, so it is safe to call from any render loop at any cadence.
|
|
18
|
+
*/
|
|
19
|
+
import { createField } from '@fundamental-engine/core';
|
|
20
|
+
import { Group } from 'three';
|
|
21
|
+
import { threeHost } from "./host.js";
|
|
22
|
+
import { PlaneProjection, VolumeProjection } from "./project.js";
|
|
23
|
+
import { ParticlePool } from "./particles.js";
|
|
24
|
+
import { FieldBodyRegistry } from "./bodies.js";
|
|
25
|
+
/** Three.js is browser-only; this stub satisfies the `createField` signature (never touched under
|
|
26
|
+
* `render: 'none'`, which acquires no 2D context). */
|
|
27
|
+
function stubCanvas() {
|
|
28
|
+
return typeof document !== 'undefined' ? document.createElement('canvas') : {};
|
|
29
|
+
}
|
|
30
|
+
export class FieldLayer {
|
|
31
|
+
/** add this to your scene; it holds the swarm `Points` (and future overlay objects). */
|
|
32
|
+
object;
|
|
33
|
+
/** the swarm pool — `pool.points`, `pool.size`, `pool.dispose()`. */
|
|
34
|
+
pool;
|
|
35
|
+
/** the active 2D↔3D mapping. */
|
|
36
|
+
projection;
|
|
37
|
+
/** the mesh-bodies registered on this field — `layer.addBody(...)` is the ergonomic entry. */
|
|
38
|
+
bodies;
|
|
39
|
+
field;
|
|
40
|
+
constructor(opts = {}) {
|
|
41
|
+
// default the mapping to the field's shape: a real volume when `depth > 0`, else a flat plane.
|
|
42
|
+
this.projection =
|
|
43
|
+
opts.projection ?? (opts.depth && opts.depth > 0 ? new VolumeProjection({ depth: opts.depth }) : new PlaneProjection());
|
|
44
|
+
this.bodies = new FieldBodyRegistry(this.projection);
|
|
45
|
+
const resolveDpr = () => opts.dpr ?? opts.renderer?.getPixelRatio() ?? (typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1);
|
|
46
|
+
const viewport = () => ({ ...this.projection.size(), dpr: resolveDpr() });
|
|
47
|
+
// the host scans the body registry; mesh-bodies are added via layer.addBody(...)
|
|
48
|
+
const host = threeHost({ viewport, root: this.bodies.root });
|
|
49
|
+
const { projection, renderer, dpr, root, canvas, capacity, style, ...fieldOpts } = opts;
|
|
50
|
+
void projection;
|
|
51
|
+
void renderer;
|
|
52
|
+
void dpr;
|
|
53
|
+
void root;
|
|
54
|
+
// route body feedback (density/load/lit) to the meshes instead of CSS custom properties
|
|
55
|
+
this.field = createField(canvas ?? stubCanvas(), { ...fieldOpts, host, render: 'none', feedbackSink: this.bodies.sink });
|
|
56
|
+
this.bodies.setOnChange(() => this.field.scan());
|
|
57
|
+
const cap = Math.max(capacity ?? 0, Math.ceil(this.field.particleCount() * 1.25) + 64);
|
|
58
|
+
this.pool = new ParticlePool({ capacity: cap, projection: this.projection, style });
|
|
59
|
+
this.object = new Group();
|
|
60
|
+
this.object.add(this.pool.points);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Register a scene object as a field body — it bends the field, the swarm responds, and feedback
|
|
64
|
+
* (density/load/lit) flows back to it. The body carries `spec.data`, so a mesh can be a meaningful
|
|
65
|
+
* agent (a bloom with its genome, a hive accruing honey), not just a force. Returns a handle whose
|
|
66
|
+
* `.data`, `.channels`, and `.remove()` you use; the body tracks the mesh as it moves.
|
|
67
|
+
*/
|
|
68
|
+
addBody(object, spec) {
|
|
69
|
+
return this.bodies.add(object, spec);
|
|
70
|
+
}
|
|
71
|
+
/** sync the swarm geometry from the engine's current particle state; returns the live count. */
|
|
72
|
+
tick() {
|
|
73
|
+
return this.pool.sync((out) => this.field.readParticles(out));
|
|
74
|
+
}
|
|
75
|
+
// ── FieldHandle surface (delegated to the wrapped engine) ───────────────────────────────────
|
|
76
|
+
scan() {
|
|
77
|
+
this.field.scan();
|
|
78
|
+
}
|
|
79
|
+
rescan() {
|
|
80
|
+
this.field.rescan();
|
|
81
|
+
}
|
|
82
|
+
setAccent(hex) {
|
|
83
|
+
this.field.setAccent(hex);
|
|
84
|
+
}
|
|
85
|
+
setPalette(palette) {
|
|
86
|
+
this.field.setPalette(palette);
|
|
87
|
+
}
|
|
88
|
+
setFormation(name) {
|
|
89
|
+
this.field.setFormation(name);
|
|
90
|
+
}
|
|
91
|
+
setAttention(on) {
|
|
92
|
+
this.field.setAttention(on);
|
|
93
|
+
}
|
|
94
|
+
setCausality(on) {
|
|
95
|
+
this.field.setCausality(on);
|
|
96
|
+
}
|
|
97
|
+
setHeatmap(on) {
|
|
98
|
+
this.field.setHeatmap(on);
|
|
99
|
+
}
|
|
100
|
+
setRender(mode) {
|
|
101
|
+
this.field.setRender(mode);
|
|
102
|
+
}
|
|
103
|
+
setOverlay(mode) {
|
|
104
|
+
this.field.setOverlay(mode);
|
|
105
|
+
}
|
|
106
|
+
setVisible(on) {
|
|
107
|
+
this.field.setVisible(on);
|
|
108
|
+
}
|
|
109
|
+
threads(list) {
|
|
110
|
+
this.field.threads(list);
|
|
111
|
+
}
|
|
112
|
+
burst(x, y, hex) {
|
|
113
|
+
this.field.burst(x, y, hex);
|
|
114
|
+
}
|
|
115
|
+
flowTo(x, y, flowOpts) {
|
|
116
|
+
this.field.flowTo(x, y, flowOpts);
|
|
117
|
+
}
|
|
118
|
+
clearFlow() {
|
|
119
|
+
this.field.clearFlow();
|
|
120
|
+
}
|
|
121
|
+
seed(atoms) {
|
|
122
|
+
this.field.seed(atoms);
|
|
123
|
+
}
|
|
124
|
+
atomAt(x, y) {
|
|
125
|
+
return this.field.atomAt(x, y);
|
|
126
|
+
}
|
|
127
|
+
focusAt(x, y) {
|
|
128
|
+
return this.field.focusAt(x, y);
|
|
129
|
+
}
|
|
130
|
+
clearFocus() {
|
|
131
|
+
this.field.clearFocus();
|
|
132
|
+
}
|
|
133
|
+
particleCount() {
|
|
134
|
+
return this.field.particleCount();
|
|
135
|
+
}
|
|
136
|
+
readParticles(out) {
|
|
137
|
+
return this.field.readParticles(out);
|
|
138
|
+
}
|
|
139
|
+
energy() {
|
|
140
|
+
return this.field.energy();
|
|
141
|
+
}
|
|
142
|
+
sample(x, y) {
|
|
143
|
+
return this.field.sample(x, y);
|
|
144
|
+
}
|
|
145
|
+
scrollV() {
|
|
146
|
+
return this.field.scrollV();
|
|
147
|
+
}
|
|
148
|
+
setBackground(mode) {
|
|
149
|
+
this.field.setBackground(mode);
|
|
150
|
+
}
|
|
151
|
+
/** stop the engine, release host listeners, and free the swarm's GPU resources. */
|
|
152
|
+
destroy() {
|
|
153
|
+
this.field.destroy();
|
|
154
|
+
this.pool.dispose();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/** Construct a `FieldLayer`. The ergonomic entry point — mirrors `mountField()` for Three.js. */
|
|
158
|
+
export function createFieldLayer(opts = {}) {
|
|
159
|
+
return new FieldLayer(opts);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Lower-level builder: `createField` wired to a `threeHost`, returning the raw `FieldHandle` (no
|
|
163
|
+
* pool, no scene object). Use this when you want the engine on a WebGL scene but will draw it
|
|
164
|
+
* yourself — e.g. injecting `overlayBackend: threeBackend(...)` to render the diagnostic overlays,
|
|
165
|
+
* or sampling `forceAt` / `netField` for your own field visuals. `createFieldLayer` is the
|
|
166
|
+
* batteries-included path; this is the seam under it. (Parallels `createBrowserField`.)
|
|
167
|
+
*/
|
|
168
|
+
export function createThreeField(opts) {
|
|
169
|
+
const { viewport, root, canvas, ...fieldOpts } = opts;
|
|
170
|
+
const host = threeHost({ viewport, root });
|
|
171
|
+
return createField(canvas ?? stubCanvas(), { ...fieldOpts, host });
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=layer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layer.js","sourceRoot":"","sources":["../src/layer.ts"],"names":[],"mappings":"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"}
|