babylon.quarks-editor 0.27.0 → 0.29.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 +92 -0
- package/README.md +31 -4
- package/dist/core/assetTree.d.ts +5 -0
- package/dist/core/assets.d.ts +7 -0
- package/dist/core/assets.js +11 -7
- package/dist/core/binding.d.ts +9 -0
- package/dist/core/binding.js +8 -0
- 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 +3 -2
- package/dist/core/defaultEffect.js +3 -1
- package/dist/core/editorSession.d.ts +229 -0
- package/dist/core/editorSession.js +983 -0
- package/dist/core/effectTree.d.ts +5 -0
- package/dist/core/emitterShapeWireframe.js +11 -4
- package/dist/core/galleryPlayback.js +2 -1
- package/dist/core/history.d.ts +6 -0
- package/dist/core/history.js +4 -0
- package/dist/core/indexedDbProjectStore.d.ts +13 -0
- package/dist/core/indexedDbProjectStore.js +13 -0
- package/dist/core/loadEffect.js +2 -0
- package/dist/core/material.d.ts +12 -2
- 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 +3 -0
- package/dist/core/scrub.d.ts +1 -1
- package/dist/core/scrub.js +2 -2
- package/dist/core/shapes.d.ts +31 -1
- package/dist/core/shapes.js +18 -3
- package/dist/core/systems.d.ts +2 -0
- package/dist/core/systems.js +5 -1
- package/dist/core/timeline.d.ts +23 -3
- package/dist/core/values.d.ts +42 -8
- package/dist/core/values.js +52 -9
- package/dist/index.d.ts +5 -1
- package/dist/react/AssetsPanel.d.ts +7 -0
- package/dist/react/AxesCurveField.d.ts +21 -0
- package/dist/react/AxesCurveField.js +25 -0
- package/dist/react/ChoiceDialog.d.ts +7 -0
- package/dist/react/ContextMenu.d.ts +10 -1
- package/dist/react/EditorWorkspace.d.ts +7 -0
- package/dist/react/EditorWorkspace.js +6 -3
- package/dist/react/EffectEditor.d.ts +8 -2
- package/dist/react/EffectEditorHost.d.ts +32 -28
- package/dist/react/EffectEditorHost.js +241 -1665
- package/dist/react/EffectTreeView.d.ts +3 -0
- package/dist/react/LifeCurveField.d.ts +18 -0
- package/dist/react/LifeCurveField.js +26 -0
- package/dist/react/MessageDialog.d.ts +5 -0
- package/dist/react/ModuleSection.d.ts +10 -0
- package/dist/react/ModuleSection.js +4 -1
- package/dist/react/ProjectsPage.d.ts +6 -0
- package/dist/react/ProjectsPage.js +27 -11
- package/dist/react/PromptDialog.d.ts +7 -0
- package/dist/react/ScenePanel.d.ts +7 -0
- package/dist/react/ScenePanel.js +7 -5
- package/dist/react/TextureSelect.d.ts +5 -5
- package/dist/react/TimelinePanel.d.ts +13 -0
- package/dist/react/TimelinePanel.js +10 -6
- package/dist/react/TimelineTrackRow.d.ts +10 -0
- package/dist/react/TransportBar.d.ts +9 -0
- package/dist/react/ValueField.d.ts +33 -5
- package/dist/react/ValueField.js +34 -9
- package/dist/react/behaviorModules.d.ts +16 -5
- package/dist/react/behaviorModules.js +28 -9
- package/dist/react/fields.d.ts +8 -0
- package/dist/react/fields.js +3 -0
- 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 +3 -1
- package/dist/react/inspectorHints.js +1 -1
- package/dist/react/modules.d.ts +17 -6
- package/dist/react/modules.js +77 -34
- 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 +17 -11
- package/src/core/assetTree.ts +14 -1
- package/src/core/assets.ts +25 -10
- package/src/core/binding.ts +9 -0
- package/src/core/collision.ts +4 -0
- package/src/core/colors.ts +21 -1
- package/src/core/defaultEffect.ts +6 -3
- package/src/core/editorSession.ts +1299 -0
- package/src/core/effectTree.ts +5 -0
- package/src/core/emitterShapeWireframe.ts +12 -4
- package/src/core/galleryPlayback.ts +2 -1
- package/src/core/history.ts +6 -0
- package/src/core/indexedDbProjectStore.ts +13 -0
- package/src/core/loadEffect.ts +3 -1
- package/src/core/material.ts +14 -4
- package/src/core/playback.ts +6 -0
- package/src/core/projectStore.ts +26 -0
- package/src/core/sceneEntries.ts +3 -0
- package/src/core/scrub.ts +2 -2
- package/src/core/shapes.ts +48 -3
- package/src/core/systems.ts +11 -2
- package/src/core/timeline.ts +40 -15
- package/src/core/values.ts +91 -14
- package/src/index.ts +5 -1
- package/src/react/AssetsPanel.tsx +7 -0
- package/src/react/AxesCurveField.tsx +72 -0
- package/src/react/ChoiceDialog.tsx +7 -0
- package/src/react/ContextMenu.tsx +10 -1
- package/src/react/EditorWorkspace.tsx +11 -5
- package/src/react/EffectEditor.tsx +7 -1
- package/src/react/EffectEditorHost.tsx +406 -2340
- package/src/react/EffectTreeView.tsx +3 -0
- package/src/react/LifeCurveField.tsx +57 -0
- package/src/react/MessageDialog.tsx +5 -0
- package/src/react/ModuleSection.tsx +11 -0
- package/src/react/ProjectsPage.tsx +38 -11
- package/src/react/PromptDialog.tsx +7 -0
- package/src/react/ScenePanel.tsx +14 -5
- package/src/react/TextureSelect.tsx +6 -6
- package/src/react/TimelinePanel.tsx +23 -6
- package/src/react/TimelineTrackRow.tsx +10 -0
- package/src/react/TransportBar.tsx +9 -0
- package/src/react/ValueField.tsx +99 -15
- package/src/react/behaviorModules.tsx +58 -42
- package/src/react/fields.tsx +12 -1
- 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 +3 -1
- package/src/react/inspectorHints.ts +1 -1
- package/src/react/modules.tsx +192 -71
- package/src/react/theme.ts +15 -0
- package/src/session.ts +17 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ArrowLeftIcon } from '@heroicons/react/24/solid';
|
|
3
|
+
import { EffectTreeView } from '../EffectTreeView.js';
|
|
4
|
+
import { iconStyle } from '../icons.js';
|
|
5
|
+
import { ScenePanel } from '../ScenePanel.js';
|
|
6
|
+
import { buttonStyle, theme } from '../theme.js';
|
|
7
|
+
import { dockIconButtonStyle, saveButtonStyle, SCENE_PANEL_WIDTH } from './hostStyles.js';
|
|
8
|
+
/** The editor's left column: the project header, then the Scene list or the open prefab. */
|
|
9
|
+
export function SceneSidebar(props) {
|
|
10
|
+
const { prefabInfo, prefabDirty, entries } = props;
|
|
11
|
+
return (_jsxs("aside", { style: {
|
|
12
|
+
width: SCENE_PANEL_WIDTH,
|
|
13
|
+
flexShrink: 0,
|
|
14
|
+
borderRight: `1px solid ${theme.border}`,
|
|
15
|
+
background: theme.panelBg,
|
|
16
|
+
display: 'flex',
|
|
17
|
+
flexDirection: 'column',
|
|
18
|
+
minHeight: 0,
|
|
19
|
+
}, children: [props.projectName !== undefined && (_jsxs("div", { style: {
|
|
20
|
+
display: 'flex',
|
|
21
|
+
alignItems: 'center',
|
|
22
|
+
gap: 6,
|
|
23
|
+
padding: '8px 10px',
|
|
24
|
+
borderBottom: `1px solid ${theme.border}`,
|
|
25
|
+
}, children: [props.canExitProject && (_jsx("button", { type: "button", className: "qe-hover", title: "Back to projects", style: { ...dockIconButtonStyle, width: 26, height: 26 }, onClick: props.onExitProject, children: _jsx(ArrowLeftIcon, { style: iconStyle(13) }) })), _jsxs("span", { title: props.projectName, style: {
|
|
26
|
+
flex: 1,
|
|
27
|
+
minWidth: 0,
|
|
28
|
+
fontSize: 13,
|
|
29
|
+
fontWeight: 600,
|
|
30
|
+
overflow: 'hidden',
|
|
31
|
+
textOverflow: 'ellipsis',
|
|
32
|
+
whiteSpace: 'nowrap',
|
|
33
|
+
}, children: [props.projectName, props.sceneDirty ? ' *' : ''] }), _jsx("button", { type: "button", className: "qe-hover", title: "Save the scene (Ctrl+S) \u2014 assets are not changed", disabled: props.projectLoading, style: saveButtonStyle(props.sceneDirty, '4px 12px'), onClick: props.onSave, children: "Save" })] })), _jsxs("div", { style: { padding: '12px 14px 10px', borderBottom: `1px solid ${theme.border}` }, children: [_jsx("div", { style: { fontSize: 14, fontWeight: 600 }, children: prefabInfo ? 'Prefab' : `Scene${entries.length > 0 ? ` · ${entries.length}` : ''}` }), _jsx("div", { style: { fontSize: 11, color: theme.textDim, marginTop: 4, lineHeight: 1.4 }, children: prefabInfo
|
|
34
|
+
? 'The scene is set aside while you edit this asset'
|
|
35
|
+
: 'Effects in the viewport · click to edit · eye shows/hides' })] }), _jsx("div", { style: {
|
|
36
|
+
flex: 1,
|
|
37
|
+
minHeight: 0,
|
|
38
|
+
overflow: 'hidden',
|
|
39
|
+
padding: '8px 12px 14px',
|
|
40
|
+
display: 'flex',
|
|
41
|
+
flexDirection: 'column',
|
|
42
|
+
}, children: prefabInfo ? (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 10, flex: 1, minHeight: 0 }, children: [_jsxs("div", { style: {
|
|
43
|
+
display: 'flex',
|
|
44
|
+
flexDirection: 'column',
|
|
45
|
+
gap: 10,
|
|
46
|
+
padding: 12,
|
|
47
|
+
border: `1px solid ${theme.borderActive}`,
|
|
48
|
+
borderRadius: 8,
|
|
49
|
+
background: 'rgba(120, 165, 255, 0.08)',
|
|
50
|
+
fontSize: 12,
|
|
51
|
+
color: theme.textDim,
|
|
52
|
+
lineHeight: 1.5,
|
|
53
|
+
}, children: [_jsxs("div", { style: { fontSize: 13, fontWeight: 600, color: theme.text }, children: [prefabInfo.name, prefabDirty ? ' *' : ''] }), _jsx("div", { style: { wordBreak: 'break-all' }, children: prefabInfo.path }), _jsx("div", { children: "Save (Ctrl+S) overwrites this asset. Effects already placed in the scene keep their own copy and do not change." }), _jsxs("div", { style: { display: 'flex', gap: 6 }, children: [_jsx("button", { type: "button", className: "qe-hover", style: buttonStyle, onClick: props.onExitPrefab, children: "\u2190 Scene" }), _jsx("button", { type: "button", className: "qe-hover", style: buttonStyle, onClick: props.onSavePrefab, children: "Save prefab" })] })] }), entries[0] && (_jsx("div", { style: {
|
|
54
|
+
flex: 1,
|
|
55
|
+
minHeight: 0,
|
|
56
|
+
overflowY: 'auto',
|
|
57
|
+
border: `1px solid ${theme.border}`,
|
|
58
|
+
borderRadius: 8,
|
|
59
|
+
background: theme.sectionBg,
|
|
60
|
+
padding: '4px 0',
|
|
61
|
+
}, children: _jsx(EffectTreeView, { includeRoot: true, root: entries[0].root, selectedNode: props.selectedNode, onSelect: (node) => props.onSelectNode(null, node) }) }))] })) : (_jsx(ScenePanel, { entries: entries, focusedRoot: props.focusedRoot, visibleRootIds: props.visibleRootIds, onFocus: props.onFocus, onToggleVisible: props.onToggleVisible, soloRootId: props.soloRootId, onToggleSolo: props.onToggleSolo, onSaveAsAsset: props.onSaveAsAsset, onDelete: props.onDelete, onCreateDefault: props.onCreateDefault, selectedNode: props.selectedNode, onSelectNode: props.onSelectNode })) })] }));
|
|
62
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AssetLoadProgress } from '../../core/assets.js';
|
|
3
|
+
import type { PrefabInfo } from '../../core/editorSession.js';
|
|
4
|
+
/** What the stage gizmo does: nothing, or move, rotate or scale the selected node. */
|
|
5
|
+
export type GizmoMode = 'none' | 'position' | 'rotation' | 'scale';
|
|
6
|
+
/** Props of {@link ViewportPane}. */
|
|
7
|
+
export interface ViewportPaneProps {
|
|
8
|
+
/** The canvas the engine draws into. */
|
|
9
|
+
canvasRef: React.RefObject<HTMLCanvasElement | null>;
|
|
10
|
+
/** The render loop writes the frame rate here. */
|
|
11
|
+
fpsRef: React.RefObject<HTMLSpanElement | null>;
|
|
12
|
+
/** Pixels at the bottom covered by the floating Assets drawer. */
|
|
13
|
+
inset: number;
|
|
14
|
+
/** The transport bar, once the scene exists. */
|
|
15
|
+
transport: React.ReactNode;
|
|
16
|
+
/** The asset drag hovering the viewport, if any. */
|
|
17
|
+
dragHover: {
|
|
18
|
+
label: string;
|
|
19
|
+
count: number;
|
|
20
|
+
} | null;
|
|
21
|
+
/** Asset import progress, while importing. */
|
|
22
|
+
assetsLoading: AssetLoadProgress | null;
|
|
23
|
+
/** The open prefab, if any. */
|
|
24
|
+
prefabInfo: PrefabInfo | null;
|
|
25
|
+
/** The open prefab has unsaved edits. */
|
|
26
|
+
prefabDirty: boolean;
|
|
27
|
+
/** Link shown in the top-left corner, outside prefab mode. */
|
|
28
|
+
backLink?: {
|
|
29
|
+
href: string;
|
|
30
|
+
label: string;
|
|
31
|
+
};
|
|
32
|
+
/** Undo is possible. */
|
|
33
|
+
canUndo: boolean;
|
|
34
|
+
/** Redo is possible. */
|
|
35
|
+
canRedo: boolean;
|
|
36
|
+
/** An effect is focused. */
|
|
37
|
+
hasFocus: boolean;
|
|
38
|
+
/** The stage gizmo's mode. */
|
|
39
|
+
gizmoMode: GizmoMode;
|
|
40
|
+
/** Emitter shape wireframes are shown. */
|
|
41
|
+
showWireframes: boolean;
|
|
42
|
+
/** Drag handlers of the viewport, for assets dropped from the drawer. */
|
|
43
|
+
dragHandlers: Pick<React.HTMLAttributes<HTMLDivElement>, 'onDragEnter' | 'onDragLeave' | 'onDragOver' | 'onDrop'>;
|
|
44
|
+
/** Undo (`false`) or redo. */
|
|
45
|
+
onHistoryStep(redo: boolean): void;
|
|
46
|
+
/** Pick the stage gizmo's mode. */
|
|
47
|
+
onGizmoMode(mode: GizmoMode): void;
|
|
48
|
+
/** Show or hide the emitter wireframes. */
|
|
49
|
+
onToggleWireframes(): void;
|
|
50
|
+
/** Back from the prefab to the scene. */
|
|
51
|
+
onExitPrefab(): void;
|
|
52
|
+
/** Save the open prefab. */
|
|
53
|
+
onSavePrefab(): void;
|
|
54
|
+
}
|
|
55
|
+
/** The 3D viewport and what floats over it: toolbars, transport, drag and import feedback. */
|
|
56
|
+
export declare function ViewportPane({ canvasRef, fpsRef, inset, transport, dragHover, assetsLoading, prefabInfo, prefabDirty, backLink, canUndo, canRedo, hasFocus, gizmoMode, showWireframes, dragHandlers, onHistoryStep, onGizmoMode, onToggleWireframes, onExitPrefab, onSavePrefab, }: ViewportPaneProps): React.ReactElement;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ArrowLeftIcon, ArrowPathIcon, ArrowsPointingOutIcon, ArrowUturnLeftIcon, ArrowUturnRightIcon, CubeTransparentIcon, CursorArrowRaysIcon, Square2StackIcon, } from '@heroicons/react/24/solid';
|
|
3
|
+
import { iconStyle } from '../icons.js';
|
|
4
|
+
import { buttonStyle, theme } from '../theme.js';
|
|
5
|
+
import { activeSquareButtonStyle, floatingPanelStyle, saveButtonStyle, squareButtonStyle } from './hostStyles.js';
|
|
6
|
+
const GIZMO_MODE_BUTTONS = [
|
|
7
|
+
{ value: 'none', Icon: CursorArrowRaysIcon, title: 'Select (hide stage gizmo)' },
|
|
8
|
+
{ value: 'position', Icon: ArrowsPointingOutIcon, title: 'Move the stage node (position)' },
|
|
9
|
+
{ value: 'rotation', Icon: ArrowPathIcon, title: 'Rotate the stage node' },
|
|
10
|
+
{ value: 'scale', Icon: Square2StackIcon, title: 'Scale the stage node' },
|
|
11
|
+
];
|
|
12
|
+
/** The 3D viewport and what floats over it: toolbars, transport, drag and import feedback. */
|
|
13
|
+
export function ViewportPane({ canvasRef, fpsRef, inset, transport, dragHover, assetsLoading, prefabInfo, prefabDirty, backLink, canUndo, canRedo, hasFocus, gizmoMode, showWireframes, dragHandlers, onHistoryStep, onGizmoMode, onToggleWireframes, onExitPrefab, onSavePrefab, }) {
|
|
14
|
+
return (_jsxs("div", { style: { position: 'relative', flex: 1, minWidth: 0 }, ...dragHandlers, children: [_jsx("canvas", { ref: canvasRef, style: { width: '100%', height: '100%', display: 'block', touchAction: 'none', outline: 'none' } }), _jsx("div", { style: {
|
|
15
|
+
...floatingPanelStyle,
|
|
16
|
+
position: 'absolute',
|
|
17
|
+
bottom: 12 + inset,
|
|
18
|
+
left: 12,
|
|
19
|
+
padding: '4px 10px',
|
|
20
|
+
fontSize: 12,
|
|
21
|
+
color: theme.textDim,
|
|
22
|
+
fontVariantNumeric: 'tabular-nums',
|
|
23
|
+
pointerEvents: 'none',
|
|
24
|
+
fontFamily: theme.font,
|
|
25
|
+
}, children: _jsx("span", { ref: fpsRef, children: "\u2014 FPS" }) }), transport && (_jsx("div", { style: { position: 'absolute', bottom: 12 + inset, left: '50%', transform: 'translateX(-50%)' }, children: transport })), dragHover && (_jsx("div", { style: {
|
|
26
|
+
position: 'absolute',
|
|
27
|
+
inset: 10,
|
|
28
|
+
border: '2px dashed rgba(120, 165, 255, 0.75)',
|
|
29
|
+
borderRadius: 12,
|
|
30
|
+
pointerEvents: 'none',
|
|
31
|
+
boxShadow: 'inset 0 0 0 1px rgba(120, 165, 255, 0.15)',
|
|
32
|
+
}, children: _jsxs("div", { style: {
|
|
33
|
+
position: 'absolute',
|
|
34
|
+
left: '50%',
|
|
35
|
+
top: 18,
|
|
36
|
+
transform: 'translateX(-50%)',
|
|
37
|
+
background: 'rgba(7, 11, 22, 0.88)',
|
|
38
|
+
border: `1px solid ${theme.border}`,
|
|
39
|
+
borderRadius: 8,
|
|
40
|
+
padding: '8px 14px',
|
|
41
|
+
fontSize: 13,
|
|
42
|
+
color: theme.text,
|
|
43
|
+
whiteSpace: 'nowrap',
|
|
44
|
+
}, children: ["Drop ", dragHover.count === 1 ? 'effect' : `${dragHover.count} effects`, " \u2014 ", dragHover.label] }) })), assetsLoading && (_jsx("div", { style: {
|
|
45
|
+
position: 'absolute',
|
|
46
|
+
inset: 0,
|
|
47
|
+
display: 'flex',
|
|
48
|
+
alignItems: 'center',
|
|
49
|
+
justifyContent: 'center',
|
|
50
|
+
background: 'rgba(7, 11, 22, 0.72)',
|
|
51
|
+
pointerEvents: 'none',
|
|
52
|
+
}, children: _jsxs("div", { style: { ...floatingPanelStyle, borderRadius: 10, padding: '16px 22px', textAlign: 'center' }, children: [_jsx("div", { style: { fontWeight: 600, marginBottom: 6 }, children: "Importing assets\u2026" }), _jsxs("div", { style: { fontSize: 13, color: theme.textDim }, children: [assetsLoading.done, " / ", assetsLoading.total || '…', " files", assetsLoading.failed > 0 ? ` · ${assetsLoading.failed} skipped` : ''] })] }) })), prefabInfo && (_jsxs("div", { style: {
|
|
53
|
+
...floatingPanelStyle,
|
|
54
|
+
position: 'absolute',
|
|
55
|
+
top: 12,
|
|
56
|
+
left: '50%',
|
|
57
|
+
transform: 'translateX(-50%)',
|
|
58
|
+
display: 'flex',
|
|
59
|
+
alignItems: 'center',
|
|
60
|
+
gap: 8,
|
|
61
|
+
padding: '4px 4px 4px 6px',
|
|
62
|
+
border: `1px solid ${theme.borderActive}`,
|
|
63
|
+
fontSize: 12.5,
|
|
64
|
+
zIndex: 5,
|
|
65
|
+
}, children: [_jsx("button", { type: "button", className: "qe-hover", title: "Back to the scene", style: { ...buttonStyle, padding: '3px 10px' }, onClick: onExitPrefab, children: "\u2190 Scene" }), _jsx("span", { style: { color: theme.textDim }, children: "\u203A" }), _jsxs("span", { style: { fontWeight: 600, whiteSpace: 'nowrap' }, children: [prefabInfo.name, prefabDirty ? ' *' : ''] }), _jsx("button", { type: "button", className: "qe-hover", title: "Overwrite the prefab asset (Ctrl+S)", style: saveButtonStyle(prefabDirty, '3px 12px'), onClick: onSavePrefab, children: "Save" })] })), backLink && !prefabInfo && (_jsxs("a", { className: "qe-hover", href: backLink.href, style: {
|
|
66
|
+
...floatingPanelStyle,
|
|
67
|
+
position: 'absolute',
|
|
68
|
+
top: 12,
|
|
69
|
+
left: 12,
|
|
70
|
+
display: 'inline-flex',
|
|
71
|
+
alignItems: 'center',
|
|
72
|
+
gap: 6,
|
|
73
|
+
padding: '6px 12px',
|
|
74
|
+
fontSize: 13,
|
|
75
|
+
fontWeight: 500,
|
|
76
|
+
color: theme.text,
|
|
77
|
+
textDecoration: 'none',
|
|
78
|
+
fontFamily: theme.font,
|
|
79
|
+
}, children: [_jsx(ArrowLeftIcon, { style: iconStyle(14) }), backLink.label.replace(/^←\s*/, '')] })), _jsxs("div", { style: {
|
|
80
|
+
position: 'absolute',
|
|
81
|
+
top: 12,
|
|
82
|
+
right: 12,
|
|
83
|
+
display: 'flex',
|
|
84
|
+
flexDirection: 'column',
|
|
85
|
+
alignItems: 'flex-end',
|
|
86
|
+
gap: 6,
|
|
87
|
+
}, children: [_jsxs("div", { style: { ...floatingPanelStyle, display: 'flex', gap: 4, padding: 4 }, children: [_jsx("button", { className: "qe-hover", style: squareButtonStyle, title: "Undo (Ctrl+Z)", disabled: !canUndo || !hasFocus, onClick: () => onHistoryStep(false), children: _jsx(ArrowUturnLeftIcon, { style: iconStyle(14) }) }), _jsx("button", { className: "qe-hover", style: squareButtonStyle, title: "Redo (Ctrl+Shift+Z)", disabled: !canRedo || !hasFocus, onClick: () => onHistoryStep(true), children: _jsx(ArrowUturnRightIcon, { style: iconStyle(14) }) })] }), _jsx("div", { style: { ...floatingPanelStyle, display: 'flex', flexDirection: 'column', gap: 4, padding: 4 }, children: GIZMO_MODE_BUTTONS.map((m) => (_jsx("button", { className: "qe-hover", style: {
|
|
88
|
+
...squareButtonStyle,
|
|
89
|
+
...(gizmoMode === m.value ? activeSquareButtonStyle : {}),
|
|
90
|
+
}, title: m.title, onClick: () => onGizmoMode(m.value), children: _jsx(m.Icon, { style: iconStyle(14) }) }, m.value))) }), _jsx("div", { style: { ...floatingPanelStyle, display: 'flex', flexDirection: 'column', gap: 4, padding: 4 }, children: _jsx("button", { className: "qe-hover", style: { ...squareButtonStyle, ...(showWireframes ? activeSquareButtonStyle : {}) }, title: "Show emitter shape wireframes", disabled: !hasFocus, onClick: onToggleWireframes, children: _jsx(CubeTransparentIcon, { style: iconStyle(14) }) }) })] })] }));
|
|
91
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { TransformNode } from '@babylonjs/core/Meshes/transformNode.js';
|
|
2
|
+
import type { EditorSession } from '../../core/editorSession.js';
|
|
3
|
+
import type { GizmoMode } from './ViewportPane.js';
|
|
4
|
+
/** True for a field that takes typed text, where editor shortcuts stay out of the way. */
|
|
5
|
+
export declare function isTextInput(target: EventTarget | null): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Inspector value controls (numbers, checkboxes, selects): Ctrl+Z there means the effect's undo,
|
|
8
|
+
* not the browser's per-field text undo. Free-text inputs (names, filters) keep the native one.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isInspectorValueControl(target: EventTarget | null): boolean;
|
|
11
|
+
/** What the editor's keyboard shortcuts do. */
|
|
12
|
+
export interface HostShortcuts {
|
|
13
|
+
/** Ctrl+S: save the scene, or ask about the open prefab. */
|
|
14
|
+
save(): void;
|
|
15
|
+
/** Ctrl+Space: open or close the Assets drawer. */
|
|
16
|
+
toggleAssets(): void;
|
|
17
|
+
/** Space: play or pause the stage. */
|
|
18
|
+
togglePlayback(): void;
|
|
19
|
+
/** Escape: close the floating Assets drawer. */
|
|
20
|
+
closeDrawer(): void;
|
|
21
|
+
/** Ctrl+Z / Ctrl+Y / Ctrl+Shift+Z. */
|
|
22
|
+
historyStep(redo: boolean): void;
|
|
23
|
+
/** Delete: remove the focused effect; returns whether it did. */
|
|
24
|
+
deleteFocused(): boolean;
|
|
25
|
+
}
|
|
26
|
+
/** Handles a keydown on the editor's window; exported for tests. */
|
|
27
|
+
export declare function handleHostShortcut(e: KeyboardEvent, shortcuts: HostShortcuts): void;
|
|
28
|
+
/** Installs the editor's keyboard shortcuts on the window; the latest `shortcuts` are always used. */
|
|
29
|
+
export declare function useHostShortcuts(shortcuts: HostShortcuts): void;
|
|
30
|
+
/**
|
|
31
|
+
* Puts the stage gizmo in `mode` and attaches it to `target`, leaving it where it is while
|
|
32
|
+
* `paused`. One gizmo drag is one undo step: the binding snapshots at drag start, and the UI
|
|
33
|
+
* refreshes at most once a frame while dragging.
|
|
34
|
+
*/
|
|
35
|
+
export declare function useStageGizmo(session: EditorSession | null, mode: GizmoMode, target: TransformNode | null, paused: boolean): void;
|
|
36
|
+
/**
|
|
37
|
+
* The floating drawer is opaque, so the scene renders only in the part of the viewport above it:
|
|
38
|
+
* the view, and every "frame this effect" camera move, re-centres on what is visible. Measured
|
|
39
|
+
* again when the drawer floats or docks and when the timeline collapses. Returns the pixels the
|
|
40
|
+
* drawer covers.
|
|
41
|
+
*/
|
|
42
|
+
export declare function useViewportInset(session: EditorSession | null, canvasRef: React.RefObject<HTMLCanvasElement | null>, areaRef: React.RefObject<HTMLDivElement | null>, drawerFloating: boolean, timelineCollapsed: boolean): number;
|
|
43
|
+
/** Asks before the page unloads while `dirty`. */
|
|
44
|
+
export declare function useUnsavedChangesGuard(dirty: boolean): void;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { Viewport } from '@babylonjs/core/Maths/math.viewport.js';
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { notifyTransformChanged } from '../../core/transformStore.js';
|
|
4
|
+
import { DRAWER_HEIGHT } from './hostStyles.js';
|
|
5
|
+
/** True for a field that takes typed text, where editor shortcuts stay out of the way. */
|
|
6
|
+
export function isTextInput(target) {
|
|
7
|
+
const el = target;
|
|
8
|
+
return !!el && (el.isContentEditable || ['INPUT', 'TEXTAREA', 'SELECT'].includes(el.tagName));
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Inspector value controls (numbers, checkboxes, selects): Ctrl+Z there means the effect's undo,
|
|
12
|
+
* not the browser's per-field text undo. Free-text inputs (names, filters) keep the native one.
|
|
13
|
+
*/
|
|
14
|
+
export function isInspectorValueControl(target) {
|
|
15
|
+
const el = target;
|
|
16
|
+
if (!el)
|
|
17
|
+
return false;
|
|
18
|
+
if (el.tagName === 'SELECT')
|
|
19
|
+
return true;
|
|
20
|
+
return el.tagName === 'INPUT' && ['number', 'checkbox', 'range', 'color'].includes(el.type);
|
|
21
|
+
}
|
|
22
|
+
/** Handles a keydown on the editor's window; exported for tests. */
|
|
23
|
+
export function handleHostShortcut(e, shortcuts) {
|
|
24
|
+
const key = e.key.toLowerCase();
|
|
25
|
+
const command = e.ctrlKey || e.metaKey;
|
|
26
|
+
if (command && key === 's') {
|
|
27
|
+
e.preventDefault();
|
|
28
|
+
shortcuts.save();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (e.code === 'Space' && command) {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
shortcuts.toggleAssets();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const target = e.target;
|
|
37
|
+
if (e.code === 'Space' && !isTextInput(target) && target?.tagName !== 'BUTTON') {
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
shortcuts.togglePlayback();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (e.key === 'Escape') {
|
|
43
|
+
shortcuts.closeDrawer();
|
|
44
|
+
}
|
|
45
|
+
if (command && (key === 'z' || key === 'y')) {
|
|
46
|
+
if (isTextInput(e.target) && !isInspectorValueControl(e.target)) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
// Leave the field first so it shows the restored value instead of its draft text.
|
|
51
|
+
e.target?.blur?.();
|
|
52
|
+
shortcuts.historyStep(key === 'y' || e.shiftKey);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (e.key === 'Delete' && !isTextInput(e.target) && shortcuts.deleteFocused()) {
|
|
56
|
+
e.preventDefault();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Installs the editor's keyboard shortcuts on the window; the latest `shortcuts` are always used. */
|
|
60
|
+
export function useHostShortcuts(shortcuts) {
|
|
61
|
+
const ref = useRef(shortcuts);
|
|
62
|
+
ref.current = shortcuts;
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
const onKey = (e) => handleHostShortcut(e, ref.current);
|
|
65
|
+
window.addEventListener('keydown', onKey);
|
|
66
|
+
return () => window.removeEventListener('keydown', onKey);
|
|
67
|
+
}, []);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Puts the stage gizmo in `mode` and attaches it to `target`, leaving it where it is while
|
|
71
|
+
* `paused`. One gizmo drag is one undo step: the binding snapshots at drag start, and the UI
|
|
72
|
+
* refreshes at most once a frame while dragging.
|
|
73
|
+
*/
|
|
74
|
+
export function useStageGizmo(session, mode, target, paused) {
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
const gm = session?.gizmoManager;
|
|
77
|
+
if (!gm)
|
|
78
|
+
return;
|
|
79
|
+
gm.positionGizmoEnabled = mode === 'position';
|
|
80
|
+
gm.rotationGizmoEnabled = mode === 'rotation';
|
|
81
|
+
gm.scaleGizmoEnabled = mode === 'scale';
|
|
82
|
+
const activeGizmo = mode === 'position'
|
|
83
|
+
? gm.gizmos.positionGizmo
|
|
84
|
+
: mode === 'rotation'
|
|
85
|
+
? gm.gizmos.rotationGizmo
|
|
86
|
+
: mode === 'scale'
|
|
87
|
+
? gm.gizmos.scaleGizmo
|
|
88
|
+
: null;
|
|
89
|
+
let dragRaf = 0;
|
|
90
|
+
const scheduleTransformRefresh = () => {
|
|
91
|
+
if (dragRaf !== 0) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
dragRaf = requestAnimationFrame(() => {
|
|
95
|
+
dragRaf = 0;
|
|
96
|
+
notifyTransformChanged();
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
const dragStartObserver = activeGizmo?.onDragStartObservable.add(() => session.binding?.onBeforeChange?.());
|
|
100
|
+
const dragObserver = activeGizmo?.onDragObservable.add(scheduleTransformRefresh);
|
|
101
|
+
const dragEndObserver = activeGizmo?.onDragEndObservable.add(() => {
|
|
102
|
+
notifyTransformChanged();
|
|
103
|
+
session.binding?.markChanged();
|
|
104
|
+
});
|
|
105
|
+
return () => {
|
|
106
|
+
if (dragRaf !== 0) {
|
|
107
|
+
cancelAnimationFrame(dragRaf);
|
|
108
|
+
}
|
|
109
|
+
if (activeGizmo) {
|
|
110
|
+
activeGizmo.onDragStartObservable.remove(dragStartObserver ?? null);
|
|
111
|
+
activeGizmo.onDragObservable.remove(dragObserver ?? null);
|
|
112
|
+
activeGizmo.onDragEndObservable.remove(dragEndObserver ?? null);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}, [session, mode]);
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (!paused) {
|
|
118
|
+
session?.gizmoManager.attachToNode(target);
|
|
119
|
+
}
|
|
120
|
+
}, [session, target, paused]);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The floating drawer is opaque, so the scene renders only in the part of the viewport above it:
|
|
124
|
+
* the view, and every "frame this effect" camera move, re-centres on what is visible. Measured
|
|
125
|
+
* again when the drawer floats or docks and when the timeline collapses. Returns the pixels the
|
|
126
|
+
* drawer covers.
|
|
127
|
+
*/
|
|
128
|
+
export function useViewportInset(session, canvasRef, areaRef, drawerFloating, timelineCollapsed) {
|
|
129
|
+
const [inset, setInset] = useState(0);
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
const update = () => {
|
|
132
|
+
const camera = session?.camera;
|
|
133
|
+
const canvas = canvasRef.current;
|
|
134
|
+
const area = areaRef.current;
|
|
135
|
+
if (!camera || !canvas || !area)
|
|
136
|
+
return;
|
|
137
|
+
const canvasRect = canvas.getBoundingClientRect();
|
|
138
|
+
const drawerTop = area.getBoundingClientRect().bottom - DRAWER_HEIGHT;
|
|
139
|
+
const covered = drawerFloating
|
|
140
|
+
? Math.max(0, Math.min(canvasRect.height * 0.8, canvasRect.bottom - drawerTop))
|
|
141
|
+
: 0;
|
|
142
|
+
const fraction = canvasRect.height > 0 ? covered / canvasRect.height : 0;
|
|
143
|
+
camera.viewport = new Viewport(0, fraction, 1, 1 - fraction);
|
|
144
|
+
setInset(covered);
|
|
145
|
+
};
|
|
146
|
+
update();
|
|
147
|
+
window.addEventListener('resize', update);
|
|
148
|
+
return () => window.removeEventListener('resize', update);
|
|
149
|
+
}, [session, canvasRef, areaRef, drawerFloating, timelineCollapsed]);
|
|
150
|
+
return inset;
|
|
151
|
+
}
|
|
152
|
+
/** Asks before the page unloads while `dirty`. */
|
|
153
|
+
export function useUnsavedChangesGuard(dirty) {
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
if (!dirty)
|
|
156
|
+
return;
|
|
157
|
+
const onBeforeUnload = (e) => {
|
|
158
|
+
e.preventDefault();
|
|
159
|
+
e.returnValue = '';
|
|
160
|
+
};
|
|
161
|
+
window.addEventListener('beforeunload', onBeforeUnload);
|
|
162
|
+
return () => window.removeEventListener('beforeunload', onBeforeUnload);
|
|
163
|
+
}, [dirty]);
|
|
164
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
/** Width of the Scene list on the left. */
|
|
3
|
+
export declare const SCENE_PANEL_WIDTH = 280;
|
|
4
|
+
/** Width of the inspector on the right. */
|
|
5
|
+
export declare const INSPECTOR_WIDTH = 340;
|
|
6
|
+
/** Height of the timeline dock when expanded. */
|
|
7
|
+
export declare const TIMELINE_HEIGHT = 200;
|
|
8
|
+
/** Height of the Assets drawer. */
|
|
9
|
+
export declare const DRAWER_HEIGHT = 280;
|
|
10
|
+
/** A square icon button of the viewport toolbars. */
|
|
11
|
+
export declare const squareButtonStyle: React.CSSProperties;
|
|
12
|
+
/** Added to a toolbar button that is switched on. */
|
|
13
|
+
export declare const activeSquareButtonStyle: React.CSSProperties;
|
|
14
|
+
/** Title of a dock (Assets, Timeline). */
|
|
15
|
+
export declare const dockTitleStyle: React.CSSProperties;
|
|
16
|
+
/** A small icon button in a dock's header. */
|
|
17
|
+
export declare const dockIconButtonStyle: React.CSSProperties;
|
|
18
|
+
/** A floating panel over the viewport. */
|
|
19
|
+
export declare const floatingPanelStyle: React.CSSProperties;
|
|
20
|
+
/** A Save button, highlighted while there is something to save. */
|
|
21
|
+
export declare function saveButtonStyle(pending: boolean, padding: string): React.CSSProperties;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { buttonStyle, theme } from '../theme.js';
|
|
2
|
+
/** Width of the Scene list on the left. */
|
|
3
|
+
export const SCENE_PANEL_WIDTH = 280;
|
|
4
|
+
/** Width of the inspector on the right. */
|
|
5
|
+
export const INSPECTOR_WIDTH = 340;
|
|
6
|
+
/** Height of the timeline dock when expanded. */
|
|
7
|
+
export const TIMELINE_HEIGHT = 200;
|
|
8
|
+
/** Height of the Assets drawer. */
|
|
9
|
+
export const DRAWER_HEIGHT = 280;
|
|
10
|
+
/** A square icon button of the viewport toolbars. */
|
|
11
|
+
export const squareButtonStyle = {
|
|
12
|
+
...buttonStyle,
|
|
13
|
+
width: 28,
|
|
14
|
+
height: 28,
|
|
15
|
+
padding: 0,
|
|
16
|
+
display: 'flex',
|
|
17
|
+
alignItems: 'center',
|
|
18
|
+
justifyContent: 'center',
|
|
19
|
+
fontWeight: 700,
|
|
20
|
+
};
|
|
21
|
+
/** Added to a toolbar button that is switched on. */
|
|
22
|
+
export const activeSquareButtonStyle = {
|
|
23
|
+
border: `1px solid ${theme.borderActive}`,
|
|
24
|
+
background: 'rgba(120, 165, 255, 0.35)',
|
|
25
|
+
};
|
|
26
|
+
/** Title of a dock (Assets, Timeline). */
|
|
27
|
+
export const dockTitleStyle = {
|
|
28
|
+
fontSize: 11,
|
|
29
|
+
fontWeight: 600,
|
|
30
|
+
letterSpacing: 0.4,
|
|
31
|
+
textTransform: 'uppercase',
|
|
32
|
+
color: theme.text,
|
|
33
|
+
};
|
|
34
|
+
/** A small icon button in a dock's header. */
|
|
35
|
+
export const dockIconButtonStyle = {
|
|
36
|
+
...buttonStyle,
|
|
37
|
+
width: 24,
|
|
38
|
+
height: 22,
|
|
39
|
+
padding: 0,
|
|
40
|
+
display: 'inline-flex',
|
|
41
|
+
alignItems: 'center',
|
|
42
|
+
justifyContent: 'center',
|
|
43
|
+
};
|
|
44
|
+
/** A floating panel over the viewport. */
|
|
45
|
+
export const floatingPanelStyle = {
|
|
46
|
+
background: theme.panelBg,
|
|
47
|
+
border: `1px solid ${theme.border}`,
|
|
48
|
+
borderRadius: 8,
|
|
49
|
+
};
|
|
50
|
+
/** A Save button, highlighted while there is something to save. */
|
|
51
|
+
export function saveButtonStyle(pending, padding) {
|
|
52
|
+
return {
|
|
53
|
+
...buttonStyle,
|
|
54
|
+
padding,
|
|
55
|
+
...(pending ? { background: theme.accent, color: '#0a1128', border: `1px solid ${theme.accent}` } : {}),
|
|
56
|
+
};
|
|
57
|
+
}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type { EditorWorkspaceProps } from './EditorWorkspace.js';
|
|
|
11
11
|
export { EffectEditor } from './EffectEditor.js';
|
|
12
12
|
export type { EffectEditorProps } from './EffectEditor.js';
|
|
13
13
|
export { EffectEditorHost, QuarksEffectEditor } from './EffectEditorHost.js';
|
|
14
|
-
export type { EffectEditorHostHandle, EffectEditorHostProps } from './EffectEditorHost.js';
|
|
14
|
+
export type { EditorProject, EffectEditorHostHandle, EffectEditorHostProps } from './EffectEditorHost.js';
|
|
15
15
|
export { EffectTreeView } from './EffectTreeView.js';
|
|
16
16
|
export type { EffectTreeViewProps } from './EffectTreeView.js';
|
|
17
17
|
export { CheckboxField, NumberField, Row, SelectField } from './fields.js';
|
|
@@ -21,6 +21,7 @@ export type { MessageDialogProps } from './MessageDialog.js';
|
|
|
21
21
|
export { ColorOverLifeModule, EmissionModule, MainModule, RendererModule, ShapeModule, SizeOverLifeModule, } from './modules.js';
|
|
22
22
|
export type { GeometryData, GeometryOption, TextureOption } from './modules.js';
|
|
23
23
|
export { ModuleSection } from './ModuleSection.js';
|
|
24
|
+
export type { ModuleProps } from './ModuleSection.js';
|
|
24
25
|
export { ProjectsPage } from './ProjectsPage.js';
|
|
25
26
|
export type { ProjectsPageProps } from './ProjectsPage.js';
|
|
26
27
|
export { PromptDialog } from './PromptDialog.js';
|
|
@@ -38,3 +39,4 @@ export type { TimelineTrackRowProps } from './TimelineTrackRow.js';
|
|
|
38
39
|
export { TransportBar } from './TransportBar.js';
|
|
39
40
|
export type { TransportBarProps } from './TransportBar.js';
|
|
40
41
|
export { ValueField } from './ValueField.js';
|
|
42
|
+
export type { ConstantValueFieldProps, CurveValueFieldProps } from './ValueField.js';
|
|
@@ -31,7 +31,7 @@ const INSPECTOR_HINTS = {
|
|
|
31
31
|
Duration: 'How long the particle system runs before stopping (non-looping) or one loop cycle.',
|
|
32
32
|
Looping: 'When enabled, the effect restarts from the beginning after duration ends.',
|
|
33
33
|
'World space': 'Simulates in world coordinates so moving the emitter does not drag existing particles.',
|
|
34
|
-
'Scaling mode': '
|
|
34
|
+
'Scaling mode': 'Which scale reaches the effect (Unity’s Scaling Mode): Local, the emitter’s own; Hierarchy, its parents’ too; Shape, the whole scale on the emission shape alone.',
|
|
35
35
|
Prewarm: 'Simulates the effect once at start so it already looks mid-playback when play begins.',
|
|
36
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.',
|
|
37
37
|
'Start delay': 'Wait time before emission starts after play or restart.',
|
package/dist/react/modules.d.ts
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
+
import { Texture } from '@babylonjs/core/Materials/Textures/texture.js';
|
|
1
2
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
binding: EffectBinding;
|
|
5
|
-
}
|
|
3
|
+
import { type ModuleProps } from './ModuleSection.js';
|
|
4
|
+
/** The Main module (Unity's main module): duration, looping, start delay, life, speed, size, rotation and colour. */
|
|
6
5
|
export declare function MainModule({ binding }: ModuleProps): React.JSX.Element;
|
|
6
|
+
/** The Emission module (Unity's Emission): rate over time and distance, and bursts. */
|
|
7
7
|
export declare function EmissionModule({ binding }: ModuleProps): React.JSX.Element;
|
|
8
|
+
/** The Shape module (Unity's Shape): the emitter shape and its settings. */
|
|
8
9
|
export declare function ShapeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
10
|
+
/** The Size over Lifetime module (Unity's Size over Lifetime): size by a curve over the particle's life. */
|
|
9
11
|
export declare function SizeOverLifeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
12
|
+
/** The Color over Lifetime module (Unity's Color over Lifetime): a gradient over the particle's life. */
|
|
10
13
|
export declare function ColorOverLifeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
14
|
+
/** A texture preset the host offers in the Renderer module's texture menus. */
|
|
11
15
|
export interface TextureOption {
|
|
16
|
+
/** Its label in the menu. */
|
|
12
17
|
label: string;
|
|
18
|
+
/** The URL the host's texture loader receives. */
|
|
13
19
|
url: string;
|
|
14
20
|
}
|
|
15
21
|
/**
|
|
@@ -18,20 +24,25 @@ export interface TextureOption {
|
|
|
18
24
|
* them into the system's instancing geometry.
|
|
19
25
|
*/
|
|
20
26
|
export interface GeometryOption {
|
|
27
|
+
/** Its label in the menu. */
|
|
21
28
|
label: string;
|
|
29
|
+
/** Vertex positions, three values per vertex. */
|
|
22
30
|
positions: Float32Array | number[];
|
|
31
|
+
/** Triangle indices; without them the vertices are drawn in sequence. */
|
|
23
32
|
indices?: Uint32Array | number[];
|
|
33
|
+
/** The first UV set, two values per vertex; without it the mesh samples UV (0, 0). */
|
|
24
34
|
uvs?: Float32Array | number[];
|
|
25
35
|
/** A second UV set (glTF `TEXCOORD_1`), what textures on UV channel 1 read on the mesh. */
|
|
26
36
|
uvs2?: Float32Array | number[];
|
|
37
|
+
/** Vertex normals, three values per vertex; without them lighting uses +Z. */
|
|
27
38
|
normals?: Float32Array | number[];
|
|
28
39
|
}
|
|
29
40
|
/** Vertex buffers a host loader (e.g. a GLB importer) returns for the Mesh render mode. */
|
|
30
41
|
export type GeometryData = Omit<GeometryOption, 'label'>;
|
|
42
|
+
/** The Renderer module (Unity's Renderer): render mode, material, textures, sorting and mesh settings. */
|
|
31
43
|
export declare function RendererModule({ binding, textureOptions, geometryOptions, resolveTexture, resolveGeometry, }: ModuleProps & {
|
|
32
44
|
textureOptions?: TextureOption[];
|
|
33
45
|
geometryOptions?: GeometryOption[];
|
|
34
|
-
resolveTexture?: (url: string) =>
|
|
46
|
+
resolveTexture?: (url: string) => Texture | null | undefined;
|
|
35
47
|
resolveGeometry?: (file: File) => Promise<GeometryData>;
|
|
36
48
|
}): React.JSX.Element;
|
|
37
|
-
export {};
|