babylon.quarks-editor 0.25.0 → 0.27.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 +69 -0
- package/README.md +38 -5
- package/dist/core/assetDragSession.d.ts +1 -1
- package/dist/core/assetTree.d.ts +1 -1
- package/dist/core/binding.d.ts +2 -2
- package/dist/core/binding.js +1 -1
- package/dist/core/defaultEffect.d.ts +2 -2
- package/dist/core/defaultEffect.js +3 -3
- package/dist/core/editorScene.d.ts +1 -1
- package/dist/core/effectTree.d.ts +1 -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/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 +1 -1
- package/dist/core/indexedDbProjectStore.d.ts +1 -1
- 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/pickAssetFiles.js +1 -1
- package/dist/core/sceneEntries.d.ts +4 -4
- package/dist/core/sceneEntries.js +2 -2
- package/dist/core/scrub.d.ts +1 -1
- package/dist/core/shapes.d.ts +1 -1
- package/dist/core/systems.d.ts +2 -2
- package/dist/core/textureExport.d.ts +1 -1
- package/dist/core/timeline.d.ts +2 -2
- package/dist/core/transport.d.ts +3 -3
- package/dist/core/transport.js +2 -2
- package/dist/core/viewportPicker.d.ts +4 -4
- package/dist/core/viewportPicker.js +8 -7
- package/dist/index.d.ts +21 -21
- package/dist/index.js +12 -12
- package/dist/react/AssetsPanel.d.ts +2 -2
- package/dist/react/AssetsPanel.js +6 -6
- package/dist/react/ChoiceDialog.js +1 -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 +2 -2
- package/dist/react/EditorWorkspace.js +4 -4
- package/dist/react/EffectEditor.d.ts +3 -3
- package/dist/react/EffectEditor.js +7 -7
- package/dist/react/EffectEditorHost.d.ts +6 -6
- package/dist/react/EffectEditorHost.js +59 -62
- package/dist/react/EffectTreeView.d.ts +1 -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.js +1 -1
- package/dist/react/ModuleSection.js +4 -4
- package/dist/react/ObjectModule.d.ts +1 -1
- package/dist/react/ObjectModule.js +4 -4
- package/dist/react/ProjectsPage.d.ts +1 -1
- package/dist/react/ProjectsPage.js +6 -6
- package/dist/react/PromptDialog.js +1 -1
- package/dist/react/ScenePanel.d.ts +2 -2
- package/dist/react/ScenePanel.js +5 -5
- 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 +7 -7
- package/dist/react/TimelinePanel.js +11 -9
- package/dist/react/TimelineTrackRow.d.ts +3 -3
- package/dist/react/TimelineTrackRow.js +6 -6
- package/dist/react/TransportBar.d.ts +4 -4
- package/dist/react/TransportBar.js +3 -3
- package/dist/react/ValueField.d.ts +1 -1
- package/dist/react/ValueField.js +3 -3
- package/dist/react/behaviorModules.d.ts +4 -2
- package/dist/react/behaviorModules.js +52 -16
- package/dist/react/fields.d.ts +1 -0
- package/dist/react/fields.js +3 -3
- package/dist/react/index.d.ts +40 -38
- package/dist/react/index.js +25 -23
- package/dist/react/inspectorHints.js +31 -0
- package/dist/react/modules.d.ts +3 -1
- package/dist/react/modules.js +100 -100
- package/package.json +3 -2
- package/src/core/assetDragSession.ts +1 -1
- package/src/core/assetTree.ts +1 -1
- package/src/core/binding.ts +3 -3
- package/src/core/defaultEffect.ts +4 -4
- package/src/core/editorScene.ts +1 -1
- package/src/core/effectTree.ts +13 -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 +1 -1
- 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 +1 -1
- package/src/core/indexedDbProjectStore.ts +1 -1
- package/src/core/lineShaders.ts +2 -2
- package/src/core/loadEffect.ts +3 -3
- package/src/core/pickAssetFiles.ts +2 -2
- package/src/core/sceneEntries.ts +5 -5
- package/src/core/scrub.ts +1 -1
- package/src/core/shapes.ts +1 -1
- package/src/core/systems.ts +2 -2
- package/src/core/textureExport.ts +1 -1
- package/src/core/timeline.ts +3 -3
- package/src/core/transport.ts +4 -4
- package/src/core/viewportPicker.ts +12 -11
- package/src/index.ts +21 -21
- package/src/react/AssetsPanel.tsx +6 -6
- package/src/react/ChoiceDialog.tsx +1 -1
- package/src/react/ContextMenu.tsx +1 -1
- package/src/react/CurveEditor.tsx +2 -2
- package/src/react/EditorWorkspace.tsx +5 -5
- package/src/react/EffectEditor.tsx +10 -8
- package/src/react/EffectEditorHost.tsx +64 -69
- package/src/react/EffectTreeView.tsx +4 -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 +1 -1
- package/src/react/ModuleSection.tsx +4 -4
- package/src/react/ObjectModule.tsx +5 -5
- package/src/react/ProjectsPage.tsx +6 -6
- package/src/react/PromptDialog.tsx +1 -1
- package/src/react/ScenePanel.tsx +7 -7
- 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 +17 -15
- package/src/react/TimelineTrackRow.tsx +9 -9
- package/src/react/TransportBar.tsx +7 -7
- package/src/react/ValueField.tsx +3 -3
- package/src/react/behaviorModules.tsx +211 -28
- package/src/react/fields.tsx +10 -3
- package/src/react/index.ts +41 -38
- package/src/react/inspectorHints.ts +40 -0
- package/src/react/modules.tsx +376 -131
package/dist/react/index.d.ts
CHANGED
|
@@ -1,38 +1,40 @@
|
|
|
1
|
-
export { AssetsPanel } from './AssetsPanel';
|
|
2
|
-
export type { AssetsPanelProps } from './AssetsPanel';
|
|
3
|
-
export { CollisionModule, ColorBySpeedModule, EmitDirectionModule, ForceOverLifeModule, GravityModule, LimitSpeedOverLifeModule, NoiseModule, OrbitOverLifeModule, RotationBySpeedModule, RotationOverLifeModule, SizeBySpeedModule, SpeedOverLifeModule, TextureSheetModule, TurbulenceModule, WidthOverTrailModule, } from './behaviorModules';
|
|
4
|
-
export { ChoiceDialog } from './ChoiceDialog';
|
|
5
|
-
export type { ChoiceDialogAction, ChoiceDialogProps } from './ChoiceDialog';
|
|
6
|
-
export { ContextMenu } from './ContextMenu';
|
|
7
|
-
export type { ContextMenuItem, ContextMenuProps } from './ContextMenu';
|
|
8
|
-
export { CurveEditor } from './CurveEditor';
|
|
9
|
-
export { EditorWorkspace, QuarksEditorWorkspace } from './EditorWorkspace';
|
|
10
|
-
export type { EditorWorkspaceProps } from './EditorWorkspace';
|
|
11
|
-
export { EffectEditor } from './EffectEditor';
|
|
12
|
-
export type { EffectEditorProps } from './EffectEditor';
|
|
13
|
-
export { EffectEditorHost, QuarksEffectEditor } from './EffectEditorHost';
|
|
14
|
-
export type { EffectEditorHostHandle, EffectEditorHostProps } from './EffectEditorHost';
|
|
15
|
-
export { EffectTreeView } from './EffectTreeView';
|
|
16
|
-
export type { EffectTreeViewProps } from './EffectTreeView';
|
|
17
|
-
export { CheckboxField, NumberField, Row, SelectField } from './fields';
|
|
18
|
-
export { GradientEditor } from './GradientEditor';
|
|
19
|
-
export { MessageDialog } from './MessageDialog';
|
|
20
|
-
export type { MessageDialogProps } from './MessageDialog';
|
|
21
|
-
export { ColorOverLifeModule, EmissionModule, MainModule, RendererModule, ShapeModule, SizeOverLifeModule, } from './modules';
|
|
22
|
-
export type { GeometryData, GeometryOption, TextureOption } from './modules';
|
|
23
|
-
export { ModuleSection } from './ModuleSection';
|
|
24
|
-
export { ProjectsPage } from './ProjectsPage';
|
|
25
|
-
export type { ProjectsPageProps } from './ProjectsPage';
|
|
26
|
-
export { PromptDialog } from './PromptDialog';
|
|
27
|
-
export type { PromptDialogProps } from './PromptDialog';
|
|
28
|
-
export { ScenePanel } from './ScenePanel';
|
|
29
|
-
export type { ScenePanelProps } from './ScenePanel';
|
|
30
|
-
export { SubEmittersModule } from './SubEmittersModule';
|
|
31
|
-
export {
|
|
32
|
-
export {
|
|
33
|
-
export
|
|
34
|
-
export {
|
|
35
|
-
export type {
|
|
36
|
-
export {
|
|
37
|
-
export type {
|
|
38
|
-
export {
|
|
1
|
+
export { AssetsPanel } from './AssetsPanel.js';
|
|
2
|
+
export type { AssetsPanelProps } from './AssetsPanel.js';
|
|
3
|
+
export { AttractorModule, CollisionModule, ColorBySpeedModule, EmitDirectionModule, ForceOverLifeModule, GravityModule, LimitSpeedOverLifeModule, NoiseModule, OrbitOverLifeModule, RotationBySpeedModule, RotationOverLifeModule, SizeBySpeedModule, SpeedOverLifeModule, TextureSheetModule, TurbulenceModule, WidthOverTrailModule, } from './behaviorModules.js';
|
|
4
|
+
export { ChoiceDialog } from './ChoiceDialog.js';
|
|
5
|
+
export type { ChoiceDialogAction, ChoiceDialogProps } from './ChoiceDialog.js';
|
|
6
|
+
export { ContextMenu } from './ContextMenu.js';
|
|
7
|
+
export type { ContextMenuItem, ContextMenuProps } from './ContextMenu.js';
|
|
8
|
+
export { CurveEditor } from './CurveEditor.js';
|
|
9
|
+
export { EditorWorkspace, QuarksEditorWorkspace } from './EditorWorkspace.js';
|
|
10
|
+
export type { EditorWorkspaceProps } from './EditorWorkspace.js';
|
|
11
|
+
export { EffectEditor } from './EffectEditor.js';
|
|
12
|
+
export type { EffectEditorProps } from './EffectEditor.js';
|
|
13
|
+
export { EffectEditorHost, QuarksEffectEditor } from './EffectEditorHost.js';
|
|
14
|
+
export type { EffectEditorHostHandle, EffectEditorHostProps } from './EffectEditorHost.js';
|
|
15
|
+
export { EffectTreeView } from './EffectTreeView.js';
|
|
16
|
+
export type { EffectTreeViewProps } from './EffectTreeView.js';
|
|
17
|
+
export { CheckboxField, NumberField, Row, SelectField } from './fields.js';
|
|
18
|
+
export { GradientEditor } from './GradientEditor.js';
|
|
19
|
+
export { MessageDialog } from './MessageDialog.js';
|
|
20
|
+
export type { MessageDialogProps } from './MessageDialog.js';
|
|
21
|
+
export { ColorOverLifeModule, EmissionModule, MainModule, RendererModule, ShapeModule, SizeOverLifeModule, } from './modules.js';
|
|
22
|
+
export type { GeometryData, GeometryOption, TextureOption } from './modules.js';
|
|
23
|
+
export { ModuleSection } from './ModuleSection.js';
|
|
24
|
+
export { ProjectsPage } from './ProjectsPage.js';
|
|
25
|
+
export type { ProjectsPageProps } from './ProjectsPage.js';
|
|
26
|
+
export { PromptDialog } from './PromptDialog.js';
|
|
27
|
+
export type { PromptDialogProps } from './PromptDialog.js';
|
|
28
|
+
export { ScenePanel } from './ScenePanel.js';
|
|
29
|
+
export type { ScenePanelProps } from './ScenePanel.js';
|
|
30
|
+
export { SubEmittersModule } from './SubEmittersModule.js';
|
|
31
|
+
export { TextureSelect, textureUrlOf } from './TextureSelect.js';
|
|
32
|
+
export { TextureUVField } from './TextureUVField.js';
|
|
33
|
+
export { buttonStyle, inputStyle, labelStyle, rowStyle, theme } from './theme.js';
|
|
34
|
+
export { TimelinePanel } from './TimelinePanel.js';
|
|
35
|
+
export type { PlaybackState, TimelinePanelProps } from './TimelinePanel.js';
|
|
36
|
+
export { TimelineTrackRow } from './TimelineTrackRow.js';
|
|
37
|
+
export type { TimelineTrackRowProps } from './TimelineTrackRow.js';
|
|
38
|
+
export { TransportBar } from './TransportBar.js';
|
|
39
|
+
export type { TransportBarProps } from './TransportBar.js';
|
|
40
|
+
export { ValueField } from './ValueField.js';
|
package/dist/react/index.js
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
export { AssetsPanel } from './AssetsPanel';
|
|
2
|
-
export { CollisionModule, ColorBySpeedModule, EmitDirectionModule, ForceOverLifeModule, GravityModule, LimitSpeedOverLifeModule, NoiseModule, OrbitOverLifeModule, RotationBySpeedModule, RotationOverLifeModule, SizeBySpeedModule, SpeedOverLifeModule, TextureSheetModule, TurbulenceModule, WidthOverTrailModule, } from './behaviorModules';
|
|
3
|
-
export { ChoiceDialog } from './ChoiceDialog';
|
|
4
|
-
export { ContextMenu } from './ContextMenu';
|
|
5
|
-
export { CurveEditor } from './CurveEditor';
|
|
6
|
-
export { EditorWorkspace, QuarksEditorWorkspace } from './EditorWorkspace';
|
|
7
|
-
export { EffectEditor } from './EffectEditor';
|
|
8
|
-
export { EffectEditorHost, QuarksEffectEditor } from './EffectEditorHost';
|
|
9
|
-
export { EffectTreeView } from './EffectTreeView';
|
|
10
|
-
export { CheckboxField, NumberField, Row, SelectField } from './fields';
|
|
11
|
-
export { GradientEditor } from './GradientEditor';
|
|
12
|
-
export { MessageDialog } from './MessageDialog';
|
|
13
|
-
export { ColorOverLifeModule, EmissionModule, MainModule, RendererModule, ShapeModule, SizeOverLifeModule, } from './modules';
|
|
14
|
-
export { ModuleSection } from './ModuleSection';
|
|
15
|
-
export { ProjectsPage } from './ProjectsPage';
|
|
16
|
-
export { PromptDialog } from './PromptDialog';
|
|
17
|
-
export { ScenePanel } from './ScenePanel';
|
|
18
|
-
export { SubEmittersModule } from './SubEmittersModule';
|
|
19
|
-
export {
|
|
20
|
-
export {
|
|
21
|
-
export {
|
|
22
|
-
export {
|
|
23
|
-
export {
|
|
1
|
+
export { AssetsPanel } from './AssetsPanel.js';
|
|
2
|
+
export { AttractorModule, CollisionModule, ColorBySpeedModule, EmitDirectionModule, ForceOverLifeModule, GravityModule, LimitSpeedOverLifeModule, NoiseModule, OrbitOverLifeModule, RotationBySpeedModule, RotationOverLifeModule, SizeBySpeedModule, SpeedOverLifeModule, TextureSheetModule, TurbulenceModule, WidthOverTrailModule, } from './behaviorModules.js';
|
|
3
|
+
export { ChoiceDialog } from './ChoiceDialog.js';
|
|
4
|
+
export { ContextMenu } from './ContextMenu.js';
|
|
5
|
+
export { CurveEditor } from './CurveEditor.js';
|
|
6
|
+
export { EditorWorkspace, QuarksEditorWorkspace } from './EditorWorkspace.js';
|
|
7
|
+
export { EffectEditor } from './EffectEditor.js';
|
|
8
|
+
export { EffectEditorHost, QuarksEffectEditor } from './EffectEditorHost.js';
|
|
9
|
+
export { EffectTreeView } from './EffectTreeView.js';
|
|
10
|
+
export { CheckboxField, NumberField, Row, SelectField } from './fields.js';
|
|
11
|
+
export { GradientEditor } from './GradientEditor.js';
|
|
12
|
+
export { MessageDialog } from './MessageDialog.js';
|
|
13
|
+
export { ColorOverLifeModule, EmissionModule, MainModule, RendererModule, ShapeModule, SizeOverLifeModule, } from './modules.js';
|
|
14
|
+
export { ModuleSection } from './ModuleSection.js';
|
|
15
|
+
export { ProjectsPage } from './ProjectsPage.js';
|
|
16
|
+
export { PromptDialog } from './PromptDialog.js';
|
|
17
|
+
export { ScenePanel } from './ScenePanel.js';
|
|
18
|
+
export { SubEmittersModule } from './SubEmittersModule.js';
|
|
19
|
+
export { TextureSelect, textureUrlOf } from './TextureSelect.js';
|
|
20
|
+
export { TextureUVField } from './TextureUVField.js';
|
|
21
|
+
export { buttonStyle, inputStyle, labelStyle, rowStyle, theme } from './theme.js';
|
|
22
|
+
export { TimelinePanel } from './TimelinePanel.js';
|
|
23
|
+
export { TimelineTrackRow } from './TimelineTrackRow.js';
|
|
24
|
+
export { TransportBar } from './TransportBar.js';
|
|
25
|
+
export { ValueField } from './ValueField.js';
|
|
@@ -13,6 +13,7 @@ const INSPECTOR_HINTS = {
|
|
|
13
13
|
'Velocity over Lifetime': 'Adds linear and orbital velocity each frame in local or world space.',
|
|
14
14
|
'Inherit Velocity': 'Copies the emitter’s movement into new particle velocity.',
|
|
15
15
|
Gravity: 'Applies a constant downward force (Earth-like gravity by default).',
|
|
16
|
+
Attractor: 'Pulls particles towards a point, harder the nearer they are (a point gravity).',
|
|
16
17
|
'Rotation over Lifetime': 'Spins particles by setting angular velocity over lifetime.',
|
|
17
18
|
Noise: 'Procedural noise that jitters particle position and rotation.',
|
|
18
19
|
Turbulence: '3D turbulent velocity field that swirls particles through space.',
|
|
@@ -30,7 +31,9 @@ const INSPECTOR_HINTS = {
|
|
|
30
31
|
Duration: 'How long the particle system runs before stopping (non-looping) or one loop cycle.',
|
|
31
32
|
Looping: 'When enabled, the effect restarts from the beginning after duration ends.',
|
|
32
33
|
'World space': 'Simulates in world coordinates so moving the emitter does not drag existing particles.',
|
|
34
|
+
'Scaling mode': 'What the emitter’s scale does to a world-space system: only the shape and sizes, or speeds and forces too (Unity’s Scaling Mode).',
|
|
33
35
|
Prewarm: 'Simulates the effect once at start so it already looks mid-playback when play begins.',
|
|
36
|
+
'Warm-up time': 'Seconds of the cycle simulated before the first frame of a looping system (Niagara’s Warmup Time); 0 warms up a whole cycle, as Unity does.',
|
|
34
37
|
'Start delay': 'Wait time before emission starts after play or restart.',
|
|
35
38
|
'Start lifetime': 'How long each spawned particle lives before dying.',
|
|
36
39
|
'Start speed': 'Initial speed along the emission direction when a particle is born.',
|
|
@@ -66,12 +69,32 @@ const INSPECTOR_HINTS = {
|
|
|
66
69
|
'Render mode': 'Orientation and geometry used to draw each particle.',
|
|
67
70
|
'Trail length': 'Maximum number of trail segments per particle (trail mode).',
|
|
68
71
|
'Follow origin': 'Keeps the trail anchored to the emitter origin instead of the particle head.',
|
|
72
|
+
'Texture mode': 'How the texture runs along the ribbon: once by distance, once with each segment an equal share, repeated per world unit, or once per segment.',
|
|
73
|
+
'Texture scale': 'Repeats of the texture: per world unit (tile), per segment (repeat), or over the ribbon.',
|
|
74
|
+
'Min vertex distance': 'The particle has to move this far before a new point is fixed; the last point follows it meanwhile. 0: a point every step.',
|
|
75
|
+
'Trail time': 'How long a point is kept, in seconds, within the trail length. 0: until the trail length is reached.',
|
|
69
76
|
'Speed factor': 'How much particle speed stretches the billboard (stretched billboard mode).',
|
|
70
77
|
'Length factor': 'Base stretch multiplier for stretched billboards.',
|
|
71
78
|
Source: 'Material preset loaded from the effect JSON (read-only reference).',
|
|
72
79
|
'Blend mode': 'How particle color is composited over the background.',
|
|
73
80
|
Transparent: 'Enables alpha blending for soft edges and fade-outs.',
|
|
74
81
|
Texture: 'Sprite or flipbook image applied to each particle.',
|
|
82
|
+
'UV channel': 'Which UV set the texture reads: the sprite or mesh UV, or a mesh’s second set / the length of a trail.',
|
|
83
|
+
Tiling: 'Repeats of the texture across the UV range, U and V (Unity’s material Tiling).',
|
|
84
|
+
Offset: 'Shift of the texture in UV units after tiling, U and V (Unity’s material Offset).',
|
|
85
|
+
Scroll: 'UV units per second the texture moves on the renderer’s clock (Unreal’s Panner).',
|
|
86
|
+
'Flip U/V': 'Fraction of particles mirrored horizontally and vertically, picked at birth (Unity’s renderer Flip).',
|
|
87
|
+
Ramp: 'Colour ramp read left to right; without one there is no gradient map.',
|
|
88
|
+
'Ramp channel': 'Which value of the map texel picks the colour along the ramp: one channel of a packed texture, or luminance.',
|
|
89
|
+
Erosion: 'Lets alpha erode the shape through a mask instead of fading it.',
|
|
90
|
+
'Erosion mask': 'Texture whose red channel orders what goes first; none uses the map’s own alpha.',
|
|
91
|
+
Softness: 'Width of the soft transition at the erosion cut, in mask units.',
|
|
92
|
+
'Edge width': 'Width of the glowing band above the erosion cut; 0 draws none.',
|
|
93
|
+
'Edge color': 'Linear RGB added in the edge band; may exceed 1 for a glow.',
|
|
94
|
+
'Noise texture': 'Texture whose red and green channels push the map’s UV about; it should repeat.',
|
|
95
|
+
'Distortion strength': 'How far the map’s UV is pushed at most, in UV units.',
|
|
96
|
+
'Swept trail': 'Spans the ribbon along a fixed axis of the emitter instead of facing the camera (a weapon trail).',
|
|
97
|
+
'Side axis': 'Local axis the swept trail spans its width along; give a unit vector.',
|
|
75
98
|
'Alpha test': 'Pixels below this alpha are discarded (cutout/hard edges).',
|
|
76
99
|
'Depth write': 'Writes to the depth buffer — usually off for additive particles.',
|
|
77
100
|
'Depth test': 'Whether particles are occluded by scene geometry.',
|
|
@@ -85,6 +108,14 @@ const INSPECTOR_HINTS = {
|
|
|
85
108
|
'Blend tiles': 'Smoothly blends between adjacent atlas tiles during animation.',
|
|
86
109
|
'Start tile': 'Atlas cell index where playback begins (0 = top-left).',
|
|
87
110
|
'Animate frames': 'Enables frame-over-lifetime curve to cycle through atlas tiles.',
|
|
111
|
+
'Time mode': 'Lifetime samples the curve over each particle’s life; FPS plays frames by age from the curve’s frame.',
|
|
112
|
+
FPS: 'Frames per second in FPS mode.',
|
|
113
|
+
Loop: 'In FPS mode, wrap back to the first frame of the segment, or hold the last.',
|
|
114
|
+
'Random frame': 'In FPS mode, show a random frame of the segment every tick instead of the next one.',
|
|
115
|
+
'Frame count': 'Frames in the segment that plays, from the first frame; 0 means no segment.',
|
|
116
|
+
'Start frame': 'Starts each particle on a random one of the first N frames (Unity’s Start Frame); editing sets a 0…N range.',
|
|
117
|
+
'attractor.center': 'Point in the system’s space particles are pulled towards.',
|
|
118
|
+
'attractor.magnitude': 'Pull strength, divided by the squared distance to the center.',
|
|
88
119
|
// Sub emitters
|
|
89
120
|
Trigger: 'When the child system is spawned: on particle birth, death, or every frame.',
|
|
90
121
|
'Use velocity': 'Orients the sub-emitter spawn using the parent particle’s velocity.',
|
package/dist/react/modules.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { EffectBinding } from '../core/binding';
|
|
2
|
+
import { EffectBinding } from '../core/binding.js';
|
|
3
3
|
interface ModuleProps {
|
|
4
4
|
binding: EffectBinding;
|
|
5
5
|
}
|
|
@@ -22,6 +22,8 @@ export interface GeometryOption {
|
|
|
22
22
|
positions: Float32Array | number[];
|
|
23
23
|
indices?: Uint32Array | number[];
|
|
24
24
|
uvs?: Float32Array | number[];
|
|
25
|
+
/** A second UV set (glTF `TEXCOORD_1`), what textures on UV channel 1 read on the mesh. */
|
|
26
|
+
uvs2?: Float32Array | number[];
|
|
25
27
|
normals?: Float32Array | number[];
|
|
26
28
|
}
|
|
27
29
|
/** Vertex buffers a host loader (e.g. a GLB importer) returns for the Mesh render mode. */
|
package/dist/react/modules.js
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Texture } from '@babylonjs/core/Materials/Textures/texture';
|
|
3
|
-
import { Mesh } from '@babylonjs/core/Meshes/mesh';
|
|
2
|
+
import { Texture } from '@babylonjs/core/Materials/Textures/texture.js';
|
|
3
|
+
import { Mesh } from '@babylonjs/core/Meshes/mesh.js';
|
|
4
4
|
import { PlusIcon, XMarkIcon } from '@heroicons/react/24/solid';
|
|
5
|
-
import { AxisAngleGenerator, BoxEmitFrom, ColorOverLife, ColorRange, ConstantColor, ConstantValue, EulerGenerator, Gradient, IntervalValue, RandomColor, RandomColorBetweenGradient, RandomQuatGenerator, RenderMode, SizeOverLife, Vector3, Vector3Function, Vector4, } from 'babylon.quarks';
|
|
6
|
-
import React, { useMemo
|
|
7
|
-
import { DEFAULT_GRADIENT_STOPS, buildGradient, findBehavior, hexToRgb, readGradientStops, rgbToHex, } from '../core/colors';
|
|
8
|
-
import { applyRendererMaterial, getMaterialLabel } from '../core/material';
|
|
9
|
-
import { DEFAULT_SHAPE_PARAMS, SHAPE_PARAM_KEYS, SHAPE_TYPES, createShape, getShapeType, readShapeParams, } from '../core/shapes';
|
|
10
|
-
import { buildCurve, buildScalar, readPieces, readScalar } from '../core/values';
|
|
11
|
-
import { CurveEditor } from './CurveEditor';
|
|
12
|
-
import { GradientEditor } from './GradientEditor';
|
|
13
|
-
import { InspectorInfoIcon } from './InspectorInfoIcon';
|
|
14
|
-
import { ModuleSection } from './ModuleSection';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
5
|
+
import { AxisAngleGenerator, BoxEmitFrom, ColorOverLife, ColorRange, ConstantColor, ConstantValue, EulerGenerator, Gradient, IntervalValue, RandomColor, RandomColorBetweenGradient, RandomQuatGenerator, RenderMode, SizeOverLife, Vector2, Vector3, Vector3Function, Vector4, normalizeTextureUV, } from 'babylon.quarks';
|
|
6
|
+
import React, { useMemo } from 'react';
|
|
7
|
+
import { DEFAULT_GRADIENT_STOPS, buildGradient, findBehavior, hexToRgb, readGradientStops, rgbToHex, } from '../core/colors.js';
|
|
8
|
+
import { applyRendererMaterial, getMaterialLabel } from '../core/material.js';
|
|
9
|
+
import { DEFAULT_SHAPE_PARAMS, SHAPE_PARAM_KEYS, SHAPE_TYPES, createShape, getShapeType, readShapeParams, } from '../core/shapes.js';
|
|
10
|
+
import { buildCurve, buildScalar, readPieces, readScalar } from '../core/values.js';
|
|
11
|
+
import { CurveEditor } from './CurveEditor.js';
|
|
12
|
+
import { GradientEditor } from './GradientEditor.js';
|
|
13
|
+
import { InspectorInfoIcon } from './InspectorInfoIcon.js';
|
|
14
|
+
import { ModuleSection } from './ModuleSection.js';
|
|
15
|
+
import { TextureSelect } from './TextureSelect.js';
|
|
16
|
+
import { TextureUVField } from './TextureUVField.js';
|
|
17
|
+
import { ValueField } from './ValueField.js';
|
|
18
|
+
import { CheckboxField, NumberField, Row, SelectField } from './fields.js';
|
|
19
|
+
import { iconStyle } from './icons.js';
|
|
20
|
+
import { theme } from './theme.js';
|
|
20
21
|
const MESH_QUAD_POSITIONS = new Float32Array([-0.5, -0.5, 0, 0.5, -0.5, 0, 0.5, 0.5, 0, -0.5, 0.5, 0]);
|
|
21
22
|
const MESH_QUAD_INDICES = new Uint32Array([0, 1, 2, 0, 2, 3]);
|
|
22
23
|
const MESH_QUAD_UVS = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
|
|
@@ -61,6 +62,29 @@ const PARAM_LABELS = {
|
|
|
61
62
|
depth: 'Depth',
|
|
62
63
|
speed: 'Speed (lengths/s)',
|
|
63
64
|
};
|
|
65
|
+
/** Uppercase group title inside a module, as the Renderer's "Material" heading. */
|
|
66
|
+
function SubHeader(props) {
|
|
67
|
+
return (_jsxs("div", { style: {
|
|
68
|
+
marginTop: 10,
|
|
69
|
+
marginBottom: 2,
|
|
70
|
+
fontSize: 11,
|
|
71
|
+
fontWeight: 600,
|
|
72
|
+
color: '#7c8db5',
|
|
73
|
+
textTransform: 'uppercase',
|
|
74
|
+
letterSpacing: 0.4,
|
|
75
|
+
display: 'flex',
|
|
76
|
+
alignItems: 'center',
|
|
77
|
+
gap: 5,
|
|
78
|
+
}, children: [props.title, _jsx(InspectorInfoIcon, { content: props.hint, size: 12 })] }));
|
|
79
|
+
}
|
|
80
|
+
/** Three number inputs editing a Vector3 by value. */
|
|
81
|
+
function AxisField(props) {
|
|
82
|
+
return (_jsx("div", { style: { display: 'flex', gap: 6 }, children: ['x', 'y', 'z'].map((axis) => (_jsx(NumberField, { value: props.value[axis], step: 0.1, onChange: (v) => {
|
|
83
|
+
const next = props.value.clone();
|
|
84
|
+
next[axis] = v;
|
|
85
|
+
props.onChange(next);
|
|
86
|
+
} }, axis))) }));
|
|
87
|
+
}
|
|
64
88
|
function ColorInput(props) {
|
|
65
89
|
const { value, onChange } = props;
|
|
66
90
|
return (_jsxs("div", { style: { display: 'flex', gap: 6, alignItems: 'center' }, children: [_jsx("input", { type: "color", className: "qe-hover", value: rgbToHex(value.x, value.y, value.z), onChange: (e) => {
|
|
@@ -118,7 +142,10 @@ export function MainModule({ binding }) {
|
|
|
118
142
|
: startColor instanceof Gradient
|
|
119
143
|
? 'gradient'
|
|
120
144
|
: colorMode;
|
|
121
|
-
return (_jsxs(ModuleSection, { title: "Main", children: [_jsx(Row, { label: "Duration", children: _jsx(NumberField, { value: system.duration, min: 0.05, onChange: (v) => binding.apply((s) => (s.duration = v)) }) }), _jsx(Row, { label: "Looping", children: _jsx(CheckboxField, { value: system.looping, onChange: (v) => binding.apply((s) => (s.looping = v)) }) }), _jsx(Row, { label: "World space", children: _jsx(CheckboxField, { value: system.worldSpace, onChange: (v) => binding.apply((s) => (s.worldSpace = v)) }) }),
|
|
145
|
+
return (_jsxs(ModuleSection, { title: "Main", children: [_jsx(Row, { label: "Duration", children: _jsx(NumberField, { value: system.duration, min: 0.05, onChange: (v) => binding.apply((s) => (s.duration = v)) }) }), _jsx(Row, { label: "Looping", children: _jsx(CheckboxField, { value: system.looping, onChange: (v) => binding.apply((s) => (s.looping = v)) }) }), _jsx(Row, { label: "World space", children: _jsx(CheckboxField, { value: system.worldSpace, onChange: (v) => binding.apply((s) => (s.worldSpace = v)) }) }), system.worldSpace && (_jsx(Row, { label: "Scaling mode", children: _jsx(SelectField, { value: system.scalingMode, options: [
|
|
146
|
+
{ value: 'shape', label: 'Shape (sizes and shape only)' },
|
|
147
|
+
{ value: 'hierarchy', label: 'Hierarchy (motion scales too)' },
|
|
148
|
+
], onChange: (mode) => binding.apply((s) => (s.scalingMode = mode)) }) })), _jsx(Row, { label: "Prewarm", children: _jsx(CheckboxField, { value: system.prewarm, onChange: (v) => binding.apply((s) => (s.prewarm = v)) }) }), system.prewarm && (_jsx(Row, { label: "Warm-up time", children: _jsx(NumberField, { value: system.prewarmTime, step: 0.1, min: 0, onChange: (v) => binding.apply((s) => (s.prewarmTime = Math.max(0, v))) }) })), _jsx(Row, { label: "Playback speed", children: _jsx(NumberField, { value: system.playbackSpeed, step: 0.1, min: 0, onChange: (v) => binding.apply((s) => (s.playbackSpeed = Math.max(0, v))) }) }), _jsxs(Row, { label: "Fixed seed", children: [_jsx(CheckboxField, { value: system.seed !== undefined, onChange: (v) => binding.apply((s) => (s.seed = v ? (s.seed ?? 1) : undefined)) }), system.seed !== undefined && (_jsx(NumberField, { value: system.seed, step: 1, min: 0, onChange: (v) => binding.apply((s) => (s.seed = Math.max(0, Math.floor(v)))) }))] }), _jsx(Row, { label: "Off screen", children: _jsx(SelectField, { value: system.cullingMode, options: [
|
|
122
149
|
{ value: 'always', label: 'Always simulate' },
|
|
123
150
|
{ value: 'pause', label: 'Pause' },
|
|
124
151
|
{ value: 'pauseAndCatchUp', label: 'Pause and catch up' },
|
|
@@ -351,9 +378,13 @@ function MeshPreview({ positions, indices, size = 96, }) {
|
|
|
351
378
|
}
|
|
352
379
|
export function RendererModule({ binding, textureOptions, geometryOptions, resolveTexture, resolveGeometry, }) {
|
|
353
380
|
const system = binding.system;
|
|
354
|
-
const currentTextureUrl = system.texture?.url ?? '';
|
|
355
|
-
const [promptingTextureUrl, setPromptingTextureUrl] = useState(false);
|
|
356
381
|
const materialLabel = getMaterialLabel(system.material);
|
|
382
|
+
const isMesh = system.renderMode === RenderMode.Mesh;
|
|
383
|
+
const gradientMap = system.gradientMap;
|
|
384
|
+
const erosion = system.erosion;
|
|
385
|
+
const distortion = system.uvDistortion;
|
|
386
|
+
const patchErosion = (patch) => binding.apply((s) => (s.erosion = { ...s.erosion, ...patch }));
|
|
387
|
+
const patchDistortion = (patch) => binding.apply((s) => (s.uvDistortion = { ...s.uvDistortion, ...patch }));
|
|
357
388
|
const loadTexture = useMemo(() => {
|
|
358
389
|
return (url) => {
|
|
359
390
|
if (resolveTexture) {
|
|
@@ -386,88 +417,53 @@ export function RendererModule({ binding, textureOptions, geometryOptions, resol
|
|
|
386
417
|
['dieWithParticle', 'Die with particle'],
|
|
387
418
|
].map(([key, label]) => (_jsx(Row, { label: label, children: _jsx(CheckboxField, { value: !!system.rendererEmitterSettings[key], onChange: (v) => binding.apply((s) => {
|
|
388
419
|
s.rendererEmitterSettings[key] = v;
|
|
389
|
-
}) }) }, key))), _jsx(Row, { label: "
|
|
390
|
-
s.rendererEmitterSettings.
|
|
391
|
-
}) }) })
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
420
|
+
}) }) }, key))), _jsx(Row, { label: "Tessellation", children: _jsx(NumberField, { value: system.rendererEmitterSettings.tessellation ?? 0, min: 0, max: 16, step: 1, onChange: (v) => binding.apply((s) => {
|
|
421
|
+
s.rendererEmitterSettings.tessellation = Math.round(v);
|
|
422
|
+
}) }) }), _jsx(Row, { label: "Curve tension", children: _jsx(NumberField, { value: system.rendererEmitterSettings.curveTension ?? 0, min: 0, max: 1, step: 0.05, onChange: (v) => binding.apply((s) => {
|
|
423
|
+
s.rendererEmitterSettings.curveTension = v;
|
|
424
|
+
}) }) }), _jsx(Row, { label: "Texture mode", children: _jsx(SelectField, { value: system.rendererEmitterSettings.textureMode ?? 'stretch', options: [
|
|
425
|
+
{ value: 'stretch', label: 'Stretch (once, by distance)' },
|
|
426
|
+
{ value: 'distributePerSegment', label: 'Distribute per segment' },
|
|
427
|
+
{ value: 'tile', label: 'Tile (per world unit)' },
|
|
428
|
+
{ value: 'repeatPerSegment', label: 'Repeat per segment' },
|
|
429
|
+
], onChange: (mode) => binding.apply((s) => {
|
|
430
|
+
s.rendererEmitterSettings.textureMode =
|
|
431
|
+
mode === 'stretch' ? undefined : mode;
|
|
432
|
+
}) }) }), _jsx(Row, { label: "Texture scale", children: _jsx(NumberField, { value: system.rendererEmitterSettings.textureScale ?? 1, min: 0.01, step: 0.1, onChange: (v) => binding.apply((s) => {
|
|
433
|
+
s.rendererEmitterSettings.textureScale = v === 1 ? undefined : v;
|
|
434
|
+
}) }) }), _jsx(Row, { label: "Min vertex distance", children: _jsx(NumberField, { value: system.rendererEmitterSettings.minVertexDistance ?? 0, min: 0, step: 0.05, onChange: (v) => binding.apply((s) => {
|
|
435
|
+
s.rendererEmitterSettings.minVertexDistance =
|
|
436
|
+
v > 0 ? v : undefined;
|
|
437
|
+
}) }) }), _jsx(Row, { label: "Trail time", children: _jsx(NumberField, { value: system.rendererEmitterSettings.lifetime ?? 0, min: 0, step: 0.1, onChange: (v) => binding.apply((s) => {
|
|
438
|
+
s.rendererEmitterSettings.lifetime = v > 0 ? v : undefined;
|
|
439
|
+
}) }) }), _jsx(Row, { label: "Swept trail", children: _jsx(CheckboxField, { value: !!system.rendererEmitterSettings.sideAxis, onChange: (v) => binding.apply((s) => {
|
|
440
|
+
s.rendererEmitterSettings.sideAxis = v
|
|
441
|
+
? new Vector3(0, 1, 0)
|
|
442
|
+
: undefined;
|
|
443
|
+
}) }) }), system.rendererEmitterSettings.sideAxis && (_jsx(Row, { label: "Side axis", children: _jsx(AxisField, { value: system.rendererEmitterSettings.sideAxis, onChange: (axis) => binding.apply((s) => {
|
|
444
|
+
// The axis's length scales the width: keep it a unit vector.
|
|
445
|
+
s.rendererEmitterSettings.sideAxis =
|
|
446
|
+
axis.length() > 0 ? axis.normalize() : axis;
|
|
447
|
+
}) }) }))] })), system.renderMode === RenderMode.StretchedBillBoard && (_jsxs(_Fragment, { children: [_jsx(Row, { label: "Speed factor", children: _jsx(NumberField, { value: system.rendererEmitterSettings.speedFactor ?? 0, step: 0.1, onChange: (v) => binding.apply((s) => (s.rendererEmitterSettings.speedFactor = v)) }) }), _jsx(Row, { label: "Length factor", children: _jsx(NumberField, { value: system.rendererEmitterSettings.lengthFactor ?? 2, step: 0.1, onChange: (v) => binding.apply((s) => (s.rendererEmitterSettings.lengthFactor = v)) }) })] })), _jsx(SubHeader, { title: "Material", hint: "Shader and blending settings applied to the particle sprite or mesh." }), materialLabel ? (_jsx(Row, { label: "Source", children: _jsx("div", { style: { fontSize: 12, color: theme.textDim, lineHeight: 1.45 }, children: materialLabel }) })) : null, _jsx(Row, { label: "Blend mode", children: _jsx(SelectField, { value: system.blending, options: [
|
|
403
448
|
{ value: 1, label: 'Additive' },
|
|
404
449
|
{ value: 2, label: 'Alpha blend' },
|
|
405
450
|
{ value: 3, label: 'Subtract' },
|
|
406
451
|
{ value: 4, label: 'Multiply' },
|
|
407
|
-
], onChange: (blend) => patchMaterial({ blendMode: blend }) }) }), _jsx(Row, { label: "Transparent", children: _jsx(CheckboxField, { value: !!system.getRendererSettings().materialTransparent, onChange: (v) => patchMaterial({ transparent: v }) }) }),
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
423
|
-
if (url === '__none') {
|
|
424
|
-
patchMaterial({ texture: null });
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
if (url === '__url') {
|
|
428
|
-
setPromptingTextureUrl(true);
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
if (url === '__file') {
|
|
432
|
-
const input = document.createElement('input');
|
|
433
|
-
input.type = 'file';
|
|
434
|
-
input.accept = 'image/*';
|
|
435
|
-
input.onchange = () => {
|
|
436
|
-
const file = input.files?.[0];
|
|
437
|
-
if (!file) {
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
const reader = new FileReader();
|
|
441
|
-
reader.onload = () => {
|
|
442
|
-
const texture = loadTexture(reader.result);
|
|
443
|
-
if (texture) {
|
|
444
|
-
patchMaterial({ texture });
|
|
445
|
-
}
|
|
446
|
-
};
|
|
447
|
-
reader.readAsDataURL(file);
|
|
448
|
-
};
|
|
449
|
-
input.click();
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
const texture = loadTexture(url);
|
|
453
|
-
if (texture) {
|
|
454
|
-
patchMaterial({ texture });
|
|
455
|
-
}
|
|
456
|
-
} }), promptingTextureUrl && (_jsx(PromptDialog, { title: "Texture URL", defaultValue: currentTextureUrl, placeholder: "https://\u2026", onSubmit: (url) => {
|
|
457
|
-
const texture = loadTexture(url);
|
|
458
|
-
if (texture) {
|
|
459
|
-
patchMaterial({ texture });
|
|
460
|
-
}
|
|
461
|
-
setPromptingTextureUrl(false);
|
|
462
|
-
}, onCancel: () => setPromptingTextureUrl(false) })), currentTextureUrl && (_jsx("img", { src: currentTextureUrl, alt: "texture preview", style: {
|
|
463
|
-
width: 64,
|
|
464
|
-
height: 64,
|
|
465
|
-
marginTop: 6,
|
|
466
|
-
objectFit: 'contain',
|
|
467
|
-
borderRadius: 6,
|
|
468
|
-
border: '1px solid #2b3761',
|
|
469
|
-
background: 'repeating-conic-gradient(#2a3252 0% 25%, #171d33 0% 50%) 0 0 / 12px 12px',
|
|
470
|
-
} }))] }), _jsx(Row, { label: "Alpha test", children: _jsx(NumberField, { value: system.getRendererSettings().materialAlphaTest ?? 0, min: 0, step: 0.05, onChange: (v) => patchMaterial({ alphaTest: Math.min(1, v) }) }) }), _jsx(Row, { label: "Depth write", children: _jsx(CheckboxField, { value: system.getRendererSettings().materialDepthWrite, onChange: (v) => patchMaterial({ depthWrite: v }) }) }), _jsx(Row, { label: "Depth test", children: _jsx(CheckboxField, { value: system.getRendererSettings().materialDepthTest, onChange: (v) => patchMaterial({ depthTest: v }) }) }), system.renderMode === RenderMode.Mesh &&
|
|
452
|
+
], onChange: (blend) => patchMaterial({ blendMode: blend }) }) }), _jsx(Row, { label: "Transparent", children: _jsx(CheckboxField, { value: !!system.getRendererSettings().materialTransparent, onChange: (v) => patchMaterial({ transparent: v }) }) }), _jsx(Row, { label: "Texture", children: _jsx(TextureSelect, { value: system.texture, textureOptions: textureOptions, loadTexture: loadTexture, onChange: (texture) => patchMaterial({ texture }), preview: true }) }), _jsx(TextureUVField, { labelPrefix: "Map ", value: system.mapUV ?? normalizeTextureUV(undefined), onChange: (uv) => binding.apply((s) => (s.mapUV = uv)) }), !isMesh && (_jsx(Row, { label: "Flip U/V", children: _jsx("div", { style: { display: 'flex', gap: 6 }, children: ['x', 'y'].map((axis) => (_jsx(NumberField, { value: system.flip?.[axis] ?? 0, min: 0, max: 1, step: 0.1, onChange: (v) => binding.apply((s) => {
|
|
453
|
+
const next = s.flip?.clone() ?? new Vector2(0, 0);
|
|
454
|
+
next[axis] = Math.min(1, Math.max(0, v));
|
|
455
|
+
s.flip = next.x === 0 && next.y === 0 ? undefined : next;
|
|
456
|
+
}) }, axis))) }) })), _jsx(Row, { label: "Alpha test", children: _jsx(NumberField, { value: system.getRendererSettings().materialAlphaTest ?? 0, min: 0, step: 0.05, onChange: (v) => patchMaterial({ alphaTest: Math.min(1, v) }) }) }), _jsx(Row, { label: "Depth write", children: _jsx(CheckboxField, { value: system.getRendererSettings().materialDepthWrite, onChange: (v) => patchMaterial({ depthWrite: v }) }) }), _jsx(Row, { label: "Depth test", children: _jsx(CheckboxField, { value: system.getRendererSettings().materialDepthTest, onChange: (v) => patchMaterial({ depthTest: v }) }) }), _jsx(SubHeader, { title: "Gradient map", hint: "Recolours the map through a colour ramp: one channel of the map, or its luminance, picks a colour along the ramp." }), _jsx(Row, { label: "Ramp", children: _jsx(TextureSelect, { value: gradientMap?.ramp, textureOptions: textureOptions, loadTexture: loadTexture, promptTitle: "Ramp texture URL", onChange: (ramp) => binding.apply((s) => (s.gradientMap = ramp ? { ...s.gradientMap, ramp } : undefined)) }) }), gradientMap && (_jsx(Row, { label: "Ramp channel", children: _jsx(SelectField, { value: gradientMap.channel, options: [
|
|
457
|
+
{ value: 'r', label: 'Red' },
|
|
458
|
+
{ value: 'g', label: 'Green' },
|
|
459
|
+
{ value: 'b', label: 'Blue' },
|
|
460
|
+
{ value: 'a', label: 'Alpha (ramp alpha replaces)' },
|
|
461
|
+
{ value: 'luminance', label: 'Luminance' },
|
|
462
|
+
], onChange: (channel) => binding.apply((s) => (s.gradientMap = { ...s.gradientMap, channel })) }) })), _jsx(SubHeader, { title: "Erosion", hint: "Alpha decides how much of the shape is left instead of how transparent it is, so a fading alpha dissolves or wipes the shape away." }), _jsx(Row, { label: "Erosion", children: _jsx(CheckboxField, { value: !!erosion, onChange: (v) => binding.apply((s) => (s.erosion = v ? {} : undefined)) }) }), erosion && (_jsxs(_Fragment, { children: [_jsx(Row, { label: "Erosion mask", children: _jsx(TextureSelect, { value: erosion.mask, textureOptions: textureOptions, loadTexture: loadTexture, noneLabel: "(map alpha)", promptTitle: "Erosion mask URL", onChange: (mask) => patchErosion({ mask }) }) }), erosion.mask && (_jsx(TextureUVField, { labelPrefix: "Mask ", value: erosion.maskUV, onChange: (maskUV) => patchErosion({ maskUV }) })), _jsx(Row, { label: "Softness", children: _jsx(NumberField, { value: erosion.softness, min: 0.0001, step: 0.01, onChange: (softness) => patchErosion({ softness }) }) }), _jsx(Row, { label: "Edge width", children: _jsx(NumberField, { value: erosion.edgeWidth, min: 0, step: 0.01, onChange: (edgeWidth) => patchErosion({ edgeWidth }) }) }), (erosion.edgeWidth > 0 || erosion.edgeColor.some((c) => c !== 1)) && (_jsx(Row, { label: "Edge color", children: _jsx("div", { style: { display: 'flex', gap: 6 }, children: [0, 1, 2].map((channel) => (_jsx(NumberField, { value: erosion.edgeColor[channel], min: 0, step: 0.05, onChange: (v) => {
|
|
463
|
+
const edgeColor = [...erosion.edgeColor];
|
|
464
|
+
edgeColor[channel] = v;
|
|
465
|
+
patchErosion({ edgeColor });
|
|
466
|
+
} }, channel))) }) }))] })), _jsx(SubHeader, { title: "UV distortion", hint: "A scrolling noise texture pushes the map's UV about, for heat shimmer and licking, breathing shapes." }), _jsx(Row, { label: "Noise texture", children: _jsx(TextureSelect, { value: distortion?.map, textureOptions: textureOptions, loadTexture: loadTexture, promptTitle: "Distortion noise URL", onChange: (map) => binding.apply((s) => (s.uvDistortion = map ? { ...s.uvDistortion, map } : undefined)) }) }), distortion && (_jsxs(_Fragment, { children: [_jsx(Row, { label: "Distortion strength", children: _jsx(NumberField, { value: distortion.strength, min: 0, step: 0.01, onChange: (strength) => patchDistortion({ strength }) }) }), _jsx(TextureUVField, { labelPrefix: "Noise ", value: distortion.mapUV, onChange: (mapUV) => patchDistortion({ mapUV }) })] })), system.renderMode === RenderMode.Mesh &&
|
|
471
467
|
(() => {
|
|
472
468
|
const preset = detectGeometryPreset(system.instancingGeometry);
|
|
473
469
|
const vertexCount = system.instancingGeometry.length / 3;
|
|
@@ -475,10 +471,12 @@ export function RendererModule({ binding, textureOptions, geometryOptions, resol
|
|
|
475
471
|
const hostGeometry = geometryOptions ?? [];
|
|
476
472
|
const applyGeometry = (g) => binding.apply((s) => {
|
|
477
473
|
const settings = s.getRendererSettings();
|
|
474
|
+
// Positions first: the setter keeps or drops the other sets by vertex count.
|
|
475
|
+
s.instancingGeometry = new Float32Array(g.positions);
|
|
478
476
|
settings.instancingIndices = (g.indices ? new Uint32Array(g.indices) : undefined);
|
|
479
477
|
settings.instancingUVs = (g.uvs ? new Float32Array(g.uvs) : undefined);
|
|
478
|
+
settings.instancingUVs2 = (g.uvs2 ? new Float32Array(g.uvs2) : undefined);
|
|
480
479
|
settings.instancingNormals = (g.normals ? new Float32Array(g.normals) : undefined);
|
|
481
|
-
s.instancingGeometry = new Float32Array(g.positions);
|
|
482
480
|
});
|
|
483
481
|
return (_jsx(Row, { label: "Geometry", children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 6 }, children: [_jsx(SelectField, { value: preset, options: [
|
|
484
482
|
...(preset === 'custom' ? [{ value: 'custom', label: 'Custom (imported)' }] : []),
|
|
@@ -509,6 +507,7 @@ export function RendererModule({ binding, textureOptions, geometryOptions, resol
|
|
|
509
507
|
}
|
|
510
508
|
binding.apply((s) => {
|
|
511
509
|
const settings = s.getRendererSettings();
|
|
510
|
+
settings.instancingUVs2 = undefined;
|
|
512
511
|
if (next === 'cube') {
|
|
513
512
|
settings.instancingIndices = MESH_CUBE_INDICES;
|
|
514
513
|
settings.instancingUVs = undefined;
|
|
@@ -521,7 +520,7 @@ export function RendererModule({ binding, textureOptions, geometryOptions, resol
|
|
|
521
520
|
s.instancingGeometry = MESH_QUAD_POSITIONS;
|
|
522
521
|
}
|
|
523
522
|
});
|
|
524
|
-
} }), _jsx(MeshPreview, { positions: system.instancingGeometry, indices: system.getRendererSettings().instancingIndices }), preset === 'custom' && (_jsxs("span", { style: { fontSize: 10.5, color: '#9eb9ff' }, children: [vertexCount, " verts / ", triangleCount, " tris \u2014 picking a preset replaces this mesh"] }))] }) }));
|
|
523
|
+
} }), _jsx(MeshPreview, { positions: system.instancingGeometry, indices: system.getRendererSettings().instancingIndices }), preset === 'custom' && (_jsxs("span", { style: { fontSize: 10.5, color: '#9eb9ff' }, children: [vertexCount, " verts / ", triangleCount, " tris", system.getRendererSettings().instancingUVs2 ? ' / 2 UV sets' : '', " \u2014 picking a preset replaces this mesh"] }))] }) }));
|
|
525
524
|
})(), system.renderMode === RenderMode.Mesh && (_jsx(Row, { label: "Lighting", children: _jsx(SelectField, { value: system.lighting, options: [
|
|
526
525
|
{ value: 'fixed', label: 'Fixed light' },
|
|
527
526
|
{ value: 'scene', label: 'Scene light' },
|
|
@@ -539,6 +538,7 @@ export function RendererModule({ binding, textureOptions, geometryOptions, resol
|
|
|
539
538
|
return (_jsxs(_Fragment, { children: [_jsx(Row, { label: "Rim mode", children: _jsx(SelectField, { value: rim.mode, options: [
|
|
540
539
|
{ value: 'add', label: 'Add (glow)' },
|
|
541
540
|
{ value: 'mix', label: 'Mix (outline)' },
|
|
541
|
+
{ value: 'fade', label: 'Fade (faces fade, edges stay)' },
|
|
542
542
|
], onChange: (mode) => patchRim({ mode }) }) }), _jsx(Row, { label: "Rim color", children: _jsx("div", { style: { display: 'flex', gap: 6 }, children: [0, 1, 2].map((channel) => (_jsx(NumberField, { value: rim.color[channel], min: 0, step: 0.05, onChange: (v) => setChannel(channel, v) }, channel))) }) }), _jsx(Row, { label: "Rim power", children: _jsx(NumberField, { value: rim.power, min: 0.01, step: 0.25, onChange: (power) => patchRim({ power }) }) }), _jsx(Row, { label: "Rim strength", children: _jsx(NumberField, { value: rim.strength, min: 0, step: 0.05, onChange: (strength) => patchRim({ strength }) }) })] }));
|
|
543
543
|
})(), _jsx(Row, { label: "Render order", children: _jsx(NumberField, { value: system.renderOrder, step: 1, onChange: (v) => binding.apply((s) => (s.renderOrder = Math.round(v))) }) }), _jsx(Row, { label: "Rendering group", children: _jsx(NumberField, { value: system.renderingGroupId, step: 1, min: 0, onChange: (v) => binding.apply((s) => (s.renderingGroupId = Math.max(0, Math.round(v)))) }) }), _jsx(Row, { label: "Layer mask", children: _jsx(NumberField, { value: system.layers.mask, min: 0, step: 1, onChange: (v) => binding.apply((s) => (s.layers.mask = Math.max(0, Math.floor(v)))) }) }), _jsxs(Row, { label: "Max particles", children: [_jsx(CheckboxField, { value: system.maxParticles !== undefined, onChange: (v) => binding.apply((s) => (s.maxParticles = v ? 1000 : undefined)) }), system.maxParticles !== undefined && (_jsx(NumberField, { value: system.maxParticles, min: 1, step: 10, onChange: (v) => binding.apply((s) => (s.maxParticles = Math.max(1, Math.floor(v)))) }))] }), system.renderMode !== RenderMode.Mesh && system.renderMode !== RenderMode.Trail && (_jsx(Row, { label: "Pivot", children: _jsx("div", { style: { display: 'flex', gap: 6 }, children: ['x', 'y', 'z'].map((axis) => (_jsx(NumberField, { value: system.pivot?.[axis] ?? 0, step: 0.05, onChange: (v) => binding.apply((s) => {
|
|
544
544
|
const next = (s.pivot ?? new Vector3()).clone();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "babylon.quarks-editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Shuriken-style effect editor for babylon.quarks: headless edit-model core + React module-stack UI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"@babylonjs/materials": ">=9.0.0",
|
|
56
56
|
"@heroicons/react": ">=2.0.0",
|
|
57
57
|
"@tanstack/react-virtual": ">=3.0.0",
|
|
58
|
-
"babylon.quarks": "
|
|
58
|
+
"babylon.quarks": "~0.27.0",
|
|
59
59
|
"react": ">=18",
|
|
60
60
|
"react-dom": ">=18"
|
|
61
61
|
},
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"@tanstack/react-virtual": "^3.14.6",
|
|
66
66
|
"@types/react": "^19.0.0",
|
|
67
67
|
"@types/react-dom": "^19.0.0",
|
|
68
|
+
"fake-indexeddb": "^6.2.6",
|
|
68
69
|
"react": "^19.0.0",
|
|
69
70
|
"react-dom": "^19.0.0",
|
|
70
71
|
"rimraf": "^6.0.0",
|
package/src/core/assetTree.ts
CHANGED
package/src/core/binding.ts
CHANGED
|
@@ -1,7 +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';
|
|
4
|
-
import {buildEffectTree, serializeEffectTree} from './effectTree';
|
|
3
|
+
import type {EffectTreeNode} from './effectTree.js';
|
|
4
|
+
import {buildEffectTree, serializeEffectTree} from './effectTree.js';
|
|
5
5
|
|
|
6
6
|
export type EditorListener = () => void;
|
|
7
7
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {TransformNode} from '@babylonjs/core/Meshes/transformNode';
|
|
2
|
-
import type {Scene} from '@babylonjs/core/scene';
|
|
1
|
+
import {TransformNode} from '@babylonjs/core/Meshes/transformNode.js';
|
|
2
|
+
import type {Scene} from '@babylonjs/core/scene.js';
|
|
3
3
|
import {
|
|
4
4
|
ColorOverLife,
|
|
5
5
|
ConeEmitter,
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
RenderMode,
|
|
11
11
|
Vector4,
|
|
12
12
|
} from 'babylon.quarks';
|
|
13
|
-
import {DEFAULT_GRADIENT_STOPS, buildGradient} from './colors';
|
|
14
|
-
import {uniqueEntryName, type SceneEntry} from './sceneEntries';
|
|
13
|
+
import {DEFAULT_GRADIENT_STOPS, buildGradient} from './colors.js';
|
|
14
|
+
import {uniqueEntryName, type SceneEntry} from './sceneEntries.js';
|
|
15
15
|
|
|
16
16
|
export interface CreateSceneDefaultOptions {
|
|
17
17
|
resolveTexture?: (url: string, scene: Scene) => unknown;
|
package/src/core/editorScene.ts
CHANGED
|
@@ -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
|
|
|
3
3
|
/** Marks meshes/nodes created only for editor interaction or overlays (not part of the effect). */
|
|
4
4
|
export const EDITOR_SCENE_NODE_METADATA = {quarksEditorSceneNode: true as const};
|