babylon.quarks-editor 0.26.0 → 0.28.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/CHANGELOG.md +134 -0
- package/README.md +69 -9
- package/dist/core/assetDragSession.d.ts +1 -1
- package/dist/core/assetTree.d.ts +6 -1
- package/dist/core/assets.d.ts +7 -0
- package/dist/core/assets.js +11 -7
- package/dist/core/binding.d.ts +11 -2
- package/dist/core/binding.js +9 -1
- package/dist/core/collision.d.ts +4 -0
- package/dist/core/collision.js +4 -0
- package/dist/core/colors.d.ts +16 -0
- package/dist/core/colors.js +8 -0
- package/dist/core/defaultEffect.d.ts +5 -4
- package/dist/core/defaultEffect.js +4 -4
- package/dist/core/editorScene.d.ts +1 -1
- package/dist/core/editorSession.d.ts +229 -0
- package/dist/core/editorSession.js +983 -0
- package/dist/core/effectTree.d.ts +6 -1
- package/dist/core/effectTree.js +13 -88
- package/dist/core/emitterShapeWireframe.d.ts +2 -2
- package/dist/core/emitterShapeWireframe.js +45 -13
- package/dist/core/galleryDropMarker.d.ts +2 -2
- package/dist/core/galleryDropMarker.js +6 -6
- package/dist/core/galleryLayout.d.ts +3 -3
- package/dist/core/galleryLayout.js +1 -1
- package/dist/core/galleryPlayback.d.ts +1 -1
- package/dist/core/galleryPlayback.js +2 -1
- package/dist/core/galleryScene.d.ts +4 -4
- package/dist/core/galleryScene.js +3 -3
- package/dist/core/gallerySelectionMarker.d.ts +4 -4
- package/dist/core/gallerySelectionMarker.js +5 -5
- package/dist/core/groups.d.ts +1 -1
- package/dist/core/groups.js +1 -1
- package/dist/core/history.d.ts +7 -1
- package/dist/core/history.js +4 -0
- package/dist/core/indexedDbProjectStore.d.ts +14 -1
- package/dist/core/indexedDbProjectStore.js +13 -0
- package/dist/core/lineShaders.d.ts +2 -2
- package/dist/core/lineShaders.js +2 -2
- package/dist/core/loadEffect.d.ts +2 -2
- package/dist/core/loadEffect.js +1 -1
- package/dist/core/material.d.ts +12 -2
- package/dist/core/pickAssetFiles.js +1 -1
- package/dist/core/playback.d.ts +6 -0
- package/dist/core/projectStore.d.ts +26 -0
- package/dist/core/projectStore.js +1 -0
- package/dist/core/sceneEntries.d.ts +7 -4
- package/dist/core/sceneEntries.js +2 -2
- package/dist/core/scrub.d.ts +2 -2
- package/dist/core/scrub.js +2 -2
- package/dist/core/shapes.d.ts +25 -1
- package/dist/core/shapes.js +5 -0
- package/dist/core/systems.d.ts +4 -2
- package/dist/core/systems.js +3 -1
- package/dist/core/textureExport.d.ts +1 -1
- package/dist/core/timeline.d.ts +25 -5
- package/dist/core/transport.d.ts +3 -3
- package/dist/core/transport.js +2 -2
- package/dist/core/values.d.ts +21 -4
- package/dist/core/values.js +5 -0
- package/dist/core/viewportPicker.d.ts +4 -4
- package/dist/core/viewportPicker.js +8 -7
- package/dist/index.d.ts +25 -21
- package/dist/index.js +12 -12
- package/dist/react/AssetsPanel.d.ts +9 -2
- package/dist/react/AssetsPanel.js +6 -6
- package/dist/react/ChoiceDialog.d.ts +7 -0
- package/dist/react/ChoiceDialog.js +1 -1
- package/dist/react/ContextMenu.d.ts +10 -1
- package/dist/react/ContextMenu.js +1 -1
- package/dist/react/CurveEditor.d.ts +1 -1
- package/dist/react/CurveEditor.js +2 -2
- package/dist/react/EditorWorkspace.d.ts +9 -2
- package/dist/react/EditorWorkspace.js +10 -7
- package/dist/react/EffectEditor.d.ts +11 -5
- package/dist/react/EffectEditor.js +7 -7
- package/dist/react/EffectEditorHost.d.ts +33 -29
- package/dist/react/EffectEditorHost.js +247 -1674
- package/dist/react/EffectTreeView.d.ts +4 -1
- package/dist/react/EffectTreeView.js +3 -3
- package/dist/react/GradientEditor.d.ts +1 -1
- package/dist/react/GradientEditor.js +3 -3
- package/dist/react/InspectorInfoIcon.js +3 -3
- package/dist/react/InspectorLabel.js +3 -3
- package/dist/react/MessageDialog.d.ts +5 -0
- package/dist/react/MessageDialog.js +1 -1
- package/dist/react/ModuleSection.d.ts +10 -0
- package/dist/react/ModuleSection.js +8 -5
- package/dist/react/ObjectModule.d.ts +1 -1
- package/dist/react/ObjectModule.js +4 -4
- package/dist/react/ProjectsPage.d.ts +7 -1
- package/dist/react/ProjectsPage.js +33 -17
- package/dist/react/PromptDialog.d.ts +7 -0
- package/dist/react/PromptDialog.js +1 -1
- package/dist/react/ScenePanel.d.ts +9 -2
- package/dist/react/ScenePanel.js +12 -10
- package/dist/react/SubEmittersModule.d.ts +1 -1
- package/dist/react/SubEmittersModule.js +5 -5
- package/dist/react/TextureSelect.d.ts +24 -0
- package/dist/react/TextureSelect.js +74 -0
- package/dist/react/TextureUVField.d.ts +14 -0
- package/dist/react/TextureUVField.js +23 -0
- package/dist/react/TimelinePanel.d.ts +20 -7
- package/dist/react/TimelinePanel.js +21 -15
- package/dist/react/TimelineTrackRow.d.ts +13 -3
- package/dist/react/TimelineTrackRow.js +6 -6
- package/dist/react/TransportBar.d.ts +13 -4
- package/dist/react/TransportBar.js +3 -3
- package/dist/react/ValueField.d.ts +32 -5
- package/dist/react/ValueField.js +22 -11
- package/dist/react/behaviorModules.d.ts +19 -6
- package/dist/react/behaviorModules.js +68 -17
- package/dist/react/fields.d.ts +9 -0
- package/dist/react/fields.js +6 -3
- package/dist/react/host/BottomDocks.d.ts +36 -0
- package/dist/react/host/BottomDocks.js +63 -0
- package/dist/react/host/HostDialogs.d.ts +50 -0
- package/dist/react/host/HostDialogs.js +113 -0
- package/dist/react/host/InspectorSidebar.d.ts +32 -0
- package/dist/react/host/InspectorSidebar.js +59 -0
- package/dist/react/host/SceneSidebar.d.ts +53 -0
- package/dist/react/host/SceneSidebar.js +62 -0
- package/dist/react/host/ViewportPane.d.ts +56 -0
- package/dist/react/host/ViewportPane.js +91 -0
- package/dist/react/host/hostHooks.d.ts +44 -0
- package/dist/react/host/hostHooks.js +164 -0
- package/dist/react/host/hostStyles.d.ts +21 -0
- package/dist/react/host/hostStyles.js +57 -0
- package/dist/react/index.d.ts +42 -38
- package/dist/react/index.js +25 -23
- package/dist/react/inspectorHints.js +31 -0
- package/dist/react/modules.d.ts +19 -6
- package/dist/react/modules.js +134 -117
- package/dist/react/theme.d.ts +15 -0
- package/dist/react/theme.js +15 -0
- package/dist/session.d.ts +9 -0
- package/dist/session.js +8 -0
- package/package.json +18 -11
- package/src/core/assetDragSession.ts +1 -1
- package/src/core/assetTree.ts +15 -2
- package/src/core/assets.ts +25 -10
- package/src/core/binding.ts +12 -3
- package/src/core/collision.ts +4 -0
- package/src/core/colors.ts +21 -1
- package/src/core/defaultEffect.ts +8 -7
- package/src/core/editorScene.ts +1 -1
- package/src/core/editorSession.ts +1299 -0
- package/src/core/effectTree.ts +18 -101
- package/src/core/emitterShapeWireframe.ts +48 -16
- package/src/core/galleryDropMarker.ts +8 -8
- package/src/core/galleryLayout.ts +4 -4
- package/src/core/galleryPlayback.ts +3 -2
- package/src/core/galleryScene.ts +5 -5
- package/src/core/gallerySelectionMarker.ts +7 -7
- package/src/core/groups.ts +1 -1
- package/src/core/history.ts +7 -1
- package/src/core/indexedDbProjectStore.ts +14 -1
- package/src/core/lineShaders.ts +2 -2
- package/src/core/loadEffect.ts +4 -4
- package/src/core/material.ts +14 -4
- package/src/core/pickAssetFiles.ts +2 -2
- package/src/core/playback.ts +6 -0
- package/src/core/projectStore.ts +26 -0
- package/src/core/sceneEntries.ts +8 -5
- package/src/core/scrub.ts +3 -3
- package/src/core/shapes.ts +29 -2
- package/src/core/systems.ts +11 -4
- package/src/core/textureExport.ts +1 -1
- package/src/core/timeline.ts +43 -18
- package/src/core/transport.ts +4 -4
- package/src/core/values.ts +20 -4
- package/src/core/viewportPicker.ts +12 -11
- package/src/index.ts +25 -21
- package/src/react/AssetsPanel.tsx +13 -6
- package/src/react/ChoiceDialog.tsx +8 -1
- package/src/react/ContextMenu.tsx +11 -2
- package/src/react/CurveEditor.tsx +2 -2
- package/src/react/EditorWorkspace.tsx +16 -10
- package/src/react/EffectEditor.tsx +17 -9
- package/src/react/EffectEditorHost.tsx +415 -2354
- package/src/react/EffectTreeView.tsx +7 -4
- package/src/react/GradientEditor.tsx +3 -3
- package/src/react/InspectorInfoIcon.tsx +3 -3
- package/src/react/InspectorLabel.tsx +3 -3
- package/src/react/MessageDialog.tsx +6 -1
- package/src/react/ModuleSection.tsx +15 -4
- package/src/react/ObjectModule.tsx +5 -5
- package/src/react/ProjectsPage.tsx +44 -17
- package/src/react/PromptDialog.tsx +8 -1
- package/src/react/ScenePanel.tsx +21 -12
- package/src/react/SubEmittersModule.tsx +6 -6
- package/src/react/TextureSelect.tsx +118 -0
- package/src/react/TextureUVField.tsx +62 -0
- package/src/react/TimelinePanel.tsx +40 -21
- package/src/react/TimelineTrackRow.tsx +19 -9
- package/src/react/TransportBar.tsx +16 -7
- package/src/react/ValueField.tsx +60 -16
- package/src/react/behaviorModules.tsx +240 -55
- package/src/react/fields.tsx +22 -4
- package/src/react/host/BottomDocks.tsx +178 -0
- package/src/react/host/HostDialogs.tsx +228 -0
- package/src/react/host/InspectorSidebar.tsx +147 -0
- package/src/react/host/SceneSidebar.tsx +227 -0
- package/src/react/host/ViewportPane.tsx +300 -0
- package/src/react/host/hostHooks.ts +198 -0
- package/src/react/host/hostStyles.ts +65 -0
- package/src/react/index.ts +43 -38
- package/src/react/inspectorHints.ts +40 -0
- package/src/react/modules.tsx +440 -170
- package/src/react/theme.ts +15 -0
- package/src/session.ts +17 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,140 @@ All notable changes to the `babylon.quarks-editor` package are documented here.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
5
|
and the project follows the `quarks.core` 0.x version line.
|
|
6
6
|
|
|
7
|
+
## [0.28.0] — 2026-10-23
|
|
8
|
+
|
|
9
|
+
### Breaking
|
|
10
|
+
|
|
11
|
+
- **Texture callbacks are typed.** `resolveTexture` returns `Texture | null | undefined` instead
|
|
12
|
+
of `unknown` (on `EffectEditorHost`, `QuarksEffectEditor.Show`, `EffectEditor`,
|
|
13
|
+
`RendererModule` and `createDefaultEffect`). `TextureSelect`'s `loadTexture` and `onChange` use
|
|
14
|
+
`Texture`, and `RendererMaterialPatch` types `texture` as `Texture | null` and
|
|
15
|
+
`reflectionAtlas` as `BaseTexture | null`. A resolver that returns a Babylon `Texture` needs no
|
|
16
|
+
change; one typed to return something else must now return a `Texture`.
|
|
17
|
+
- **`ValueField` has two prop shapes.** `CurveValueFieldProps` (the default, `curve` unset or
|
|
18
|
+
`true`) calls `onChange` with a `ScalarGenerator`; `ConstantValueFieldProps` (`curve: false`)
|
|
19
|
+
calls it with a `ValueGenerator`. Code that passed `curve={false}` and expected a curve back no
|
|
20
|
+
longer type-checks.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- A **Render face** field (Both, Front, Back) for mesh systems, editing the library's new
|
|
25
|
+
`renderFace`.
|
|
26
|
+
- **`createEditorSession`** and the `EditorSession` interface, in a new
|
|
27
|
+
`babylon.quarks-editor/session` entry: the scene, camera, gizmos, history, scene entries, assets,
|
|
28
|
+
prefab mode and project save/load without React. The host passes only the view callbacks it
|
|
29
|
+
needs; none runs after `dispose()`, which also drops a project load or an import still in
|
|
30
|
+
flight. `EffectEditorHost` is now a view over a session. The session has its own entry because
|
|
31
|
+
it builds the viewport (grid, gizmos, markers), which the UI-free `.` entry does not load.
|
|
32
|
+
- **`createEngine`** on `EffectEditorHostProps` (and `Show()`), to draw with a WebGPU or other
|
|
33
|
+
engine instead of the default WebGL `Engine`. It may return a promise, so a `WebGPUEngine` can
|
|
34
|
+
finish `initAsync()` first.
|
|
35
|
+
- Exported types that public signatures already used: `AssetLoadProgress`, `EffectAsset`,
|
|
36
|
+
`AssetDragPayload`, `SceneEntry`, `TimelineRow` (`TimelineGroupRow | TimelineSystemRow`),
|
|
37
|
+
`AnyGenerator`, `ModuleProps`, `ConstantValueFieldProps` and `CurveValueFieldProps`, and
|
|
38
|
+
`EditorProject` from `./react`.
|
|
39
|
+
- TSDoc on every public export. `npm run docs:check` now builds the editor's API docs and fails on
|
|
40
|
+
an undocumented export or a broken link.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- A mesh from geometry without indices (a preset or a loaded GLB) no longer leaves the system
|
|
45
|
+
with no index buffer: it gets sequential indices, so it draws and exports. A mesh without UVs or
|
|
46
|
+
normals gets the library's fallback ones instead of keeping the previous mesh's.
|
|
47
|
+
- Randomize Direction's angle no longer offers a curve. The angle is sampled once per particle,
|
|
48
|
+
so a curve could not apply, and a curve loaded from JSON shows as its starting value.
|
|
49
|
+
- `EffectEditorHost` under React StrictMode, or remounted, no longer lets the first mount's project
|
|
50
|
+
load fill the live editor with entries from a disposed scene.
|
|
51
|
+
- The transport's play resumes what pause froze and no longer replays effects or bursts that had
|
|
52
|
+
already finished (it uses the library's new `resume()`, now that `play()` replays a finished
|
|
53
|
+
system).
|
|
54
|
+
- A node deleted by an undo while selected hands the selection back to its effect's root on the
|
|
55
|
+
next render. The host only checked when the selection or the session changed, so the inspector
|
|
56
|
+
and timeline could keep showing the deleted node.
|
|
57
|
+
|
|
58
|
+
### Internal
|
|
59
|
+
|
|
60
|
+
- The asset import checks every field it reads from an effect file, with no `any`.
|
|
61
|
+
- The React panels follow the React Compiler's rules (eslint-plugin-react-hooks 7): no ref
|
|
62
|
+
written during render, and state that follows a prop is adjusted during render instead of in an
|
|
63
|
+
effect, which saves a render each time.
|
|
64
|
+
- `EffectEditorHost` is split into a session and panel components under `src/react/host/`, and
|
|
65
|
+
every `as never` cast is gone. The session and the host have their own tests, and the React
|
|
66
|
+
code has a coverage floor.
|
|
67
|
+
|
|
68
|
+
## [0.27.1] — 2026-10-23 (not published)
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- **Peer ranges:** `@babylonjs/core` and `@babylonjs/materials` are `^9.0.0` instead of
|
|
73
|
+
`>=9.0.0` (no Babylon 10 exists yet, so no install that worked stops working). `babylon.quarks` stays `~0.27.0`: the editor follows the library's minor line, and
|
|
74
|
+
the release check now enforces it.
|
|
75
|
+
- The `exports` map lists `types` first and exports `./package.json`. The README says the package
|
|
76
|
+
is ES modules only.
|
|
77
|
+
|
|
78
|
+
## [0.27.0] — 2026-10-23
|
|
79
|
+
|
|
80
|
+
A 0.27.0 dated 2026-10-21 was prepared but never published; its entries are folded in here.
|
|
81
|
+
|
|
82
|
+
### Added
|
|
83
|
+
|
|
84
|
+
- Main module: "Warm-up time", shown while Prewarm is on, the seconds of the cycle simulated
|
|
85
|
+
before the first frame (`prewarmTime`; 0 warms up a whole cycle).
|
|
86
|
+
- **The Renderer module reaches the 0.25–0.26 texture features.** Map layout (UV channel,
|
|
87
|
+
tiling, offset, scroll), Flip, a Gradient map section (ramp and channel), an Erosion section
|
|
88
|
+
(mask with its own layout, softness, edge width and colour) and a UV distortion section (noise
|
|
89
|
+
with its layout, strength). The ramp, mask and noise are picked the way the texture is: from
|
|
90
|
+
the host's presets, a URL or a file.
|
|
91
|
+
- Renderer: a swept trail's side axis. A host geometry
|
|
92
|
+
(`GeometryOption`, `resolveGeometry`) may carry a second UV set, `uvs2`, which mesh particles
|
|
93
|
+
read on UV channel 1; the demo's glTF loader passes `TEXCOORD_1` through.
|
|
94
|
+
- Main: Scaling mode for world-space systems (shape only, or the hierarchy's motion too).
|
|
95
|
+
- Texture Sheet Animation: time mode (lifetime or FPS), FPS, loop or hold, random frame, cycles,
|
|
96
|
+
frame count and a random start frame.
|
|
97
|
+
- Attractor module: a point gravity (`GravityForce`) with its centre and strength.
|
|
98
|
+
- Emitter shape wireframes for the Box and Edge shapes: the box outline with its +Z emit
|
|
99
|
+
direction, and the edge line with its +Y emit direction.
|
|
100
|
+
- `TextureSelect` and `TextureUVField` components, exported from `babylon.quarks-editor/react`.
|
|
101
|
+
- Renderer module, trails: "Tessellation" and "Curve tension".
|
|
102
|
+
|
|
103
|
+
### Changed
|
|
104
|
+
|
|
105
|
+
- Renderer, trails: "Texture mode" (stretch, distribute per segment, tile, repeat per segment),
|
|
106
|
+
"Texture scale", "Min vertex distance" and "Trail time", each left unset at its default so the
|
|
107
|
+
JSON stays sparse. The "Head width scale" row is gone: it wrote a `headWidthScale` field no
|
|
108
|
+
runtime read (the head's width comes from the Width over Trail module).
|
|
109
|
+
- **`TimelinePanelProps` and `TransportBarProps` take `RefObject<HTMLElement | null>` refs**, the
|
|
110
|
+
type `useRef<HTMLElement>(null)` returns, now that the editor compiles with `strict`. Code that
|
|
111
|
+
passed the old type still compiles.
|
|
112
|
+
|
|
113
|
+
### Fixed
|
|
114
|
+
|
|
115
|
+
- An imported effect whose images were inlined from the picked files is saved with those inlined
|
|
116
|
+
images; `serializeEffect` writes a texture's source path only while the texture still shows the
|
|
117
|
+
image it was loaded with, and an inlined image has no path. A test covers import → scene → save.
|
|
118
|
+
- **Saving lost mesh nodes and texture settings.** The editor now saves through `serializeEffect`:
|
|
119
|
+
mesh nodes keep their geometry (so mesh surface emitters still emit after a save and reload),
|
|
120
|
+
and textures keep their wrap, sampling, repeat, offset and rotation. Textures with no url a file
|
|
121
|
+
can point at are reported instead of written as an empty entry.
|
|
122
|
+
- The yellow hover ring stayed on the ground after the hovered effect was removed from the scene.
|
|
123
|
+
- **Node ESM and webpack 5 could not import the package.** `dist` was compiled with relative and
|
|
124
|
+
`@babylonjs` deep imports that had no file extension. Every import now ends in `.js`.
|
|
125
|
+
- The `babylon.quarks` peer range was `>=0.17.0`, but the editor needs current APIs (beam mode,
|
|
126
|
+
rim fade, culling and sort settings). It is now `~0.27.0`.
|
|
127
|
+
|
|
128
|
+
### Internal
|
|
129
|
+
|
|
130
|
+
- Jest tests now cover the whole editor core (`src/core`): systems, material, timeline, scrub,
|
|
131
|
+
playback and transport, groups, collision, effect tree, assets and asset tree, scene entries,
|
|
132
|
+
gallery layout, playback, markers and picker, emitter shape wireframes, texture export and the
|
|
133
|
+
IndexedDB project store. The coverage threshold for the editor is raised to match.
|
|
134
|
+
- Editor tests resolve `babylon.quarks` to its sources, so they pick up library changes made in
|
|
135
|
+
the same branch without rebuilding it.
|
|
136
|
+
- React modules are tested in jsdom through the DOM, and the whole `EffectEditor` is mounted in
|
|
137
|
+
every render mode.
|
|
138
|
+
- The README leads with `QuarksEffectEditor.Show`, lists every peer and every module, and the
|
|
139
|
+
`EffectEditor` snippet carries all of its props.
|
|
140
|
+
|
|
7
141
|
## [0.26.0] — 2026-10-21
|
|
8
142
|
|
|
9
143
|
### Added
|
package/README.md
CHANGED
|
@@ -7,11 +7,33 @@ Shuriken-style effect editor for [babylon.quarks](https://www.npmjs.com/package/
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npm install babylon.quarks-editor babylon.quarks @babylonjs/core react @heroicons/react @tanstack/react-virtual
|
|
10
|
+
npm install babylon.quarks-editor babylon.quarks @babylonjs/core @babylonjs/materials react react-dom @heroicons/react @tanstack/react-virtual
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
The editor is an ES module package (`import`, not `require`). Its version follows babylon.quarks:
|
|
14
|
+
editor 0.28.x needs babylon.quarks 0.28.x.
|
|
15
|
+
|
|
13
16
|
## Usage
|
|
14
17
|
|
|
18
|
+
The supported embed is the host: it owns the scene, the timeline, undo/redo, playback and the
|
|
19
|
+
module inspector, and mounts into any element.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import {Texture} from '@babylonjs/core/Materials/Textures/texture';
|
|
23
|
+
import {QuarksEffectEditor} from 'babylon.quarks-editor/react';
|
|
24
|
+
|
|
25
|
+
const editor = QuarksEffectEditor.Show({
|
|
26
|
+
hostElement: document.getElementById('editor')!,
|
|
27
|
+
effectJson, // optional: a Quarks JSON export to open; a default effect otherwise
|
|
28
|
+
textureOptions: [{label: 'Glow', url: '/textures/glow.png'}],
|
|
29
|
+
resolveTexture: (url, scene) => new Texture(url, scene),
|
|
30
|
+
onSave: (json) => save(json), // the effect as Quarks JSON, round-trips through QuarksLoader
|
|
31
|
+
});
|
|
32
|
+
editor.dispose();
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The module inspector on its own, for a host that already has a scene and a selection:
|
|
36
|
+
|
|
15
37
|
```tsx
|
|
16
38
|
import {EffectBinding, EffectHistory} from 'babylon.quarks-editor';
|
|
17
39
|
import {EffectEditor} from 'babylon.quarks-editor/react';
|
|
@@ -20,13 +42,25 @@ const binding = new EffectBinding(particleSystem); // your babylon.quarks Partic
|
|
|
20
42
|
const history = new EffectHistory();
|
|
21
43
|
history.attach(binding);
|
|
22
44
|
|
|
23
|
-
<EffectEditor
|
|
45
|
+
<EffectEditor
|
|
46
|
+
binding={binding}
|
|
47
|
+
selectedSystem={binding.system}
|
|
48
|
+
gizmoTargetNode={binding.system.emitter}
|
|
49
|
+
gizmoTargetLabel={binding.system.emitter.name}
|
|
50
|
+
/>;
|
|
24
51
|
|
|
25
52
|
// Serialize to Quarks JSON (round-trips through QuarksLoader):
|
|
26
53
|
const json = binding.exportJSON('MyEffect');
|
|
27
54
|
```
|
|
28
55
|
|
|
29
|
-
Modules: Main, Emission (
|
|
56
|
+
Modules, in Unity's order: Main, Emission (rate over time and distance, bursts), Shape (cone,
|
|
57
|
+
sphere, hemisphere, circle, donut, rectangle, grid, box, edge, mesh surface, point), Randomize
|
|
58
|
+
Direction, Velocity / Speed / Limit Speed / Force over Lifetime, Inherit Velocity, Gravity,
|
|
59
|
+
Attractor, Orbit over Lifetime, Color over Lifetime and by Speed, Size over Lifetime and by Speed,
|
|
60
|
+
Rotation over Lifetime (2D and 3D) and by Speed, Noise, Turbulence, Collision, Width over Trail,
|
|
61
|
+
Sub Emitters, Texture Sheet Animation, Sequences, Renderer (render modes incl. trail, mesh and
|
|
62
|
+
beam; material, texture layout, flip, gradient map, erosion, UV distortion, soft particles, sorting).
|
|
63
|
+
Multi-system hierarchy with add/remove/rename, undo/redo via `EffectHistory`.
|
|
30
64
|
|
|
31
65
|
The `.` export is UI-free (edit model, serialization, value/shape/gradient helpers) — usable headless. The `./react` export ships the components; React is a peer dependency, so the same UI can mount in a standalone page or inside a [BabylonJS Editor](https://github.com/BabylonJS/Editor) plugin.
|
|
32
66
|
|
|
@@ -35,22 +69,25 @@ The `.` export is UI-free (edit model, serialization, value/shape/gradient helpe
|
|
|
35
69
|
The editor never loads assets itself — it defers to host-supplied callbacks so it doesn't need
|
|
36
70
|
an opinion on your CDN, asset pipeline, or loader (`@babylonjs/loaders`, your own backend, etc.):
|
|
37
71
|
|
|
38
|
-
- `resolveTexture(url) => Texture
|
|
39
|
-
"Load from file…" in the Renderer module) into
|
|
72
|
+
- `resolveTexture(url) => Texture | null | undefined` — turns a picked URL or `data:` URI (from
|
|
73
|
+
"Custom URL…" / "Load from file…" in the Renderer module) into the Babylon `Texture` assigned as
|
|
74
|
+
`system.texture`. Return `null` or `undefined` to leave the texture unset.
|
|
40
75
|
- `resolveGeometry(file) => Promise<GeometryData>` — turns a picked file (from "Load from file…"
|
|
41
76
|
in the Mesh render mode's geometry dropdown) into vertex buffers: `{positions, indices?, uvs?,
|
|
42
|
-
normals?}` (typed arrays or plain number arrays
|
|
77
|
+
uvs2?, normals?}` (typed arrays or plain number arrays; `uvs2` is the second UV set textures on
|
|
78
|
+
UV channel 1 read).
|
|
43
79
|
- `textureOptions?: {label, url}[]` / `geometryOptions?: {label, positions, indices?, uvs?,
|
|
44
|
-
normals?}[]` — preset lists shown alongside "Custom URL…" / "Load from file…".
|
|
80
|
+
uvs2?, normals?}[]` — preset lists shown alongside "Custom URL…" / "Load from file…". The texture
|
|
81
|
+
presets also serve the gradient map's ramp, the erosion mask and the distortion noise.
|
|
45
82
|
|
|
46
83
|
**Signature differs by entry point** — a common source of "works in the demo, throws in my
|
|
47
84
|
host" bugs:
|
|
48
85
|
|
|
49
86
|
- `QuarksEffectEditor.Show(...)` / `<EffectEditorHost>` call your callbacks with the live
|
|
50
|
-
`Scene` as a second argument: `resolveTexture: (url, scene) =>
|
|
87
|
+
`Scene` as a second argument: `resolveTexture: (url, scene) => Texture | null | undefined`,
|
|
51
88
|
`resolveGeometry: (file, scene) => Promise<GeometryData>`.
|
|
52
89
|
- The lower-level `<EffectEditor>` (no Host wrapper) does **not** pass a scene:
|
|
53
|
-
`resolveTexture: (url) =>
|
|
90
|
+
`resolveTexture: (url) => Texture | null | undefined`, `resolveGeometry: (file) => Promise<GeometryData>`. If you
|
|
54
91
|
copy a `Show()`-style resolver that reads its `scene` parameter into a raw `<EffectEditor>`,
|
|
55
92
|
`scene` is `undefined` and your resolver throws.
|
|
56
93
|
|
|
@@ -79,6 +116,29 @@ resolveGeometry: async (file, scene) => {
|
|
|
79
116
|
},
|
|
80
117
|
```
|
|
81
118
|
|
|
119
|
+
## Custom engines and headless use
|
|
120
|
+
|
|
121
|
+
`<EffectEditorHost>` creates a WebGL `Engine` on its canvas. Pass `createEngine` to build another
|
|
122
|
+
engine on that canvas instead, or a `NullEngine` in tests. It may return a promise:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
createEngine: async (canvas) => {
|
|
126
|
+
const engine = new WebGPUEngine(canvas);
|
|
127
|
+
await engine.initAsync();
|
|
128
|
+
return engine;
|
|
129
|
+
},
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Build a new engine on every call: the host disposes it when it unmounts, and React StrictMode
|
|
133
|
+
mounts the host twice.
|
|
134
|
+
|
|
135
|
+
Everything the host does besides drawing its panels lives in an `EditorSession`, from the
|
|
136
|
+
`babylon.quarks-editor/session` entry: `createEditorSession({engine, playback, view, ...})`. The
|
|
137
|
+
session owns the scene, camera, gizmos, history, scene entries, assets, prefab mode and project
|
|
138
|
+
save/load, and reports changes through the `view` callbacks you pass. Use it to drive the editor
|
|
139
|
+
from your own UI, or to script and test editing without React. It builds the viewport (grid,
|
|
140
|
+
gizmos, markers), which is why it is not part of the lighter UI-free `.` entry.
|
|
141
|
+
|
|
82
142
|
## License
|
|
83
143
|
|
|
84
144
|
MIT
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssetDragPayload } from './assetTree';
|
|
1
|
+
import type { AssetDragPayload } from './assetTree.js';
|
|
2
2
|
/** Stores the current asset drag payload for viewport preview (getData is drop-only in most browsers). */
|
|
3
3
|
export declare function setAssetDragSession(payload: AssetDragPayload | null): void;
|
|
4
4
|
export declare function getAssetDragSession(): AssetDragPayload | null;
|
package/dist/core/assetTree.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EffectAsset } from './assets';
|
|
1
|
+
import type { EffectAsset } from './assets.js';
|
|
2
2
|
export interface AssetTreeFolder {
|
|
3
3
|
kind: 'folder';
|
|
4
4
|
name: string;
|
|
@@ -19,11 +19,16 @@ export declare function folderChildren(tree: AssetTreeNode[], path: string): Ass
|
|
|
19
19
|
/** Assets whose name or path contains `query`, across every folder, sorted by name. */
|
|
20
20
|
export declare function searchAssets(assets: EffectAsset[], query: string): EffectAsset[];
|
|
21
21
|
export declare const ASSET_DRAG_MIME = "application/x-quarks-asset-drop";
|
|
22
|
+
/** What is dragged out of the Assets panel: one asset, or every asset under a folder. */
|
|
22
23
|
export type AssetDragPayload = {
|
|
24
|
+
/** One asset. */
|
|
23
25
|
kind: 'asset';
|
|
26
|
+
/** The asset's id. */
|
|
24
27
|
id: number;
|
|
25
28
|
} | {
|
|
29
|
+
/** A folder. */
|
|
26
30
|
kind: 'folder';
|
|
31
|
+
/** The folder's path; every asset under it is dragged. */
|
|
27
32
|
path: string;
|
|
28
33
|
};
|
|
29
34
|
export declare function writeAssetDrag(dataTransfer: DataTransfer, payload: AssetDragPayload): void;
|
package/dist/core/assets.d.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* fresh, independent copy (see `instantiateSceneEntry`).
|
|
5
5
|
*/
|
|
6
6
|
export interface EffectAsset {
|
|
7
|
+
/** The asset's id in this session; scene entries made from it keep it. */
|
|
7
8
|
id: number;
|
|
9
|
+
/** The asset's display name, its file name without `.json`. */
|
|
8
10
|
name: string;
|
|
9
11
|
/** Relative path inside the imported folder (preserves subfolders). */
|
|
10
12
|
path: string;
|
|
@@ -13,10 +15,15 @@ export interface EffectAsset {
|
|
|
13
15
|
/** Texture/geometry files the effect references that were not among the imported files. */
|
|
14
16
|
missingFiles: string[];
|
|
15
17
|
}
|
|
18
|
+
/** How far an asset import got. */
|
|
16
19
|
export interface AssetLoadProgress {
|
|
20
|
+
/** JSON files read so far. */
|
|
17
21
|
done: number;
|
|
22
|
+
/** JSON files in the import. */
|
|
18
23
|
total: number;
|
|
24
|
+
/** Effects found so far. */
|
|
19
25
|
loaded: number;
|
|
26
|
+
/** Files that could not be read. */
|
|
20
27
|
failed: number;
|
|
21
28
|
}
|
|
22
29
|
export declare function relativePathOf(file: File): string;
|
package/dist/core/assets.js
CHANGED
|
@@ -42,6 +42,9 @@ function readAsDataUrl(file) {
|
|
|
42
42
|
reader.readAsDataURL(file);
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
+
function isRecord(value) {
|
|
46
|
+
return value !== null && typeof value === 'object';
|
|
47
|
+
}
|
|
45
48
|
/** True for a Quarks effect envelope with at least one particle emitter. */
|
|
46
49
|
export function isEffectJson(json) {
|
|
47
50
|
const object = json?.object;
|
|
@@ -206,11 +209,11 @@ export function assetIconUrl(asset) {
|
|
|
206
209
|
if (cached !== undefined) {
|
|
207
210
|
return cached;
|
|
208
211
|
}
|
|
209
|
-
const json = asset.json;
|
|
212
|
+
const json = isRecord(asset.json) ? asset.json : {};
|
|
210
213
|
const findMaterial = (node) => {
|
|
211
|
-
if (!node
|
|
214
|
+
if (!isRecord(node))
|
|
212
215
|
return undefined;
|
|
213
|
-
if (node.type === 'ParticleEmitter' && node.ps
|
|
216
|
+
if (node.type === 'ParticleEmitter' && isRecord(node.ps) && node.ps.material)
|
|
214
217
|
return node.ps.material;
|
|
215
218
|
for (const child of Array.isArray(node.children) ? node.children : []) {
|
|
216
219
|
const found = findMaterial(child);
|
|
@@ -219,10 +222,11 @@ export function assetIconUrl(asset) {
|
|
|
219
222
|
}
|
|
220
223
|
return undefined;
|
|
221
224
|
};
|
|
222
|
-
const byUuid = (list, uuid) => (Array.isArray(list) ? list : []).find((item) => item
|
|
223
|
-
const material = byUuid(json
|
|
224
|
-
const texture = byUuid(json
|
|
225
|
-
const
|
|
225
|
+
const byUuid = (list, uuid) => (Array.isArray(list) ? list : []).find((item) => isRecord(item) && item.uuid === uuid);
|
|
226
|
+
const material = byUuid(json.materials, findMaterial(json.object));
|
|
227
|
+
const texture = byUuid(json.textures, material?.map ?? material?.texture);
|
|
228
|
+
const firstImage = Array.isArray(json.images) ? json.images[0] : undefined;
|
|
229
|
+
const image = byUuid(json.images, texture?.image) ?? (isRecord(firstImage) ? firstImage : undefined);
|
|
226
230
|
const url = typeof image?.url === 'string' && image.url ? image.url : null;
|
|
227
231
|
iconCache.set(asset, url);
|
|
228
232
|
return url;
|
package/dist/core/binding.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { TransformNode } from '@babylonjs/core/Meshes/transformNode';
|
|
1
|
+
import type { TransformNode } from '@babylonjs/core/Meshes/transformNode.js';
|
|
2
2
|
import type { ParticleSystem } from 'babylon.quarks';
|
|
3
|
-
import type { EffectTreeNode } from './effectTree';
|
|
3
|
+
import type { EffectTreeNode } from './effectTree.js';
|
|
4
|
+
/** Called after every change made through an {@link EffectBinding}. */
|
|
4
5
|
export type EditorListener = () => void;
|
|
5
6
|
/**
|
|
6
7
|
* Headless edit-model over a live ParticleSystem: mutate through apply() so every
|
|
@@ -20,11 +21,18 @@ export declare class EffectBinding {
|
|
|
20
21
|
constructor(system: ParticleSystem, subSystems?: ParticleSystem[], root?: TransformNode);
|
|
21
22
|
/** Editor hierarchy tree (groups + emitters) rooted at this effect's scene root. */
|
|
22
23
|
getTree(): EffectTreeNode;
|
|
24
|
+
/** Calls `listener` after every change; returns the call that stops it. */
|
|
23
25
|
subscribe(listener: EditorListener): () => void;
|
|
24
26
|
/** Monotonic change counter, usable as a React external-store snapshot. */
|
|
25
27
|
getRevision(): number;
|
|
28
|
+
/**
|
|
29
|
+
* Changes the main system through `mutate`: takes an undo snapshot first, then notifies
|
|
30
|
+
* subscribers. Every inspector edit goes through here.
|
|
31
|
+
*/
|
|
26
32
|
apply(mutate: (system: ParticleSystem) => void): void;
|
|
33
|
+
/** Adds a system to the effect's sub systems. */
|
|
27
34
|
addSubSystem(sub: ParticleSystem): void;
|
|
35
|
+
/** Removes a system from the effect's sub systems; a system it does not have is ignored. */
|
|
28
36
|
removeSubSystem(sub: ParticleSystem): void;
|
|
29
37
|
/**
|
|
30
38
|
* Swaps which system is "main" — used when the current `system` is about to be removed
|
|
@@ -39,6 +47,7 @@ export declare class EffectBinding {
|
|
|
39
47
|
*/
|
|
40
48
|
markChanged(): void;
|
|
41
49
|
private notify;
|
|
50
|
+
/** Restarts every system of the effect from time 0. */
|
|
42
51
|
restart(): void;
|
|
43
52
|
/**
|
|
44
53
|
* Serializes the effect into the Quarks JSON envelope understood by QuarksLoader,
|
package/dist/core/binding.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildEffectTree, serializeEffectTree } from './effectTree';
|
|
1
|
+
import { buildEffectTree, serializeEffectTree } from './effectTree.js';
|
|
2
2
|
/**
|
|
3
3
|
* Headless edit-model over a live ParticleSystem: mutate through apply() so every
|
|
4
4
|
* change notifies subscribers (React UI, save indicators, hosts like BabylonJS Editor).
|
|
@@ -17,6 +17,7 @@ export class EffectBinding {
|
|
|
17
17
|
getTree() {
|
|
18
18
|
return buildEffectTree(this.root);
|
|
19
19
|
}
|
|
20
|
+
/** Calls `listener` after every change; returns the call that stops it. */
|
|
20
21
|
subscribe(listener) {
|
|
21
22
|
this.listeners.add(listener);
|
|
22
23
|
return () => this.listeners.delete(listener);
|
|
@@ -25,15 +26,21 @@ export class EffectBinding {
|
|
|
25
26
|
getRevision() {
|
|
26
27
|
return this.revision;
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Changes the main system through `mutate`: takes an undo snapshot first, then notifies
|
|
31
|
+
* subscribers. Every inspector edit goes through here.
|
|
32
|
+
*/
|
|
28
33
|
apply(mutate) {
|
|
29
34
|
this.onBeforeChange?.();
|
|
30
35
|
mutate(this.system);
|
|
31
36
|
this.notify();
|
|
32
37
|
}
|
|
38
|
+
/** Adds a system to the effect's sub systems. */
|
|
33
39
|
addSubSystem(sub) {
|
|
34
40
|
this.subSystems.push(sub);
|
|
35
41
|
this.notify();
|
|
36
42
|
}
|
|
43
|
+
/** Removes a system from the effect's sub systems; a system it does not have is ignored. */
|
|
37
44
|
removeSubSystem(sub) {
|
|
38
45
|
const index = this.subSystems.indexOf(sub);
|
|
39
46
|
if (index >= 0) {
|
|
@@ -69,6 +76,7 @@ export class EffectBinding {
|
|
|
69
76
|
listener();
|
|
70
77
|
}
|
|
71
78
|
}
|
|
79
|
+
/** Restarts every system of the effect from time 0. */
|
|
72
80
|
restart() {
|
|
73
81
|
// onlyUsedByOther systems skip self-emission in update(); play() only unpauses sim.
|
|
74
82
|
for (const system of [this.system, ...this.subSystems]) {
|
package/dist/core/collision.d.ts
CHANGED
|
@@ -8,7 +8,11 @@ import { Vector3 } from 'babylon.quarks';
|
|
|
8
8
|
*/
|
|
9
9
|
export declare class GroundPlaneResolver {
|
|
10
10
|
y: number;
|
|
11
|
+
/** @param y - Height of the ground plane. */
|
|
11
12
|
constructor(y?: number);
|
|
13
|
+
/**
|
|
14
|
+
* True when `position` is at or below the plane, with the plane's normal written to `normal`.
|
|
15
|
+
*/
|
|
12
16
|
resolve(position: Vector3, normal: Vector3): boolean;
|
|
13
17
|
}
|
|
14
18
|
/**
|
package/dist/core/collision.js
CHANGED
|
@@ -7,9 +7,13 @@ import { getPhysicsResolver, setPhysicsResolver } from 'babylon.quarks';
|
|
|
7
7
|
* which is exactly what ApplyCollision.update reflects the velocity against.
|
|
8
8
|
*/
|
|
9
9
|
export class GroundPlaneResolver {
|
|
10
|
+
/** @param y - Height of the ground plane. */
|
|
10
11
|
constructor(y = 0) {
|
|
11
12
|
this.y = y;
|
|
12
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* True when `position` is at or below the plane, with the plane's normal written to `normal`.
|
|
16
|
+
*/
|
|
13
17
|
resolve(position, normal) {
|
|
14
18
|
if (position.y <= this.y) {
|
|
15
19
|
normal.set(0, 1, 0);
|
package/dist/core/colors.d.ts
CHANGED
|
@@ -2,28 +2,44 @@ import type { Behavior } from 'babylon.quarks';
|
|
|
2
2
|
import { ColorOverLife, Gradient, Vector4 } from 'babylon.quarks';
|
|
3
3
|
/** One RGBA stop of the editable gradient (all channels 0..1, pos 0..1). */
|
|
4
4
|
export interface GradientStop {
|
|
5
|
+
/** Where the stop sits over the particle's life, 0..1. */
|
|
5
6
|
pos: number;
|
|
7
|
+
/** Red, 0..1. */
|
|
6
8
|
r: number;
|
|
9
|
+
/** Green, 0..1. */
|
|
7
10
|
g: number;
|
|
11
|
+
/** Blue, 0..1. */
|
|
8
12
|
b: number;
|
|
13
|
+
/** Alpha, 0..1. */
|
|
9
14
|
a: number;
|
|
10
15
|
}
|
|
16
|
+
/** The gradient a new Color over Lifetime starts with: warm yellow fading out through red. */
|
|
11
17
|
export declare const DEFAULT_GRADIENT_STOPS: GradientStop[];
|
|
18
|
+
/** A quarks gradient through `stops`, sorted by position; colour and alpha share the stops. */
|
|
12
19
|
export declare function buildGradient(stops: GradientStop[]): Gradient;
|
|
20
|
+
/** A Color over Lifetime behavior through `stops`. */
|
|
13
21
|
export declare function buildColorOverLife(stops: GradientStop[]): ColorOverLife;
|
|
22
|
+
/** An RGBA colour as a quarks `Vector4`. */
|
|
14
23
|
export declare function rgbaToVector4(stop: {
|
|
15
24
|
r: number;
|
|
16
25
|
g: number;
|
|
17
26
|
b: number;
|
|
18
27
|
a: number;
|
|
19
28
|
}): Vector4;
|
|
29
|
+
/** A stop's colour as CSS `rgba()`. */
|
|
20
30
|
export declare function stopToCss(stop: GradientStop): string;
|
|
31
|
+
/** The stops as a left-to-right CSS `linear-gradient`, for a gradient preview. */
|
|
21
32
|
export declare function stopsToCssGradient(stops: GradientStop[]): string;
|
|
33
|
+
/** A `#rrggbb` colour as channels 0..1. */
|
|
22
34
|
export declare function hexToRgb(hex: string): {
|
|
35
|
+
/** Red, 0..1. */
|
|
23
36
|
r: number;
|
|
37
|
+
/** Green, 0..1. */
|
|
24
38
|
g: number;
|
|
39
|
+
/** Blue, 0..1. */
|
|
25
40
|
b: number;
|
|
26
41
|
};
|
|
42
|
+
/** Channels 0..1, clamped, as a `#rrggbb` colour. */
|
|
27
43
|
export declare function rgbToHex(r: number, g: number, b: number): string;
|
|
28
44
|
/** Reads RGBA stops back from a Gradient (union of color/alpha key positions). */
|
|
29
45
|
export declare function readGradientStops(gradient: Gradient): GradientStop[];
|
package/dist/core/colors.js
CHANGED
|
@@ -1,27 +1,34 @@
|
|
|
1
1
|
import { ColorOverLife, Gradient, Vector3, Vector4 } from 'babylon.quarks';
|
|
2
|
+
/** The gradient a new Color over Lifetime starts with: warm yellow fading out through red. */
|
|
2
3
|
export const DEFAULT_GRADIENT_STOPS = [
|
|
3
4
|
{ pos: 0, r: 1, g: 0.85, b: 0.4, a: 1 },
|
|
4
5
|
{ pos: 1, r: 1, g: 0.25, b: 0.05, a: 0 },
|
|
5
6
|
];
|
|
7
|
+
/** A quarks gradient through `stops`, sorted by position; colour and alpha share the stops. */
|
|
6
8
|
export function buildGradient(stops) {
|
|
7
9
|
const sorted = [...stops].sort((a, b) => a.pos - b.pos);
|
|
8
10
|
return new Gradient(sorted.map((s) => [new Vector3(s.r, s.g, s.b), s.pos]), sorted.map((s) => [s.a, s.pos]));
|
|
9
11
|
}
|
|
12
|
+
/** A Color over Lifetime behavior through `stops`. */
|
|
10
13
|
export function buildColorOverLife(stops) {
|
|
11
14
|
return new ColorOverLife(buildGradient(stops));
|
|
12
15
|
}
|
|
16
|
+
/** An RGBA colour as a quarks `Vector4`. */
|
|
13
17
|
export function rgbaToVector4(stop) {
|
|
14
18
|
return new Vector4(stop.r, stop.g, stop.b, stop.a);
|
|
15
19
|
}
|
|
20
|
+
/** A stop's colour as CSS `rgba()`. */
|
|
16
21
|
export function stopToCss(stop) {
|
|
17
22
|
const c = (v) => Math.round(v * 255);
|
|
18
23
|
return `rgba(${c(stop.r)}, ${c(stop.g)}, ${c(stop.b)}, ${stop.a.toFixed(2)})`;
|
|
19
24
|
}
|
|
25
|
+
/** The stops as a left-to-right CSS `linear-gradient`, for a gradient preview. */
|
|
20
26
|
export function stopsToCssGradient(stops) {
|
|
21
27
|
const sorted = [...stops].sort((a, b) => a.pos - b.pos);
|
|
22
28
|
const parts = sorted.map((s) => `${stopToCss(s)} ${(s.pos * 100).toFixed(1)}%`);
|
|
23
29
|
return `linear-gradient(90deg, ${parts.join(', ')})`;
|
|
24
30
|
}
|
|
31
|
+
/** A `#rrggbb` colour as channels 0..1. */
|
|
25
32
|
export function hexToRgb(hex) {
|
|
26
33
|
const value = hex.replace('#', '');
|
|
27
34
|
return {
|
|
@@ -30,6 +37,7 @@ export function hexToRgb(hex) {
|
|
|
30
37
|
b: parseInt(value.slice(4, 6), 16) / 255,
|
|
31
38
|
};
|
|
32
39
|
}
|
|
40
|
+
/** Channels 0..1, clamped, as a `#rrggbb` colour. */
|
|
33
41
|
export function rgbToHex(r, g, b) {
|
|
34
42
|
const c = (v) => Math.round(Math.min(1, Math.max(0, v)) * 255)
|
|
35
43
|
.toString(16)
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Texture } from '@babylonjs/core/Materials/Textures/texture.js';
|
|
2
|
+
import type { Scene } from '@babylonjs/core/scene.js';
|
|
2
3
|
import { ParticleSystem } from 'babylon.quarks';
|
|
3
|
-
import { type SceneEntry } from './sceneEntries';
|
|
4
|
+
import { type SceneEntry } from './sceneEntries.js';
|
|
4
5
|
export interface CreateSceneDefaultOptions {
|
|
5
|
-
resolveTexture?: (url: string, scene: Scene) =>
|
|
6
|
+
resolveTexture?: (url: string, scene: Scene) => Texture | null | undefined;
|
|
6
7
|
textureUrl?: string;
|
|
7
8
|
}
|
|
8
9
|
/** Creates a simple cone burst preset for new editor effects. */
|
|
9
|
-
export declare function createDefaultEffect(scene: Scene, resolveTexture?: (url: string, scene: Scene) =>
|
|
10
|
+
export declare function createDefaultEffect(scene: Scene, resolveTexture?: (url: string, scene: Scene) => Texture | null | undefined, textureUrl?: string): ParticleSystem;
|
|
10
11
|
/** Creates a preset effect as a new scene entry (systems not registered with the renderer yet). */
|
|
11
12
|
export declare function createSceneDefaultEntry(scene: Scene, existing: SceneEntry[], options?: CreateSceneDefaultOptions): SceneEntry;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
|
|
1
|
+
import { TransformNode } from '@babylonjs/core/Meshes/transformNode.js';
|
|
2
2
|
import { ColorOverLife, ConeEmitter, ConstantColor, ConstantValue, IntervalValue, ParticleSystem, RenderMode, Vector4, } from 'babylon.quarks';
|
|
3
|
-
import { DEFAULT_GRADIENT_STOPS, buildGradient } from './colors';
|
|
4
|
-
import { uniqueEntryName } from './sceneEntries';
|
|
3
|
+
import { DEFAULT_GRADIENT_STOPS, buildGradient } from './colors.js';
|
|
4
|
+
import { uniqueEntryName } from './sceneEntries.js';
|
|
5
5
|
/** Creates a simple cone burst preset for new editor effects. */
|
|
6
6
|
export function createDefaultEffect(scene, resolveTexture, textureUrl) {
|
|
7
7
|
const system = new ParticleSystem({
|
|
@@ -15,7 +15,7 @@ export function createDefaultEffect(scene, resolveTexture, textureUrl) {
|
|
|
15
15
|
emissionOverTime: new ConstantValue(80),
|
|
16
16
|
shape: new ConeEmitter({ radius: 0.3, angle: 0.25 }),
|
|
17
17
|
renderMode: RenderMode.BillBoard,
|
|
18
|
-
texture:
|
|
18
|
+
texture: textureUrl && resolveTexture ? resolveTexture(textureUrl, scene) : undefined,
|
|
19
19
|
transparent: true,
|
|
20
20
|
blendMode: 1,
|
|
21
21
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TransformNode } from '@babylonjs/core/Meshes/transformNode';
|
|
1
|
+
import type { TransformNode } from '@babylonjs/core/Meshes/transformNode.js';
|
|
2
2
|
/** Marks meshes/nodes created only for editor interaction or overlays (not part of the effect). */
|
|
3
3
|
export declare const EDITOR_SCENE_NODE_METADATA: {
|
|
4
4
|
quarksEditorSceneNode: true;
|