refactor(particlesystem): align ParticleSystemComponent with CameraComponent architecture#8873
Merged
Merged
Conversation
…mponent architecture Move all ~60 properties from ParticleSystemComponentData onto the component as private fields with real getters/setters, inlining the side effects that previously lived in set_* event handlers. The data class now holds only 'enabled', the system schema shrinks to ['enabled'], and the system applies incoming data through the public setters and clones via an explicit property list. Behavior is preserved, including the legacy mesh->meshAsset id remap, vec3/curve/curveset deserialization, the dual resetTime+resetMaterial side effect of the loop property, and skipping null values when cloning. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Public API reportThis PR changes the public API surface (+10 / −10), per the docs' rules (@ignore / @Private / undocumented are excluded). Show API diff-AttributeSchema.type: "string" | "number" | "boolean" | "vec2" | "vec3" | "vec4" | "json" | "rgb" | "asset" | "curve" | "entity" | "rgba"
+AttributeSchema.type: "string" | "number" | "boolean" | "vec2" | "vec3" | "vec4" | "json" | "rgb" | "asset" | "entity" | "rgba" | "curve"
-ParticleSystemComponent.get colorMapAsset(): Asset
+ParticleSystemComponent.get colorMapAsset(): Asset | null
-ParticleSystemComponent.get meshAsset(): Asset
+ParticleSystemComponent.get meshAsset(): Asset | null
-ParticleSystemComponent.get normalMapAsset(): Asset
+ParticleSystemComponent.get normalMapAsset(): Asset | null
-ParticleSystemComponent.get renderAsset(): Asset
+ParticleSystemComponent.get renderAsset(): Asset | null
-ParticleSystemComponent.set colorMapAsset(arg: Asset)
+ParticleSystemComponent.set colorMapAsset(arg: Asset | null)
-ParticleSystemComponent.set meshAsset(arg: Asset)
+ParticleSystemComponent.set meshAsset(arg: Asset | null)
-ParticleSystemComponent.set normalMapAsset(arg: Asset)
+ParticleSystemComponent.set normalMapAsset(arg: Asset | null)
-ParticleSystemComponent.set renderAsset(arg: Asset)
+ParticleSystemComponent.set renderAsset(arg: Asset | null)
-ScriptAttributes.add(name: string, args: { array: boolean; assetType: string; color: string; curves: string[]; default: any; description: string; enum: any[]; max: number; min: number; placeholder: string | string[]; precision: number; schema: any[]; size: number; step: number; title: string; type: "string" | "number" | "boolean" | "vec2" | "vec3" | "vec4" | "json" | "rgb" | "asset" | "curve" | "entity" | "rgba" }): void
+ScriptAttributes.add(name: string, args: { array: boolean; assetType: string; color: string; curves: string[]; default: any; description: string; enum: any[]; max: number; min: number; placeholder: string | string[]; precision: number; schema: any[]; size: number; step: number; title: string; type: "string" | "number" | "boolean" | "vec2" | "vec3" | "vec4" | "json" | "rgb" | "asset" | "entity" | "rgba" | "curve" }): voidInformational only — this never fails the build. |
Contributor
There was a problem hiding this comment.
Pull request overview
Refactors ParticleSystemComponent to match the newer component architecture used by Camera/Light/Button/etc by moving most state off the legacy data bag and set_* event handlers, while keeping enabled schema-based.
Changes:
- Migrates ParticleSystemComponent properties to private fields with real getters/setters; inlines side effects previously implemented via
set_*listeners. - Reduces component data/schema to
enabledonly; updates system initialization/cloning to use public setters/getters and perform vec3/curve deserialization. - Adds a new unit test suite covering defaults, JSON-style initialization, asset/id normalization, cloning, and pause/play behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
src/framework/components/particle-system/component.js |
Moves runtime state to private fields; rewires property side effects and lifecycle behavior to operate on this.emitter and private fields. |
src/framework/components/particle-system/system.js |
Shrinks schema to enabled, updates initialization and cloning to apply properties via setters and deep-clone Vec3/Curve/CurveSet values. |
src/framework/components/particle-system/data.js |
Reduces data object to enabled only. |
test/framework/components/particlesystem/component.test.mjs |
Adds tests for defaults, initialization conversions, legacy remap, asset normalization, cloning, and pause behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…laying() Skip present-but-undefined keys in initializeComponentData so class-field defaults are preserved (matching the base initializer) and curve deserialization cannot throw on undefined. Make isPlaying() return false when no emitter exists instead of throwing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…om/playcanvas/engine into refactor-particle-system-component
…ty JSDoc
Skip explicit nulls in curve/curveset deserialization so component creation
cannot throw on { alphaGraph: null }. Correct the JSDoc on the four asset
properties to Asset|number|null (they normalize Asset instances to ids),
matching the ModelComponent convention.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per the convention from the collision migration discussion, the public API documents encouraged usage (Asset|null) rather than everything tolerated (ids remain accepted and stored internally). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Asset setters gate deferred loads on the component's enabled state, so the intended enabled value must be in the data store before they run. Previously they always saw the default (true) and could trigger loads for components initialized disabled. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Continues the component architecture migration series (#8871 collision, #8870 button, #8777, #8693, #8666) by moving the
ParticleSystemComponentoff the legacy data-object +set_*event architecture.component.js
onSet*event handlers are inlined into the setters, gated onthis.emitter(the emitter only exists afteronEnable)._setSimpleProperty,_setComplexProperty,_setGraphProperty) called from the setters.Assetinstances to ids and handle bind/unbind directly.modeandscenedata fields are dropped;pausedbecomes a private runtime field.data.js
enabled = true.system.js
['enabled'];initializeComponentDatakeeps the legacymesh→meshAssetid remap and vec3/curve/curveset deserialization, then applies properties through the public setters;cloneComponentreads getters and deep-clonesVec3/Curve/CurveSetvalues;Component._buildAccessorsprovides theenabledaccessor.Tests
Vec3, raw{type, keys}→Curve/CurveSetwith type preserved), instance pass-through, legacy mesh-id remap, Asset→id normalization, deep cloning, and pause behavior.Notes for reviewers
loopwas registered with two legacy handlers (onSetLoopplus the SIMPLE_PROPERTIES handler), so its new setter performs bothresetTime()andresetMaterial()to preserve behavior.cloneComponentskipsnull/undefinedvalues exactly like the old schema-based clone did — otherwise a cloned direct-assignedmeshwould be wiped by a trailingmeshAsset: nullwrite.loop,blendType,depthSofteningdepth-layer request/release,layersmigration,pause()/play(),enabledtoggle) — all propagate to the emitter with no console errors.Checklist
🤖 Generated with Claude Code