What: Unity editor Tool
Tools: Original written in Visual Studio.
Re-Written With Windsurf (It's Awesome!)
A WIP Unity editor tool that standardizes particle presets, spawns prefabs from them, adds simple track keying, auto-captures thumbnail previews for any prefab, and includes a plain-English URP material maker for consistent rendering.
Architecture at a glance (what exists)
┌─────────────────────────────────────────────────────────────────┐
│                           FXTool (Editor)                       │
│                                                                 │
│  ┌───────────┐    ┌──────────────┐   ┌───────────────┐          │
│  │ FXPreset  │ →  │ FXPresetApplier │ → (Scene/Prefab)          │
│  └───────────┘    └──────────────┘   └───────────────┘          │
│         ↑                          ↑                             │
│         │                          │                             │
│  (listed/edited)             (invoked from)                      │
│         │                          │                             │
│  ┌──────────────┐     ┌──────────────────────┐      ┌──────────┐ │
│  │ FXToolWindow │ →→  │ FXTrackManager (API) │  →→  │ Animator │ │
│  └──────────────┘     └──────────────────────┘      └──────────┘ │
│         │                                                       │
│         ├── (calls)                                             │
│         │                                                       │
│  ┌─────────────────────┐        ┌──────────────────────┐        │
│  │ FXLibraryMaterial…  │  →→    │ FXURPMaterialFactory │        │
│  └─────────────────────┘        └──────────────────────┘        │
│                                                                 │
│   (PlayMode helper)                                             │
│        ┌─────────────────────────┐                              │
│        │ FXRuntimeThumbCapturer │  (GUID-keyed PNG cache)       │
│        └─────────────────────────┘                              │
└─────────────────────────────────────────────────────────────────┘
 
1) Folders & naming (shared foundation)
The tool enforces a predictable layout (Assets/FXTool/...) and naming helpers for roots/children, then guarantees all folders exist via EnsureAll(). This keeps presets, prefabs, thumbnails, materials, and textures tidy and script-discoverable.
public static string BuildChildName(string category, string preset, string role, int i = 0)
=> $"FX_{San(category)}_{San(preset)}_{role}_{i:D2}";
This naming scheme is used everywhere (presets to prefab names, child PS nodes, etc.).
2) Presets (ScriptableObjects)
A preset stores identity (category/name/desc) and the key Shuriken knobs (duration, looping, lifetime, speed, size, emission, shape), plus renderer/sorting and optional flipbook info. It’s intentionally minimal but extendable.
[CreateAssetMenu(menuName="FXTool/Preset")]
public class FXPreset : ScriptableObject {
public FXCategory category; public string presetName; public string description;
public float duration; public bool looping; public float startLifetime, startSpeed, startSize;
public int rateOverTime; public ParticleSystem.Burst[] bursts;
public ParticleSystemShapeType shape; public float radius, angle;
public Material material; public string sortingLayer; public int orderInLayer;
public Texture2D flipbook; public int tilesX=1, tilesY=1; public float flipbookFPS=12f;
}
ScriptableObject with callouts (“Main”, “Emission”, “Shape”, “Material/Sorting”, “Flipbook”).
 
