createParticleSystem
Add particle effects to 3D scenes in Spline by configuring emission rate, lifetime, speed, size, color, and emission shape for visual enhancements.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sceneId | Yes | Scene ID | |
| name | No | System name | Particle System |
| position | No | System position | |
| emissionRate | No | Particles per second | |
| lifetime | No | Particle lifetime (seconds) | |
| speed | No | Particle speed | |
| size | No | Particle size | |
| color | No | Particle color (hex) | #ffffff |
| shape | No | Emission shape | sphere |
Implementation Reference
- src/tools/design/particle-tools.js:15-122 (registration)Complete registration of the 'createParticleSystem' tool, including detailed input schema using Zod and the handler function that calls the Spline API to create the particle system.server.tool( "createParticleSystem", { sceneId: z.string().min(1).describe("Scene ID"), emitterType: z.enum(["point", "box", "sphere", "circle", "mesh"]).describe("Type of particle emitter"), position: z.object({ x: z.number().default(0), y: z.number().default(0), z: z.number().default(0), }).optional().describe("Position in 3D space"), rotation: z.object({ x: z.number().default(0), y: z.number().default(0), z: z.number().default(0), }).optional().describe("Rotation in degrees"), parameters: z.object({ // Emission parameters rate: z.number().positive().describe("Particles per second"), burstCount: z.number().int().min(0).default(0).describe("Number of particles to emit in a burst"), burstInterval: z.number().positive().optional().describe("Interval between bursts (seconds)"), duration: z.number().positive().optional().describe("Duration of emission (seconds, 0 for continuous)"), loop: z.boolean().default(true).describe("Whether the emission loops"), // Emitter shape parameters size: z.object({ x: z.number().positive(), y: z.number().positive(), z: z.number().positive(), }).optional().describe("Emitter size for box/sphere emitters"), radius: z.number().positive().optional().describe("Radius for circle/sphere emitters"), sourceMeshId: z.string().optional().describe("Source mesh ID for mesh emitters"), emitFromVolume: z.boolean().default(true).optional().describe("Emit from volume or surface"), // Particle appearance particleShape: z.enum(["point", "sphere", "cube", "custom"]).default("sphere").describe("Particle shape"), customMeshId: z.string().optional().describe("Custom mesh ID for custom particle shape"), particleSize: z.number().positive().default(0.1).describe("Particle size"), sizeVariation: z.number().min(0).max(1).default(0).describe("Random variation in particle size"), startSize: z.number().positive().optional().describe("Initial particle size"), endSize: z.number().positive().optional().describe("Final particle size"), // Particle material material: z.string().optional().describe("Material ID to apply to particles"), color: z.string().optional().describe("Particle color (hex/rgb)"), startColor: z.string().optional().describe("Initial particle color (hex/rgb)"), endColor: z.string().optional().describe("Final particle color (hex/rgb)"), opacity: z.number().min(0).max(1).default(1).describe("Particle opacity"), startOpacity: z.number().min(0).max(1).optional().describe("Initial particle opacity"), endOpacity: z.number().min(0).max(1).optional().describe("Final particle opacity"), // Particle behavior lifetime: z.number().positive().default(1).describe("Particle lifetime in seconds"), lifetimeVariation: z.number().min(0).max(1).default(0).describe("Random variation in particle lifetime"), speed: z.number().default(1).describe("Particle movement speed"), speedVariation: z.number().min(0).max(1).default(0).describe("Random variation in particle speed"), direction: z.object({ x: z.number().default(0), y: z.number().default(1), z: z.number().default(0), }).optional().describe("Base emission direction"), directionVariation: z.number().min(0).max(1).default(0).describe("Random variation in emission direction"), // Physics gravity: z.object({ x: z.number().default(0), y: z.number().default(0), z: z.number().default(0), }).optional().describe("Gravity force"), drag: z.number().min(0).default(0).describe("Air drag coefficient"), turbulence: z.number().min(0).default(0).describe("Turbulence strength"), turbulenceScale: z.number().positive().default(1).describe("Turbulence scale"), // Collision collisionEnabled: z.boolean().default(false).describe("Enable collision detection"), collideWith: z.array(z.string()).optional().describe("Object IDs to collide with"), bounciness: z.number().min(0).max(1).default(0.5).describe("Collision bounciness"), }).describe("Particle system parameters"), }, async ({ sceneId, emitterType, position, rotation, parameters }) => { try { const result = await fetchFromSplineApi(`/scenes/${sceneId}/objects/particles`, { method: "POST", body: JSON.stringify({ emitterType, position, rotation, parameters, }), }); return { content: [{ type: "text", text: `Created ${emitterType} particle system (ID: ${result.objectId})` }] }; } catch (error) { return { content: [{ type: "text", text: `Error creating particle system: ${error.message}` }], isError: true }; } } );
- The execution handler for createParticleSystem tool that POSTs to the Spline API endpoint to create the particle system object.async ({ sceneId, emitterType, position, rotation, parameters }) => { try { const result = await fetchFromSplineApi(`/scenes/${sceneId}/objects/particles`, { method: "POST", body: JSON.stringify({ emitterType, position, rotation, parameters, }), }); return { content: [{ type: "text", text: `Created ${emitterType} particle system (ID: ${result.objectId})` }] }; } catch (error) { return { content: [{ type: "text", text: `Error creating particle system: ${error.message}` }], isError: true }; } } );
- Comprehensive Zod schema defining all inputs for the createParticleSystem tool, including emitter configuration, particle properties, physics, and more.{ sceneId: z.string().min(1).describe("Scene ID"), emitterType: z.enum(["point", "box", "sphere", "circle", "mesh"]).describe("Type of particle emitter"), position: z.object({ x: z.number().default(0), y: z.number().default(0), z: z.number().default(0), }).optional().describe("Position in 3D space"), rotation: z.object({ x: z.number().default(0), y: z.number().default(0), z: z.number().default(0), }).optional().describe("Rotation in degrees"), parameters: z.object({ // Emission parameters rate: z.number().positive().describe("Particles per second"), burstCount: z.number().int().min(0).default(0).describe("Number of particles to emit in a burst"), burstInterval: z.number().positive().optional().describe("Interval between bursts (seconds)"), duration: z.number().positive().optional().describe("Duration of emission (seconds, 0 for continuous)"), loop: z.boolean().default(true).describe("Whether the emission loops"), // Emitter shape parameters size: z.object({ x: z.number().positive(), y: z.number().positive(), z: z.number().positive(), }).optional().describe("Emitter size for box/sphere emitters"), radius: z.number().positive().optional().describe("Radius for circle/sphere emitters"), sourceMeshId: z.string().optional().describe("Source mesh ID for mesh emitters"), emitFromVolume: z.boolean().default(true).optional().describe("Emit from volume or surface"), // Particle appearance particleShape: z.enum(["point", "sphere", "cube", "custom"]).default("sphere").describe("Particle shape"), customMeshId: z.string().optional().describe("Custom mesh ID for custom particle shape"), particleSize: z.number().positive().default(0.1).describe("Particle size"), sizeVariation: z.number().min(0).max(1).default(0).describe("Random variation in particle size"), startSize: z.number().positive().optional().describe("Initial particle size"), endSize: z.number().positive().optional().describe("Final particle size"), // Particle material material: z.string().optional().describe("Material ID to apply to particles"), color: z.string().optional().describe("Particle color (hex/rgb)"), startColor: z.string().optional().describe("Initial particle color (hex/rgb)"), endColor: z.string().optional().describe("Final particle color (hex/rgb)"), opacity: z.number().min(0).max(1).default(1).describe("Particle opacity"), startOpacity: z.number().min(0).max(1).optional().describe("Initial particle opacity"), endOpacity: z.number().min(0).max(1).optional().describe("Final particle opacity"), // Particle behavior lifetime: z.number().positive().default(1).describe("Particle lifetime in seconds"), lifetimeVariation: z.number().min(0).max(1).default(0).describe("Random variation in particle lifetime"), speed: z.number().default(1).describe("Particle movement speed"), speedVariation: z.number().min(0).max(1).default(0).describe("Random variation in particle speed"), direction: z.object({ x: z.number().default(0), y: z.number().default(1), z: z.number().default(0), }).optional().describe("Base emission direction"), directionVariation: z.number().min(0).max(1).default(0).describe("Random variation in emission direction"), // Physics gravity: z.object({ x: z.number().default(0), y: z.number().default(0), z: z.number().default(0), }).optional().describe("Gravity force"), drag: z.number().min(0).default(0).describe("Air drag coefficient"), turbulence: z.number().min(0).default(0).describe("Turbulence strength"), turbulenceScale: z.number().positive().default(1).describe("Turbulence scale"), // Collision collisionEnabled: z.boolean().default(false).describe("Enable collision detection"), collideWith: z.array(z.string()).optional().describe("Object IDs to collide with"), bounciness: z.number().min(0).max(1).default(0.5).describe("Collision bounciness"), }).describe("Particle system parameters"), },
- src/tools/design-tools.js:95-137 (registration)Simpler stub registration of createParticleSystem in design-tools.js, likely overridden or supplementary.server.tool( 'createParticleSystem', { sceneId: z.string().min(1).describe('Scene ID'), name: z.string().optional().default('Particle System').describe('System name'), position: z.object({ x: z.number().default(0).describe('X position'), y: z.number().default(0).describe('Y position'), z: z.number().default(0).describe('Z position'), }).optional().describe('System position'), emissionRate: z.number().min(0).optional().default(50).describe('Particles per second'), lifetime: z.number().min(0).optional().default(2).describe('Particle lifetime (seconds)'), speed: z.number().min(0).optional().default(1).describe('Particle speed'), size: z.number().min(0).optional().default(0.1).describe('Particle size'), color: z.string().optional().default('#ffffff').describe('Particle color (hex)'), shape: z.enum(['point', 'sphere', 'box', 'cone']).optional().default('sphere') .describe('Emission shape'), }, async ({ sceneId, name, position, emissionRate, lifetime, speed, size, color, shape }) => { try { // This would normally call the Spline API to create a particle system // For now, just return a success message return { content: [ { type: 'text', text: `Particle system "${name}" created successfully` } ] }; } catch (error) { return { content: [ { type: 'text', text: `Error creating particle system: ${error.message}` } ], isError: true }; } } );
- Imports for Zod schema validation and API client helpers used in the tool implementation.import { z } from "zod"; import { fetchFromSplineApi, updateSplineObject } from "../../utils/api-client.js";