babylon.quarks-editor 0.17.7
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 +13 -0
- package/LICENSE +21 -0
- package/README.md +84 -0
- package/dist/core/binding.d.ts +43 -0
- package/dist/core/binding.js +82 -0
- package/dist/core/collision.d.ts +20 -0
- package/dist/core/collision.js +39 -0
- package/dist/core/colors.d.ts +31 -0
- package/dist/core/colors.js +60 -0
- package/dist/core/effectTree.d.ts +25 -0
- package/dist/core/effectTree.js +115 -0
- package/dist/core/groups.d.ts +12 -0
- package/dist/core/groups.js +27 -0
- package/dist/core/history.d.ts +25 -0
- package/dist/core/history.js +69 -0
- package/dist/core/loadEffect.d.ts +8 -0
- package/dist/core/loadEffect.js +87 -0
- package/dist/core/scrub.d.ts +11 -0
- package/dist/core/scrub.js +24 -0
- package/dist/core/shapes.d.ts +31 -0
- package/dist/core/shapes.js +98 -0
- package/dist/core/systems.d.ts +25 -0
- package/dist/core/systems.js +76 -0
- package/dist/core/textureExport.d.ts +9 -0
- package/dist/core/textureExport.js +58 -0
- package/dist/core/timeline.d.ts +35 -0
- package/dist/core/timeline.js +69 -0
- package/dist/core/values.d.ts +31 -0
- package/dist/core/values.js +81 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +9 -0
- package/dist/react/CurveEditor.d.ts +12 -0
- package/dist/react/CurveEditor.js +106 -0
- package/dist/react/EffectEditor.d.ts +22 -0
- package/dist/react/EffectEditor.js +30 -0
- package/dist/react/EffectEditorHost.d.ts +42 -0
- package/dist/react/EffectEditorHost.js +247 -0
- package/dist/react/GradientEditor.d.ts +7 -0
- package/dist/react/GradientEditor.js +72 -0
- package/dist/react/ModuleSection.d.ts +9 -0
- package/dist/react/ModuleSection.js +24 -0
- package/dist/react/PromptDialog.d.ts +14 -0
- package/dist/react/PromptDialog.js +45 -0
- package/dist/react/SubEmittersModule.d.ts +10 -0
- package/dist/react/SubEmittersModule.js +39 -0
- package/dist/react/TimelinePanel.d.ts +32 -0
- package/dist/react/TimelinePanel.js +225 -0
- package/dist/react/TimelineTrackRow.d.ts +23 -0
- package/dist/react/TimelineTrackRow.js +107 -0
- package/dist/react/ValueField.d.ts +13 -0
- package/dist/react/ValueField.js +19 -0
- package/dist/react/behaviorModules.d.ts +23 -0
- package/dist/react/behaviorModules.js +139 -0
- package/dist/react/fields.d.ts +24 -0
- package/dist/react/fields.js +30 -0
- package/dist/react/index.d.ts +20 -0
- package/dist/react/index.js +14 -0
- package/dist/react/modules.d.ts +35 -0
- package/dist/react/modules.js +439 -0
- package/dist/react/theme.d.ts +26 -0
- package/dist/react/theme.js +78 -0
- package/package.json +63 -0
- package/src/core/binding.ts +105 -0
- package/src/core/collision.ts +40 -0
- package/src/core/colors.ts +84 -0
- package/src/core/effectTree.ts +143 -0
- package/src/core/groups.ts +29 -0
- package/src/core/history.ts +77 -0
- package/src/core/loadEffect.ts +102 -0
- package/src/core/scrub.ts +28 -0
- package/src/core/shapes.ts +133 -0
- package/src/core/systems.ts +98 -0
- package/src/core/textureExport.ts +63 -0
- package/src/core/timeline.ts +94 -0
- package/src/core/values.ts +113 -0
- package/src/index.ts +32 -0
- package/src/react/CurveEditor.tsx +168 -0
- package/src/react/EffectEditor.tsx +111 -0
- package/src/react/EffectEditorHost.tsx +377 -0
- package/src/react/GradientEditor.tsx +127 -0
- package/src/react/ModuleSection.tsx +54 -0
- package/src/react/PromptDialog.tsx +85 -0
- package/src/react/SubEmittersModule.tsx +80 -0
- package/src/react/TimelinePanel.tsx +354 -0
- package/src/react/TimelineTrackRow.tsx +267 -0
- package/src/react/ValueField.tsx +60 -0
- package/src/react/behaviorModules.tsx +658 -0
- package/src/react/fields.tsx +76 -0
- package/src/react/index.ts +43 -0
- package/src/react/modules.tsx +1034 -0
- package/src/react/theme.ts +85 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { buildCurve, buildScalar, readPieces, readScalar } from '../core/values';
|
|
3
|
+
import { CurveEditor } from './CurveEditor';
|
|
4
|
+
import { NumberField, Row, SelectField } from './fields';
|
|
5
|
+
/**
|
|
6
|
+
* Unity-like value field: Constant | Random Between Two Constants | Curve,
|
|
7
|
+
* bound to a quarks value generator.
|
|
8
|
+
*/
|
|
9
|
+
export function ValueField(props) {
|
|
10
|
+
const state = readScalar(props.generator);
|
|
11
|
+
const commit = (patch) => {
|
|
12
|
+
props.onChange(buildScalar({ ...state, ...patch }));
|
|
13
|
+
};
|
|
14
|
+
return (_jsxs(_Fragment, { children: [_jsx(Row, { label: props.label, children: _jsx(SelectField, { value: state.mode, options: [
|
|
15
|
+
{ value: 'constant', label: 'Constant' },
|
|
16
|
+
{ value: 'random', label: 'Random between two' },
|
|
17
|
+
{ value: 'curve', label: 'Curve' },
|
|
18
|
+
], onChange: (mode) => commit({ mode }) }) }), state.mode === 'constant' && (_jsx(Row, { label: "", children: _jsx(NumberField, { value: state.value, min: props.min, onChange: (value) => commit({ value }) }) })), state.mode === 'random' && (_jsx(Row, { label: "", children: _jsxs("div", { style: { display: 'flex', gap: 6 }, children: [_jsx(NumberField, { value: state.min, min: props.min, onChange: (min) => commit({ min }) }), _jsx(NumberField, { value: state.max, min: props.min, onChange: (max) => commit({ max }) })] }) })), state.mode === 'curve' && (_jsx("div", { style: { marginTop: 6 }, children: _jsx(CurveEditor, { pieces: readPieces(props.generator), maxValue: props.curveMax, onChange: (pieces) => props.onChange(buildCurve(pieces)) }) }))] }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { EffectBinding } from '../core/binding';
|
|
3
|
+
interface ModuleProps {
|
|
4
|
+
binding: EffectBinding;
|
|
5
|
+
}
|
|
6
|
+
export declare function SpeedOverLifeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
7
|
+
export declare function LimitSpeedOverLifeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
8
|
+
export declare function ForceOverLifeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
9
|
+
export declare function VelocityOverLifeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
10
|
+
export declare function InheritVelocityModule({ binding }: ModuleProps): React.JSX.Element;
|
|
11
|
+
export declare function GravityModule({ binding }: ModuleProps): React.JSX.Element;
|
|
12
|
+
export declare function RotationOverLifeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
13
|
+
export declare function NoiseModule({ binding }: ModuleProps): React.JSX.Element;
|
|
14
|
+
export declare function TurbulenceModule({ binding }: ModuleProps): React.JSX.Element;
|
|
15
|
+
export declare function EmitDirectionModule({ binding }: ModuleProps): React.JSX.Element;
|
|
16
|
+
export declare function CollisionModule({ binding }: ModuleProps): React.JSX.Element;
|
|
17
|
+
export declare function ColorBySpeedModule({ binding }: ModuleProps): React.JSX.Element;
|
|
18
|
+
export declare function SizeBySpeedModule({ binding }: ModuleProps): React.JSX.Element;
|
|
19
|
+
export declare function RotationBySpeedModule({ binding }: ModuleProps): React.JSX.Element;
|
|
20
|
+
export declare function OrbitOverLifeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
21
|
+
export declare function WidthOverTrailModule({ binding }: ModuleProps): React.JSX.Element;
|
|
22
|
+
export declare function TextureSheetModule({ binding }: ModuleProps): React.JSX.Element;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ApplyCollision, ApplyForce, ChangeEmitDirection, ColorBySpeed, ConstantValue, ForceOverLife, FrameOverLife, Gradient, InheritVelocity, IntervalValue, LimitSpeedOverLife, Noise, OrbitOverLife, RotationBySpeed, RotationOverLife, SizeBySpeed, SpeedOverLife, TurbulenceField, Vector3, VelocityOverLife, WidthOverLength, } from 'babylon.quarks';
|
|
3
|
+
import { ensureGroundResolver } from '../core/collision';
|
|
4
|
+
import { DEFAULT_GRADIENT_STOPS, buildGradient, findBehavior, readGradientStops } from '../core/colors';
|
|
5
|
+
import { buildCurve, buildScalar, readPieces, readScalar } from '../core/values';
|
|
6
|
+
import { GradientEditor } from './GradientEditor';
|
|
7
|
+
import { CurveEditor } from './CurveEditor';
|
|
8
|
+
import { ModuleSection } from './ModuleSection';
|
|
9
|
+
import { NumberField, Row, SelectField } from './fields';
|
|
10
|
+
import { ValueField } from './ValueField';
|
|
11
|
+
function removeBehaviorOfType(behaviors, type) {
|
|
12
|
+
for (let i = behaviors.length - 1; i >= 0; i--) {
|
|
13
|
+
if (behaviors[i].type === type) {
|
|
14
|
+
behaviors.splice(i, 1);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Shared shell for modules backed by a single toggleable quarks behavior. */
|
|
19
|
+
function BehaviorModule(props) {
|
|
20
|
+
const behavior = findBehavior(props.binding.system.behaviors, props.type);
|
|
21
|
+
return (_jsx(ModuleSection, { title: props.title, enabled: !!behavior, defaultOpen: false, onToggle: (enabled) => props.binding.apply((s) => {
|
|
22
|
+
removeBehaviorOfType(s.behaviors, props.type);
|
|
23
|
+
if (enabled) {
|
|
24
|
+
s.addBehavior(props.create());
|
|
25
|
+
}
|
|
26
|
+
}), children: behavior ? props.children(behavior) : null }));
|
|
27
|
+
}
|
|
28
|
+
export function SpeedOverLifeModule({ binding }) {
|
|
29
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Speed over Lifetime", type: "SpeedOverLife", create: () => new SpeedOverLife(buildScalar({ mode: 'curve', value: 1, min: 0, max: 1, curve: [1, 0.75, 0.5, 0] })), children: (behavior) => (_jsx("div", { style: { marginTop: 6 }, children: _jsx(CurveEditor, { pieces: readPieces(behavior.speed), maxValue: 2, onChange: (pieces) => binding.apply(() => (behavior.speed = buildCurve(pieces))) }) })) }));
|
|
30
|
+
}
|
|
31
|
+
export function LimitSpeedOverLifeModule({ binding }) {
|
|
32
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Limit Speed over Lifetime", type: "LimitSpeedOverLife", create: () => new LimitSpeedOverLife(buildScalar({ mode: 'curve', value: 1, min: 0, max: 1, curve: [4, 2, 1, 1] }), 0.5), children: (behavior) => (_jsxs(_Fragment, { children: [_jsx("div", { style: { marginTop: 6 }, children: _jsx(CurveEditor, { pieces: readPieces(behavior.speed), maxValue: 8, onChange: (pieces) => binding.apply(() => (behavior.speed = buildCurve(pieces))) }) }), _jsx(Row, { label: "Dampen", children: _jsx(NumberField, { value: behavior.dampen, min: 0, step: 0.05, onChange: (v) => binding.apply(() => (behavior.dampen = Math.min(1, v))) }) })] })) }));
|
|
33
|
+
}
|
|
34
|
+
export function ForceOverLifeModule({ binding }) {
|
|
35
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Force over Lifetime", type: "ForceOverLife", create: () => new ForceOverLife(new ConstantValue(0), new ConstantValue(2), new ConstantValue(0)), children: (behavior) => (_jsxs(_Fragment, { children: [_jsx(ValueField, { label: "X", generator: behavior.x, curveMax: 10, onChange: (g) => binding.apply(() => (behavior.x = g)) }), _jsx(ValueField, { label: "Y", generator: behavior.y, curveMax: 10, onChange: (g) => binding.apply(() => (behavior.y = g)) }), _jsx(ValueField, { label: "Z", generator: behavior.z, curveMax: 10, onChange: (g) => binding.apply(() => (behavior.z = g)) })] })) }));
|
|
36
|
+
}
|
|
37
|
+
export function VelocityOverLifeModule({ binding }) {
|
|
38
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Velocity over Lifetime", type: "VelocityOverLife", create: () => new VelocityOverLife(new ConstantValue(0), new ConstantValue(1), new ConstantValue(0)), children: (behavior) => (_jsxs(_Fragment, { children: [_jsx(Row, { label: "Space", children: _jsx(SelectField, { value: behavior.space, options: [
|
|
39
|
+
{ value: 'local', label: 'Local' },
|
|
40
|
+
{ value: 'world', label: 'World' },
|
|
41
|
+
], onChange: (v) => binding.apply(() => (behavior.space = v)) }) }), _jsx(ValueField, { label: "Linear X", generator: behavior.linearX, curveMax: 10, onChange: (g) => binding.apply(() => (behavior.linearX = g)) }), _jsx(ValueField, { label: "Linear Y", generator: behavior.linearY, curveMax: 10, onChange: (g) => binding.apply(() => (behavior.linearY = g)) }), _jsx(ValueField, { label: "Linear Z", generator: behavior.linearZ, curveMax: 10, onChange: (g) => binding.apply(() => (behavior.linearZ = g)) }), _jsx(ValueField, { label: "Orbital X", generator: behavior.orbitalX, curveMax: Math.PI * 4, onChange: (g) => binding.apply(() => (behavior.orbitalX = g)) }), _jsx(ValueField, { label: "Orbital Y", generator: behavior.orbitalY, curveMax: Math.PI * 4, onChange: (g) => binding.apply(() => (behavior.orbitalY = g)) }), _jsx(ValueField, { label: "Orbital Z", generator: behavior.orbitalZ, curveMax: Math.PI * 4, onChange: (g) => binding.apply(() => (behavior.orbitalZ = g)) })] })) }));
|
|
42
|
+
}
|
|
43
|
+
export function InheritVelocityModule({ binding }) {
|
|
44
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Inherit Velocity", type: "InheritVelocity", create: () => new InheritVelocity(new ConstantValue(1), 'initial'), children: (behavior) => (_jsxs(_Fragment, { children: [_jsx(Row, { label: "Mode", children: _jsx(SelectField, { value: behavior.mode, options: [
|
|
45
|
+
{ value: 'initial', label: 'Initial' },
|
|
46
|
+
{ value: 'current', label: 'Current' },
|
|
47
|
+
], onChange: (v) => binding.apply(() => (behavior.mode = v)) }) }), _jsx(ValueField, { label: "Multiplier", generator: behavior.multiplier, curveMax: 2, onChange: (g) => binding.apply(() => (behavior.multiplier = g)) })] })) }));
|
|
48
|
+
}
|
|
49
|
+
export function GravityModule({ binding }) {
|
|
50
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Gravity", type: "ApplyForce", create: () => new ApplyForce(new Vector3(0, -1, 0), new ConstantValue(9.81)), children: (behavior) => (_jsx(Row, { label: "Strength", children: _jsx(NumberField, { value: readScalar(behavior.magnitude).value, step: 0.5, onChange: (v) => binding.apply(() => (behavior.magnitude = new ConstantValue(v))) }) })) }));
|
|
51
|
+
}
|
|
52
|
+
export function RotationOverLifeModule({ binding }) {
|
|
53
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Rotation over Lifetime", type: "RotationOverLife", create: () => new RotationOverLife(new ConstantValue(Math.PI)), children: (behavior) => (_jsx(ValueField, { label: "Velocity (rad/s)", generator: behavior.angularVelocity, curveMax: Math.PI * 4, onChange: (g) => binding.apply(() => (behavior.angularVelocity = g)) })) }));
|
|
54
|
+
}
|
|
55
|
+
export function NoiseModule({ binding }) {
|
|
56
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Noise", type: "Noise", create: () => new Noise(new ConstantValue(1), new ConstantValue(1), new ConstantValue(1), new ConstantValue(0)), children: (behavior) => (_jsxs(_Fragment, { children: [_jsx(ValueField, { label: "Frequency", generator: behavior.frequency, min: 0, curveMax: 10, onChange: (g) => binding.apply(() => (behavior.frequency = g)) }), _jsx(ValueField, { label: "Strength", generator: behavior.power, min: 0, curveMax: 10, onChange: (g) => binding.apply(() => (behavior.power = g)) }), _jsx(ValueField, { label: "Position amount", generator: behavior.positionAmount, min: 0, curveMax: 2, onChange: (g) => binding.apply(() => (behavior.positionAmount = g)) }), _jsx(ValueField, { label: "Rotation amount", generator: behavior.rotationAmount, min: 0, curveMax: Math.PI, onChange: (g) => binding.apply(() => (behavior.rotationAmount = g)) })] })) }));
|
|
57
|
+
}
|
|
58
|
+
/** Three numeric inputs for a Vector3 field, replacing the whole vector on any edit. */
|
|
59
|
+
function Vector3Row(props) {
|
|
60
|
+
const set = (axis, n) => {
|
|
61
|
+
const next = props.value.clone();
|
|
62
|
+
next[axis] = n;
|
|
63
|
+
props.onChange(next);
|
|
64
|
+
};
|
|
65
|
+
return (_jsx(Row, { label: props.label, children: _jsxs("div", { style: { display: 'flex', gap: 6 }, children: [_jsx(NumberField, { value: props.value.x, min: props.min, step: props.step, onChange: (n) => set('x', n) }), _jsx(NumberField, { value: props.value.y, min: props.min, step: props.step, onChange: (n) => set('y', n) }), _jsx(NumberField, { value: props.value.z, min: props.min, step: props.step, onChange: (n) => set('z', n) })] }) }));
|
|
66
|
+
}
|
|
67
|
+
export function TurbulenceModule({ binding }) {
|
|
68
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Turbulence", type: "TurbulenceField", create: () => new TurbulenceField(new Vector3(1, 1, 1), 3, new Vector3(1, 1, 1), new Vector3(1, 1, 1)), children: (behavior) => (_jsxs(_Fragment, { children: [_jsx(Vector3Row, { label: "Scale", value: behavior.scale, min: 0.01, step: 0.1, onChange: (v) => binding.apply(() => (behavior.scale = v)) }), _jsx(Row, { label: "Octaves", children: _jsx(NumberField, { value: behavior.octaves, min: 1, step: 1, onChange: (v) => binding.apply(() => (behavior.octaves = Math.max(1, Math.round(v)))) }) }), _jsx(Vector3Row, { label: "Strength", value: behavior.velocityMultiplier, step: 0.5, onChange: (v) => binding.apply(() => (behavior.velocityMultiplier = v)) }), _jsx(Vector3Row, { label: "Time scale", value: behavior.timeScale, step: 0.1, onChange: (v) => binding.apply(() => (behavior.timeScale = v)) })] })) }));
|
|
69
|
+
}
|
|
70
|
+
export function EmitDirectionModule({ binding }) {
|
|
71
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Randomize Direction", type: "ChangeEmitDirection", create: () => new ChangeEmitDirection(new IntervalValue(0, Math.PI / 6)), children: (behavior) => (_jsx(ValueField, { label: "Angle (rad)", generator: behavior.angle, min: 0, curveMax: Math.PI, onChange: (g) => binding.apply(() => (behavior.angle = g)) })) }));
|
|
72
|
+
}
|
|
73
|
+
export function CollisionModule({ binding }) {
|
|
74
|
+
// Ensure the shared ground-plane resolver exists before any ApplyCollision is created,
|
|
75
|
+
// otherwise its update() would dereference an undefined resolver.
|
|
76
|
+
const resolver = ensureGroundResolver();
|
|
77
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Collision", type: "ApplyCollision", create: () => new ApplyCollision(ensureGroundResolver(), 0.5), children: (behavior) => (_jsxs(_Fragment, { children: [_jsx(Row, { label: "Bounce", children: _jsx(NumberField, { value: behavior.bounce, min: 0, step: 0.05, onChange: (v) => binding.apply(() => (behavior.bounce = v)) }) }), _jsx(Row, { label: "Floor Y", children: _jsx(NumberField, { value: resolver.y, step: 0.1, onChange: (v) => binding.apply(() => (resolver.y = v)) }) }), _jsx("div", { style: { fontSize: 11, opacity: 0.6, marginTop: 4 }, children: "Collides against a ground plane. Bounce is saved with the effect; Floor Y is an editor preview aid (a host can register its own colliders)." })] })) }));
|
|
78
|
+
}
|
|
79
|
+
/** Shared speed-range rows for the "by Speed" trio. */
|
|
80
|
+
function SpeedRangeRows({ binding, behavior }) {
|
|
81
|
+
return (_jsx(Row, { label: "Speed range", children: _jsxs("div", { style: { display: 'flex', gap: 6 }, children: [_jsx(NumberField, { value: behavior.speedRange.a, min: 0, onChange: (v) => binding.apply(() => (behavior.speedRange = new IntervalValue(v, behavior.speedRange.b))) }), _jsx(NumberField, { value: behavior.speedRange.b, min: 0, onChange: (v) => binding.apply(() => (behavior.speedRange = new IntervalValue(behavior.speedRange.a, v))) })] }) }));
|
|
82
|
+
}
|
|
83
|
+
export function ColorBySpeedModule({ binding }) {
|
|
84
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Color by Speed", type: "ColorBySpeed", create: () => new ColorBySpeed(buildGradient(DEFAULT_GRADIENT_STOPS), new IntervalValue(0, 5)), children: (behavior) => (_jsxs(_Fragment, { children: [_jsx("div", { style: { marginTop: 6 }, children: _jsx(GradientEditor, { stops: behavior.color instanceof Gradient ? readGradientStops(behavior.color) : DEFAULT_GRADIENT_STOPS, onChange: (stops) => binding.apply(() => (behavior.color = buildGradient(stops))) }) }), _jsx(SpeedRangeRows, { binding: binding, behavior: behavior })] })) }));
|
|
85
|
+
}
|
|
86
|
+
export function SizeBySpeedModule({ binding }) {
|
|
87
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Size by Speed", type: "SizeBySpeed", create: () => new SizeBySpeed(buildScalar({ mode: 'curve', value: 1, min: 0, max: 1, curve: [0.5, 0.8, 1.2, 1.5] }), new IntervalValue(0, 5)), children: (behavior) => (_jsxs(_Fragment, { children: [_jsx("div", { style: { marginTop: 6 }, children: _jsx(CurveEditor, { pieces: readPieces(behavior.size), maxValue: 2, onChange: (pieces) => binding.apply(() => (behavior.size = buildCurve(pieces))) }) }), _jsx(SpeedRangeRows, { binding: binding, behavior: behavior })] })) }));
|
|
88
|
+
}
|
|
89
|
+
export function RotationBySpeedModule({ binding }) {
|
|
90
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Rotation by Speed", type: "RotationBySpeed", create: () => new RotationBySpeed(new ConstantValue(Math.PI), new IntervalValue(0, 5)), children: (behavior) => (_jsxs(_Fragment, { children: [_jsx(ValueField, { label: "Velocity (rad/s)", generator: behavior.angularVelocity, curveMax: Math.PI * 4, onChange: (g) => binding.apply(() => (behavior.angularVelocity = g)) }), _jsx(SpeedRangeRows, { binding: binding, behavior: behavior })] })) }));
|
|
91
|
+
}
|
|
92
|
+
export function OrbitOverLifeModule({ binding }) {
|
|
93
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Orbit over Lifetime", type: "OrbitOverLife", create: () => new OrbitOverLife(new ConstantValue(Math.PI), new Vector3(0, 1, 0)), children: (behavior) => (_jsx(ValueField, { label: "Orbit speed", generator: behavior.orbitSpeed, curveMax: Math.PI * 4, onChange: (g) => binding.apply(() => (behavior.orbitSpeed = g)) })) }));
|
|
94
|
+
}
|
|
95
|
+
export function WidthOverTrailModule({ binding }) {
|
|
96
|
+
return (_jsx(BehaviorModule, { binding: binding, title: "Width over Trail", type: "WidthOverLength", create: () => new WidthOverLength(buildScalar({ mode: 'curve', value: 1, min: 0, max: 1, curve: [1, 0.75, 0.4, 0] })), children: (behavior) => (_jsx("div", { style: { marginTop: 6 }, children: _jsx(CurveEditor, { pieces: readPieces(behavior.width), maxValue: 2, onChange: (pieces) => binding.apply(() => (behavior.width = buildCurve(pieces))) }) })) }));
|
|
97
|
+
}
|
|
98
|
+
export function TextureSheetModule({ binding }) {
|
|
99
|
+
const system = binding.system;
|
|
100
|
+
const frameBehavior = findBehavior(system.behaviors, 'FrameOverLife');
|
|
101
|
+
const tiles = Math.max(1, system.uTileCount * system.vTileCount);
|
|
102
|
+
const textureUrl = system.texture?.url;
|
|
103
|
+
const u = Math.max(1, system.uTileCount);
|
|
104
|
+
const v = Math.max(1, system.vTileCount);
|
|
105
|
+
// Start tile → cell (row-major, top-left origin — matches the shader's tile UV mapping).
|
|
106
|
+
const startIdx = Math.min(Math.max(0, Math.round(readScalar(system.startTileIndex).value)), tiles - 1);
|
|
107
|
+
const startCol = startIdx % u;
|
|
108
|
+
const startRow = Math.floor(startIdx / u);
|
|
109
|
+
return (_jsxs(ModuleSection, { title: "Texture Sheet Animation", defaultOpen: false, children: [textureUrl && (_jsxs("div", { style: { marginTop: 6 }, children: [_jsxs("div", { style: { position: 'relative', width: 218, border: '1px solid #2b3761', borderRadius: 6, overflow: 'hidden' }, children: [_jsx("img", { src: textureUrl, alt: "texture atlas", style: { width: '100%', display: 'block' } }), _jsx("div", { style: {
|
|
110
|
+
position: 'absolute',
|
|
111
|
+
inset: 0,
|
|
112
|
+
pointerEvents: 'none',
|
|
113
|
+
backgroundImage: `repeating-linear-gradient(to right, rgba(158,185,255,0.55) 0 1px, transparent 1px calc(100% / ${u})),` +
|
|
114
|
+
`repeating-linear-gradient(to bottom, rgba(158,185,255,0.55) 0 1px, transparent 1px calc(100% / ${v}))`,
|
|
115
|
+
} }), _jsx("div", { style: {
|
|
116
|
+
position: 'absolute',
|
|
117
|
+
pointerEvents: 'none',
|
|
118
|
+
left: `${(startCol * 100) / u}%`,
|
|
119
|
+
top: `${(startRow * 100) / v}%`,
|
|
120
|
+
width: `${100 / u}%`,
|
|
121
|
+
height: `${100 / v}%`,
|
|
122
|
+
boxSizing: 'border-box',
|
|
123
|
+
border: '2px solid #ffce6b',
|
|
124
|
+
background: 'rgba(255, 206, 107, 0.22)',
|
|
125
|
+
}, children: _jsx("span", { style: {
|
|
126
|
+
position: 'absolute',
|
|
127
|
+
top: 1,
|
|
128
|
+
left: 2,
|
|
129
|
+
fontSize: 9,
|
|
130
|
+
fontWeight: 700,
|
|
131
|
+
color: '#ffce6b',
|
|
132
|
+
textShadow: '0 0 3px #000',
|
|
133
|
+
}, children: startIdx }) })] }), _jsxs("div", { style: { fontSize: 11, color: '#b7c6ea', marginTop: 3 }, children: [u, " \u00D7 ", v, " = ", tiles, " tiles; frame indices 0\u2013", tiles - 1, "; start tile", ' ', _jsx("span", { style: { color: '#ffce6b', fontWeight: 600 }, children: startIdx })] })] })), _jsx(Row, { label: "Tiles U", children: _jsx(NumberField, { value: system.uTileCount, min: 1, step: 1, onChange: (v) => binding.apply((s) => (s.uTileCount = Math.round(v))) }) }), _jsx(Row, { label: "Tiles V", children: _jsx(NumberField, { value: system.vTileCount, min: 1, step: 1, onChange: (v) => binding.apply((s) => (s.vTileCount = Math.round(v))) }) }), _jsx(Row, { label: "Blend tiles", children: _jsx("input", { type: "checkbox", className: "qe-hover", checked: system.blendTiles, style: { justifySelf: 'start', width: 15, height: 15, accentColor: '#78a5ff', cursor: 'pointer' }, onChange: (e) => binding.apply((s) => (s.blendTiles = e.target.checked)) }) }), _jsx(Row, { label: "Start tile", children: _jsx(NumberField, { value: readScalar(system.startTileIndex).value, min: 0, step: 1, onChange: (v) => binding.apply((s) => (s.startTileIndex = new ConstantValue(Math.round(v)))) }) }), _jsx(Row, { label: "Animate frames", children: _jsx("input", { type: "checkbox", className: "qe-hover", checked: !!frameBehavior, style: { justifySelf: 'start', width: 15, height: 15, accentColor: '#78a5ff', cursor: 'pointer' }, onChange: (e) => binding.apply((s) => {
|
|
134
|
+
removeBehaviorOfType(s.behaviors, 'FrameOverLife');
|
|
135
|
+
if (e.target.checked) {
|
|
136
|
+
s.addBehavior(new FrameOverLife(buildScalar({ mode: 'curve', value: 0, min: 0, max: tiles - 1, curve: [0, (tiles - 1) / 3, (2 * (tiles - 1)) / 3, tiles - 1] })));
|
|
137
|
+
}
|
|
138
|
+
}) }) }), frameBehavior && (_jsx("div", { style: { marginTop: 6 }, children: _jsx(CurveEditor, { pieces: readPieces(frameBehavior.frame), maxValue: Math.max(1, tiles - 1), onChange: (pieces) => binding.apply(() => (frameBehavior.frame = buildCurve(pieces))) }) }))] }));
|
|
139
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export declare function Row(props: {
|
|
3
|
+
label: string;
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
}): React.JSX.Element;
|
|
6
|
+
/** Number input that keeps focus-friendly local text state and commits parsed values. */
|
|
7
|
+
export declare function NumberField(props: {
|
|
8
|
+
value: number;
|
|
9
|
+
onChange: (value: number) => void;
|
|
10
|
+
step?: number;
|
|
11
|
+
min?: number;
|
|
12
|
+
}): React.JSX.Element;
|
|
13
|
+
export declare function CheckboxField(props: {
|
|
14
|
+
value: boolean;
|
|
15
|
+
onChange: (value: boolean) => void;
|
|
16
|
+
}): React.JSX.Element;
|
|
17
|
+
export declare function SelectField<T extends string | number>(props: {
|
|
18
|
+
value: T;
|
|
19
|
+
options: Array<{
|
|
20
|
+
value: T;
|
|
21
|
+
label: string;
|
|
22
|
+
}>;
|
|
23
|
+
onChange: (value: T) => void;
|
|
24
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { inputStyle, labelStyle, rowStyle } from './theme';
|
|
4
|
+
export function Row(props) {
|
|
5
|
+
return (_jsxs("div", { style: rowStyle, children: [_jsx("span", { style: labelStyle, title: props.label, children: props.label }), props.children] }));
|
|
6
|
+
}
|
|
7
|
+
/** Number input that keeps focus-friendly local text state and commits parsed values. */
|
|
8
|
+
export function NumberField(props) {
|
|
9
|
+
const [text, setText] = useState(String(round(props.value)));
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
setText(String(round(props.value)));
|
|
12
|
+
}, [props.value]);
|
|
13
|
+
return (_jsx("input", { type: "number", className: "qe-hover", style: inputStyle, value: text, step: props.step ?? 0.1, min: props.min, onChange: (e) => {
|
|
14
|
+
setText(e.target.value);
|
|
15
|
+
const parsed = parseFloat(e.target.value);
|
|
16
|
+
if (!Number.isNaN(parsed)) {
|
|
17
|
+
props.onChange(props.min !== undefined ? Math.max(props.min, parsed) : parsed);
|
|
18
|
+
}
|
|
19
|
+
} }));
|
|
20
|
+
}
|
|
21
|
+
export function CheckboxField(props) {
|
|
22
|
+
return (_jsx("input", { type: "checkbox", className: "qe-hover", checked: props.value, onChange: (e) => props.onChange(e.target.checked), style: { justifySelf: 'start', width: 15, height: 15, accentColor: '#78a5ff', cursor: 'pointer' } }));
|
|
23
|
+
}
|
|
24
|
+
export function SelectField(props) {
|
|
25
|
+
const numeric = typeof props.value === 'number';
|
|
26
|
+
return (_jsx("select", { className: "qe-hover", style: { ...inputStyle, cursor: 'pointer' }, value: String(props.value), onChange: (e) => props.onChange((numeric ? Number(e.target.value) : e.target.value)), children: props.options.map((o) => (_jsx("option", { value: String(o.value), children: o.label }, String(o.value)))) }));
|
|
27
|
+
}
|
|
28
|
+
function round(v) {
|
|
29
|
+
return Math.round(v * 1000) / 1000;
|
|
30
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export { EffectEditor } from './EffectEditor';
|
|
2
|
+
export type { EffectEditorProps } from './EffectEditor';
|
|
3
|
+
export { SpeedOverLifeModule, LimitSpeedOverLifeModule, ForceOverLifeModule, GravityModule, RotationOverLifeModule, NoiseModule, TurbulenceModule, CollisionModule, EmitDirectionModule, TextureSheetModule, ColorBySpeedModule, SizeBySpeedModule, RotationBySpeedModule, OrbitOverLifeModule, WidthOverTrailModule, } from './behaviorModules';
|
|
4
|
+
export type { TextureOption, GeometryOption, GeometryData } from './modules';
|
|
5
|
+
export { SubEmittersModule } from './SubEmittersModule';
|
|
6
|
+
export { TimelinePanel } from './TimelinePanel';
|
|
7
|
+
export type { TimelinePanelProps, PlaybackState } from './TimelinePanel';
|
|
8
|
+
export { TimelineTrackRow } from './TimelineTrackRow';
|
|
9
|
+
export type { TimelineTrackRowProps } from './TimelineTrackRow';
|
|
10
|
+
export { ModuleSection } from './ModuleSection';
|
|
11
|
+
export { PromptDialog } from './PromptDialog';
|
|
12
|
+
export type { PromptDialogProps } from './PromptDialog';
|
|
13
|
+
export { CurveEditor } from './CurveEditor';
|
|
14
|
+
export { GradientEditor } from './GradientEditor';
|
|
15
|
+
export { ValueField } from './ValueField';
|
|
16
|
+
export { Row, NumberField, CheckboxField, SelectField } from './fields';
|
|
17
|
+
export { MainModule, EmissionModule, ShapeModule, SizeOverLifeModule, ColorOverLifeModule, RendererModule, } from './modules';
|
|
18
|
+
export { theme, inputStyle, rowStyle, labelStyle, buttonStyle } from './theme';
|
|
19
|
+
export { EffectEditorHost, QuarksEffectEditor } from './EffectEditorHost';
|
|
20
|
+
export type { EffectEditorHostProps, EffectEditorHostHandle } from './EffectEditorHost';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { EffectEditor } from './EffectEditor';
|
|
2
|
+
export { SpeedOverLifeModule, LimitSpeedOverLifeModule, ForceOverLifeModule, GravityModule, RotationOverLifeModule, NoiseModule, TurbulenceModule, CollisionModule, EmitDirectionModule, TextureSheetModule, ColorBySpeedModule, SizeBySpeedModule, RotationBySpeedModule, OrbitOverLifeModule, WidthOverTrailModule, } from './behaviorModules';
|
|
3
|
+
export { SubEmittersModule } from './SubEmittersModule';
|
|
4
|
+
export { TimelinePanel } from './TimelinePanel';
|
|
5
|
+
export { TimelineTrackRow } from './TimelineTrackRow';
|
|
6
|
+
export { ModuleSection } from './ModuleSection';
|
|
7
|
+
export { PromptDialog } from './PromptDialog';
|
|
8
|
+
export { CurveEditor } from './CurveEditor';
|
|
9
|
+
export { GradientEditor } from './GradientEditor';
|
|
10
|
+
export { ValueField } from './ValueField';
|
|
11
|
+
export { Row, NumberField, CheckboxField, SelectField } from './fields';
|
|
12
|
+
export { MainModule, EmissionModule, ShapeModule, SizeOverLifeModule, ColorOverLifeModule, RendererModule, } from './modules';
|
|
13
|
+
export { theme, inputStyle, rowStyle, labelStyle, buttonStyle } from './theme';
|
|
14
|
+
export { EffectEditorHost, QuarksEffectEditor } from './EffectEditorHost';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { EffectBinding } from '../core/binding';
|
|
3
|
+
interface ModuleProps {
|
|
4
|
+
binding: EffectBinding;
|
|
5
|
+
}
|
|
6
|
+
export declare function MainModule({ binding }: ModuleProps): React.JSX.Element;
|
|
7
|
+
export declare function EmissionModule({ binding }: ModuleProps): React.JSX.Element;
|
|
8
|
+
export declare function ShapeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
9
|
+
export declare function SizeOverLifeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
10
|
+
export declare function ColorOverLifeModule({ binding }: ModuleProps): React.JSX.Element;
|
|
11
|
+
export interface TextureOption {
|
|
12
|
+
label: string;
|
|
13
|
+
url: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A host-supplied mesh for the Mesh render mode (e.g. asset meshes from BabylonJS Editor),
|
|
17
|
+
* analogous to TextureOption. The host provides ready vertex buffers; selecting one copies
|
|
18
|
+
* them into the system's instancing geometry.
|
|
19
|
+
*/
|
|
20
|
+
export interface GeometryOption {
|
|
21
|
+
label: string;
|
|
22
|
+
positions: Float32Array | number[];
|
|
23
|
+
indices?: Uint32Array | number[];
|
|
24
|
+
uvs?: Float32Array | number[];
|
|
25
|
+
normals?: Float32Array | number[];
|
|
26
|
+
}
|
|
27
|
+
/** Vertex buffers a host loader (e.g. a GLB importer) returns for the Mesh render mode. */
|
|
28
|
+
export type GeometryData = Omit<GeometryOption, 'label'>;
|
|
29
|
+
export declare function RendererModule({ binding, textureOptions, geometryOptions, resolveTexture, resolveGeometry, }: ModuleProps & {
|
|
30
|
+
textureOptions?: TextureOption[];
|
|
31
|
+
geometryOptions?: GeometryOption[];
|
|
32
|
+
resolveTexture?: (url: string) => unknown;
|
|
33
|
+
resolveGeometry?: (file: File) => Promise<GeometryData>;
|
|
34
|
+
}): React.JSX.Element;
|
|
35
|
+
export {};
|