3) Preset to Prefab
The applier builds a rooted GameObject, adds a child with a ParticleSystem, and transfers preset values into Shuriken modules. It also wires flipbook settings when present, and can immediately save a prefab asset.
var root = new GameObject(FXNaming.BuildRootName(p.category.ToString(), p.presetName));
var psGo = new GameObject(FXNaming.BuildChildName(p.category.ToString(), p.presetName, "PS"));
var ps = psGo.AddComponent<ParticleSystem>();
// main
var main = ps.main;
main.duration = p.duration; main.loop = p.looping;
main.startLifetime = p.startLifetime; main.startSpeed = p.startSpeed; main.startSize = p.startSize;
// emission
ps.emission.rateOverTime = p.rateOverTime;
// renderer & sorting
var r = ps.GetComponent<ParticleSystemRenderer>();
r.sharedMaterial = p.material; r.sortingLayerName = p.sortingLayer; r.sortingOrder = p.orderInLayer;
4) Editor window (Library | Inspector | Tracks)
The tool window exposes three workflows:
- Library: lists all FXPreset assets under Assets/FXTool/Presets so you can select, duplicate, or ping.
- Inspector actions: “Create From Preset” to spawns in scene; “Save As Prefab” to writes to Assets/FXTool/Prefabs.
- Tracks (MVP): a tiny keyframer for position on the spawned root. You set Clip name/FPS/Frame/Vector3 and it keys transform curves.
// “Key Position on Root at Frame”
var ctrl = FXTrackManager.EnsureAnimator(_lastRoot);
var clip = FXTrackManager.EnsureClip(ctrl, _clipName, Mathf.Max(2f, _frame/_fps+0.1f), _fps);
FXTrackManager.KeyTransformPosition(clip, _lastRoot.transform, _frame, _pos, _fps);
5) Tracks API (Animator + clips + transform curves)
Under the hood: if the spawned root doesn’t have an Animator, it creates one and stores a controller next to your prefabs. Then it ensures a clip by name and writes transform curves for m_LocalPosition.{x,y,z} at a given time = frame/fps.
static void AddKey(AnimationClip clip, Transform t, string prop, float v, float time) {
var bind = EditorCurveBinding.FloatCurve(AnimationUtility.CalculateTransformPath(t, null), typeof(Transform), prop);
var curve = AnimationUtility.GetEditorCurve(clip, bind) ?? new AnimationCurve();
curve.AddKey(new Keyframe(time, v) { weightedMode = WeightedMode.Both });
AnimationUtility.SetEditorCurve(clip, bind, curve);
}
6) Thumbnail capture (the big quality-of-life win!)
No need for Play Mode - just instantiate each requested prefab in front of Camera.main, warm up the particle systems, render to a square RT, reads back to Texture2D, and save as a PNG into a cache folder keyed by GUID.
Particle pack used for testing: https://assetstore.unity.com/packages...
instance.transform.position = cam.transform.position + cam.transform.forward * cfg.distance;
foreach (var ps in instance.GetComponentsInChildren<ParticleSystem>(true)) {
ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
ps.Simulate(0f, true, true, true);
ps.Play(true);
}
// render to RT to Texture2D to PNG in cache
The cache path is created defensively (Assets/FXTool/Cache/ParticleThumbs/...), and each PNG is named with the prefab’s GUID so the library can look up thumbnails deterministically later.
UX detail: the coroutine uses small warmup/capture delays so particles are “mid-motion” when snapped; it also shuts down Play Mode when done so the batch flow is quick.
7) URP Material Factory (plain-English, guard-railed)
A separate editor window lets you pick Usage (Sprite, Particle Billboard, Trails, UI), Blend (Alpha/Additive/Premultiplied/Multiply/Cutout), sidedness, ZWrite, and emission. It then creates/updates a URP material at a stable path (Assets/FXTool/Materials/<Category>/<Name>.mat).
On apply, it sets the URP surface/blend/keyword combo properly (including premultiplied and alpha-clip cases) and toggles common keywords.
On masse layer switcher /
There’s also a small “Tips” section to nudge best-practice choices (e.g., Sprite-Unlit-Default for 2D, Particles/Unlit + Additive for glows). The path utility ensures category subfolders exist.
How the pieces talk to each other
- FXPreset is the source of truth for particle settings.
- FXPresetApplier reads a preset and builds a scene object/prefab with those values (and flipbook, sorting).
- FXToolWindow is the entry point: pick preset to create to (optionally) save prefab to (optionally) key position.
- FXTrackManager owns animator/clip creation and low-level curve writing.
- FXRuntimeThumbCapturer batch-renders thumbnails for any list of prefab paths and writes them to a cache (GUID-keyed).
- URP Material Factory creates consistent materials that presets can reference.
 
