A particle is a function of its age, not a thing that is stepped (#73)
game-maker / suite (push) Failing after 4m22s

The asset type `particles` is placeable and carries a graph at the same time —
`behavior` was the blueprint. Because a continuous emitter gives birth to particle n
at time n/rate, the whole field is a function of the clock rather than of the frames:
no ring-buffer bookkeeping, exact time jumps, reproducibility as a measurable property.

compile.ts follows compileShader's frame but emits JS closures into a Float64Array
instead of GLSL, and without eval; a node with two consumers is evaluated once.
Drawing is one Pixi ParticleContainer per source, so one draw call.

Collision, wind and braking in flight are out for good — that is the price of the
formula model, not an omission.

The tab count goes from nine to ten, which is exactly the case #84 was built for one
day earlier: at 1280 px the row no longer holds every tab, so guard 14b now asks for
hidden.length > 0 instead of === 0.
This commit is contained in:
root committed 2026-09-14 05:44:25 +02:00
1 parent f83c568999
commit 0f9e1611d1
39 files changed
+2386 -32

No files matched your search

+21 -2
View File
@@ -21,6 +21,7 @@ import { HierarchyPanel } from './panels/HierarchyPanel';
import { Toolbar } from './panels/Toolbar';
import { type PlayHost, PlaySession, type WorldSnapshot } from './PlaySession';
import { ProjectSession } from './ProjectSession';
import { ParticlesEditor } from './particles/ParticlesEditor';
import { ShaderEditor } from './shader/ShaderEditor';
import { StateMachineEditor } from './statemachine/StateMachineEditor';
import { installShortcuts } from './shortcuts';
@@ -29,7 +30,16 @@ import { TextureEditor } from './texture/TextureEditor';
import { installFileImport } from './fileImport';
export type CentreTab =
'scene' | 'graph' | 'statemachine' | 'shader' | 'game' | 'texture' | 'animation' | 'container' | 'list';
| 'scene'
| 'graph'
| 'statemachine'
| 'shader'
| 'particles'
| 'game'
| 'texture'
| 'animation'
| 'container'
| 'list';
const TAB_ORDER = [
'scene',
@@ -37,6 +47,7 @@ const TAB_ORDER = [
'graph',
'statemachine',
'shader',
'particles',
'texture',
'animation',
'container',
@@ -49,6 +60,7 @@ const TAB_LABELS: Record<CentreTab, string> = {
graph: 'Behavior',
statemachine: 'State machine',
shader: 'Shader',
particles: 'Particles',
texture: 'Texture',
animation: 'Animation',
container: 'Container',
@@ -61,6 +73,7 @@ const TAB_OF_ASSET: Partial<Record<AssetType, CentreTab>> = {
behavior: 'graph',
statemachine: 'statemachine',
shader: 'shader',
particles: 'particles',
texture: 'texture',
animation: 'animation',
container: 'container',
@@ -87,6 +100,7 @@ export class Editor implements PlayHost {
readonly graphEditor: GraphEditor;
readonly stateMachineEditor: StateMachineEditor;
readonly shaderEditor: ShaderEditor;
readonly particlesEditor: ParticlesEditor;
readonly textureEditor: TextureEditor;
readonly animationEditor: AnimationEditor;
readonly containerEditor: ContainerEditor;
@@ -129,6 +143,7 @@ export class Editor implements PlayHost {
this.graphEditor = new GraphEditor(state);
this.stateMachineEditor = new StateMachineEditor(state);
this.shaderEditor = new ShaderEditor(state);
this.particlesEditor = new ParticlesEditor(state);
this.textureEditor = new TextureEditor(state);
this.animationEditor = new AnimationEditor(state);
this.containerEditor = new ContainerEditor(state);
@@ -175,6 +190,7 @@ export class Editor implements PlayHost {
graph: this.graphEditor,
statemachine: this.stateMachineEditor,
shader: this.shaderEditor,
particles: this.particlesEditor,
texture: this.textureEditor,
animation: this.animationEditor,
container: this.containerEditor,
@@ -233,7 +249,9 @@ export class Editor implements PlayHost {
? 'statemachine'
: state.selectedShaderId
? 'shader'
: 'graph';
: state.selectedParticlesId
? 'particles'
: 'graph';
if (this.tab !== tab) this.showTab(tab);
}
if (s?.kind === 'frame' && this.tab !== 'texture') this.showTab('texture');
@@ -305,6 +323,7 @@ export class Editor implements PlayHost {
this.gameView.animate();
this.console.refresh();
if (this.tab === 'animation') this.animationEditor.tick(dt);
if (this.tab === 'particles') this.particlesEditor.tick();
}
private measureFps(dt: number): void {