Current limitations / “known” WIP
- Track keying: only transform position is exposed; PS module animation is planned (Emission, Size, Speed, Color) either via safe bindings or a tiny runtime driver.
- Thumbnail UX: batch list is passed by EditorPrefs (simple but brittle); a first-class “Library” grid with live cache state and folder filters is the next obvious polish.
- Flipbook flow: presets carry rows/cols/FPS, but import helpers and sprite slicing UX are still to come.
- Pooling & spawn rules: stubbed/roadmapped.
- Visual library browser with thumbnail grid, folder dropdown, and Preview/Place actions.
- Module animation (Emission/Size/Speed/Color) with robust 2021-friendly bindings.
- Flipbook importer (rows/cols slicing + material hookup).
- Pooling UI (prewarm/auto-despawn).
- Strict structure validator and JSON import/export for presets.
Here’s a concise script structure diagram outline for the Unity FX tool (Editor-side only). It maps responsibilities, key APIs, and dependencies between scripts so anyone can see how the pieces fit.
Top-level overview
FXToolWindow (EditorWindow)
Role: Main entry point UI – browse presets, spawn prefabs, save prefabs, key basic motion.
- 
Lists FXPresetassets fromAssets/FXTool/Presets, duplicate/ping, pick active preset.
- 
Buttons: Create From Preset, Save As Prefab (calls FXPresetApplier).
- 
“Tracks” pane: keys position on the spawned root via FXTrackManager.
- 
Depends on: FXPreset,FXPresetApplier,FXTrackManager,FXFolders.
- 
Key code path (library + key): 
[MenuItem("Tools/Particles/FXTool")] → ShowWindow()
DrawLibrary() → FindAssets("t:FXPreset") … select/duplicate
DrawInspectorAndTracks() → CreateFromPreset(), SaveAsPrefab()
→ FXTrackManager.EnsureAnimator/EnsureClip/KeyTransformPosition()
FXPreset (ScriptableObject)
Role: Source of truth for particle settings & identity.
- 
Sections: Identity, Main, Emission, Shape, Renderer/Material/Sorting, Texture Sheet (Flipbook). 
- 
Referenced by FXPresetApplierto build a concrete PS.
- 
Key fields: duration/looping/lifetime/speed/size, rateOverTime/bursts, shape/radius/angle, material/sorting, flipbook tiles & fps. 
- 
Snippet: 
FXPresetApplier (static utility)
Role: Convert a FXPreset into a scene object (root + child PS) and save as prefab.
- 
Builds named root & child using FXNaming; createsParticleSystem.
- 
Applies preset values to Main/Emission/Shape/Renderer; optional Texture Sheet Animation. 
- 
Saves to Assets/FXTool/Prefabs/<name>.prefab.
- 
Snippet: create & apply + flipbook + save. 
FXTrackManager (static API)
Role: Minimal “tracks” layer – ensures Animator/Clip; keys Transform.position curves.
- 
Creates/assigns AnimatorControllernext to the prefab folder; ensures named clip.
- 
Keys m_LocalPosition.{x,y,z}at time = frame/fps.
- 
Extensible later for PS module animation. 
- 
Snippet: ensure & key. 
FXRuntimeThumbCapturer (MonoBehaviour – Editor guarded)
Role: PlayMode helper that auto-captures thumbnails for any list of prefab paths.
- 
Reads list from EditorPrefs(GUIDs or paths), spawns prefabs in front of Camera.main, warms PS, renders to RT, saves 256px PNG toAssets/FXTool/Cache/ParticleThumbs/<prefabGUID>.png, imports with sane settings.
- 
Cleans up and stops Play Mode when done. 
- 
Snippet: instantiate → warm → capture → write PNG → stop. 
FXLibraryMaterialTool (EditorWindow)
Role: Plain-English URP material builder for FX (independent of PS).
- 
Inputs: Usage (Sprite, Billboard, Trails, UI), Blend (Alpha/Additive/Premultiplied/Multiply/Cutout), toggles (Double-Sided, ZWrite, Shadows, Emission), Base Map + Color. 
- 
Writes .mattoAssets/FXTool/Materials/<Category>/<Name>.mat, pings the asset.
- 
Calls FXURPMaterialFactory.CreateOrUpdate(...)under the hood.
- 
Snippet: UI → Create/Update call. 
FXURPMaterialFactory (static)
Role: Centralizes URP surface/blend/keyword setup.
- 
Applies Src/Dst blend, alpha variants, Cutout via _ALPHATEST_ON, Premultiplied via _ALPHAPREMULTIPLY_ON, toggles _SURFACE_TYPE_TRANSPARENT.
- 
Called only by FXLibraryMaterialTool.
- 
Snippet (keywords & blends): 
FXNaming & FXFolders (static support)
Role: Consistent names and folder structure for everything.
- 
FXNaming.BuildChildName(category,preset,role,i)→FX_<Cat>_<Preset>_<Role>_##
- 
FXFolders.EnsureAll()createsAssets/FXTool/{Presets,Prefabs,Thumbnails,Materials,Textures}.
- 
Snippet: naming + ensure folders. 
Dependency graph (editor)
FXToolWindow
 ├─ uses → FXPreset (list/select/duplicate)
 ├─ calls → FXPresetApplier (Create From Preset / Save As Prefab)
 └─ calls → FXTrackManager (EnsureAnimator, EnsureClip, KeyTransformPosition)
FXPresetApplier
 ├─ reads → FXPreset (values)
 ├─ uses → FXNaming (names), FXFolders (paths)
 └─ writes → Prefab asset
FXTrackManager
 └─ writes → AnimatorController + AnimationClip (curves on Transform)
FXLibraryMaterialTool
 └─ calls → FXURPMaterialFactory (CreateOrUpdate material)
FXRuntimeThumbCapturer (Play Mode, UNITY_EDITOR)
 ├─ reads → EditorPrefs capture list
 ├─ loads → Prefabs by path
 ├─ uses → Camera.main for RT capture
 └─ writes → PNG cache (GUID-keyed), reimports Texture
 






 Render test:
Render test:

