浏览代码

Added fireworks example (#45)

* Added confetti example

* Moved start_firework function from module to script.

Also, some fixes of typos and emmitters materials

* Firewirks. Added  some comments. Remove unnesesary code

* Fireworks. fix wrong self

* Updated instructions file

* Fix instruction in fireworks example
Iurii Baukin 10 月之前
父节点
当前提交
d8885254fb

二进制
assets/images/fireworks/fw_circle_01.png


二进制
assets/images/fireworks/fw_light_01.png


二进制
assets/images/fireworks/fw_star_01.png


二进制
assets/images/fireworks/fw_trace_01.png


二进制
assets/images/fireworks/fw_trace_02.png


+ 15 - 0
assets/sprites.atlas

@@ -73,6 +73,21 @@ images {
 images {
   image: "/assets/images/confetti/confetti_rectangle.png"
 }
+images {
+  image: "/assets/images/fireworks/fw_star_01.png"
+}
+images {
+  image: "/assets/images/fireworks/fw_circle_01.png"
+}
+images {
+  image: "/assets/images/fireworks/fw_light_01.png"
+}
+images {
+  image: "/assets/images/fireworks/fw_trace_01.png"
+}
+images {
+  image: "/assets/images/fireworks/fw_trace_02.png"
+}
 images {
   image: "/assets/images/bar_round_large_grey.png"
 }

+ 1 - 1
examples/_main/examples.lua

@@ -16,7 +16,7 @@ examples["gui"] = {
 }
 examples["input"] = { "move", "text", "down_duration", "mouse_and_touch" }
 examples["material"] = { "vertexcolor", { name = "unlit", nobg = true }, "uvgradient", "noise", { name = "screenspace", nobg = true } }
-examples["particles"] = { "confetti", "particlefx", "modifiers", "fire_and_smoke" }
+examples["particles"] = { "confetti", "particlefx", "modifiers", "fire_and_smoke", "fireworks" }
 examples["sound"] = { "music", "fade_in_out", "panning" }
 examples["render"] = { "camera", { name = "orbit_camera", nobg = true }, "screen_to_world" }
 examples["debug"] = { "physics", "profile" }

+ 6 - 0
examples/_main/loader.go

@@ -442,6 +442,12 @@ embedded_components {
   data: "collection: \"/examples/particles/confetti/confetti.collection\"\n"
   ""
 }
+embedded_components {
+  id: "particles/fireworks"
+  type: "collectionproxy"
+  data: "collection: \"/examples/particles/fireworks/fireworks.collection\"\n"
+  ""
+}
 embedded_components {
   id: "gui/healthbar"
   type: "collectionproxy"

+ 89 - 0
examples/particles/fireworks/fireworks.collection

@@ -0,0 +1,89 @@
+name: "fireworks"
+scale_along_z: 0
+embedded_instances {
+  id: "gameobject"
+  data: "components {\n"
+  "  id: \"script\"\n"
+  "  component: \"/examples/particles/fireworks/fireworks.script\"\n"
+  "}\n"
+  "embedded_components {\n"
+  "  id: \"blue_trail_factory\"\n"
+  "  type: \"factory\"\n"
+  "  data: \"prototype: \\\"/examples/particles/fireworks/fw_trail_blue.go\\\"\\n"
+  "\"\n"
+  "}\n"
+  "embedded_components {\n"
+  "  id: \"green_trail_factory\"\n"
+  "  type: \"factory\"\n"
+  "  data: \"prototype: \\\"/examples/particles/fireworks/fw_trail_green.go\\\"\\n"
+  "\"\n"
+  "}\n"
+  "embedded_components {\n"
+  "  id: \"red_trail_factory\"\n"
+  "  type: \"factory\"\n"
+  "  data: \"prototype: \\\"/examples/particles/fireworks/fw_trail_red.go\\\"\\n"
+  "\"\n"
+  "}\n"
+  "embedded_components {\n"
+  "  id: \"blue_splat_factory\"\n"
+  "  type: \"factory\"\n"
+  "  data: \"prototype: \\\"/examples/particles/fireworks/fw_splat_blue.go\\\"\\n"
+  "\"\n"
+  "}\n"
+  "embedded_components {\n"
+  "  id: \"red_splat_factory\"\n"
+  "  type: \"factory\"\n"
+  "  data: \"prototype: \\\"/examples/particles/fireworks/fw_splat_red.go\\\"\\n"
+  "\"\n"
+  "}\n"
+  "embedded_components {\n"
+  "  id: \"green_splat_factory\"\n"
+  "  type: \"factory\"\n"
+  "  data: \"prototype: \\\"/examples/particles/fireworks/fw_splat_green.go\\\"\\n"
+  "\"\n"
+  "}\n"
+  ""
+  position {
+    x: 360.0
+    y: 50.0
+  }
+}
+embedded_instances {
+  id: "instructions"
+  data: "embedded_components {\n"
+  "  id: \"label\"\n"
+  "  type: \"label\"\n"
+  "  data: \"size {\\n"
+  "  x: 128.0\\n"
+  "  y: 32.0\\n"
+  "}\\n"
+  "color {\\n"
+  "  x: 0.0\\n"
+  "  y: 0.5647059\\n"
+  "  z: 0.99215686\\n"
+  "}\\n"
+  "outline {\\n"
+  "  x: 1.0\\n"
+  "  y: 1.0\\n"
+  "  z: 1.0\\n"
+  "}\\n"
+  "shadow {\\n"
+  "  x: 1.0\\n"
+  "  y: 1.0\\n"
+  "  z: 1.0\\n"
+  "}\\n"
+  "text: \\\"Tap to start random firework\\\"\\n"
+  "font: \\\"/assets/text48.font\\\"\\n"
+  "material: \\\"/builtins/fonts/label.material\\\"\\n"
+  "\"\n"
+  "  scale {\n"
+  "    x: 0.5\n"
+  "    y: 0.5\n"
+  "  }\n"
+  "}\n"
+  ""
+  position {
+    x: 360.0
+    y: 38.0
+  }
+}

+ 16 - 0
examples/particles/fireworks/fireworks.md

@@ -0,0 +1,16 @@
+---
+title: Particle effect example - fireworks
+brief: This example shows a fireworks effect made with particles.
+scripts: fireworks.script
+---
+
+This effect consists of two particle effects: trail and bang. In this example there are three different colors, which could be easily changed in particle emitters settings.
+
+
+The main script `fireworks.script` spawns the fireworks trail particlefx on startup or when any key is pressed or the mouse button is clicked. It also has a timer that spawns the particlefx in a loop with a 3 second delay. 
+
+To start effect:
+- add factories for splat and trail particles;
+- call "start_fireworks" method with parameters (time, start point, speed vector).
+
+Images for particles are taken from Kenney Particle Pack.

+ 94 - 0
examples/particles/fireworks/fireworks.script

@@ -0,0 +1,94 @@
+local colors = {"red", "green", "blue"} -- list of existing fireworks colors
+local instances = {} -- list of active fireworks instances
+
+local _tension = 0.9 -- emulation of air tension. More value leads to faster deceleration
+local _gravity = 980 -- gravity, measuring in mm/sq.s.
+
+local function start_fireworks(trail_id, bang_id, start_pos, speed, time, gravity, tension)
+	go.set_position(start_pos, trail_id)
+	particlefx.play(trail_id)
+	local m = {
+		update = function(self, dt)
+			if self.time > 0 then
+				local prev_pos = vmath.vector3(self.start_pos)
+				self.start_pos.x = self.start_pos.x + self.speed.x*dt
+				self.start_pos.y = self.start_pos.y + self.speed.y*dt
+
+				local triangle = vmath.vector3(prev_pos.x - start_pos.x, prev_pos.y - start_pos.y, 0)
+				local angle = math.atan2(triangle.y, triangle.x)
+				self.speed.x = self.speed.x - self.speed.x * self.tension*dt
+				self.speed.y = self.speed.y - self.speed.y * self.tension*dt - self.gravity*dt
+
+				go.set_position(self.start_pos, self.trail)
+				go.set_rotation(vmath.quat_rotation_z(angle+math.pi/2), self.trail)
+				if self.time > 0 then
+					go.set_scale(self.time, self.trail)
+				end
+
+			elseif self.time <= 0 and not self.is_stopped then
+				self.is_stopped = true
+				particlefx.stop(self.trail, { clear = true })
+				go.set_position(self.start_pos, self.bang)
+				particlefx.play(self.bang)
+			elseif self.time <= -1.5 and self.bang  then
+				go.delete(self.bang)
+				self.bang = nil
+			end
+			self.time = self.time - dt
+		end,
+		start_pos = start_pos,
+		time = time,
+		speed = speed,
+		gravity = gravity or _gravity,
+		tension = tension or _tension,
+		trail = trail_id,
+		bang = bang_id
+	}
+
+	return m
+end
+
+local function single_shot()
+	if #instances > 5 then
+		return
+	end
+	local color = colors[math.random(1, #colors)]
+	local splat = factory.create("#"..color.."_splat_factory")
+	local trail = factory.create("#"..color.."_trail_factory")
+
+	local strength = 1000+math.random()*600 		-- scalar value of speed
+	local angle = (-0.2+math.random()*0.4)*math.pi	-- angle beetween central vertical line and trail
+	
+	local pos = vmath.vector3(360-math.sin(angle)*350, 0, 0)
+	local speed = vmath.vector3(strength*math.sin(angle), strength*math.cos(angle), 0)
+	table.insert(instances, 
+		start_fireworks(trail, splat, 
+			pos, speed, 
+			1.2+math.random()*0.5
+		)
+	)
+end
+
+function init(self)
+	single_shot()
+
+	timer.delay(3, true, single_shot) 
+
+	msg.post(".", "acquire_input_focus")
+end
+
+function update(self, dt)
+	for i, val in ipairs(instances) do
+		if not val.bang then
+			table.remove(instances, i)
+		else
+			val:update(dt)
+		end
+	end
+end
+
+function on_input(self, action_id, action)
+	if action.pressed then 
+		single_shot()
+	end
+end

+ 4 - 0
examples/particles/fireworks/fw_splat_blue.go

@@ -0,0 +1,4 @@
+components {
+  id: "tile_splat_blue"
+  component: "/examples/particles/fireworks/fw_splat_blue.particlefx"
+}

+ 1134 - 0
examples/particles/fireworks/fw_splat_blue.particlefx

@@ -0,0 +1,1134 @@
+emitters {
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.2
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_01"
+  material: "/builtins/materials/particlefx.material"
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 150
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 10000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_X
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Y
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+    spread: 0.5
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 200.0
+    }
+    spread: 20.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 3.0
+    }
+    spread: 0.5
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.12941177
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.3019608
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.7019608
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: -0.5
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.42859232
+      t_x: 0.024429077
+      t_y: 0.99970156
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.12233837
+    }
+    points {
+      x: 0.08273616
+      y: 2.0447288
+      t_x: 0.14027841
+      t_y: -0.9901121
+    }
+    points {
+      x: 0.26107493
+      y: 0.40814364
+      t_x: 0.27199933
+      t_y: -0.96229744
+    }
+    points {
+      x: 0.38371336
+      y: -0.036952645
+      t_x: 0.9262474
+      t_y: 0.3769161
+    }
+    points {
+      x: 0.7171824
+      y: 0.16613448
+      t_x: 0.64932483
+      t_y: 0.76051116
+    }
+    points {
+      x: 1.0
+      y: -0.20678474
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 10.92268
+    }
+    points {
+      x: 0.105944626
+      y: 6.334795
+      t_x: 0.34915915
+      t_y: -0.93706346
+    }
+    points {
+      x: 0.30114007
+      y: 2.4454107
+      t_x: 0.14935292
+      t_y: -0.98878396
+    }
+    points {
+      x: 1.0
+      y: 1.5742594
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 15.942318
+    }
+    points {
+      x: 0.08151466
+      y: 4.3566136
+      t_x: 0.039131545
+      t_y: -0.9992341
+    }
+    points {
+      x: 0.51758957
+      y: -0.68891436
+      t_x: 0.96546835
+      t_y: -0.26052028
+    }
+    points {
+      x: 0.77581435
+      y: 0.08814634
+      t_x: 0.91469765
+      t_y: 0.40413892
+    }
+    points {
+      x: 1.0
+      y: -0.5702326
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_RADIAL
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 0.0
+      }
+    }
+    properties {
+      key: MODIFIER_KEY_MAX_DISTANCE
+      points {
+        y: 30.0
+      }
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_ACCELERATION
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 50.0
+      }
+    }
+  }
+  duration_spread: 0.1
+  stretch_with_velocity: true
+}
+emitters {
+  id: "emitter1"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.2
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_star_01"
+  material: "/builtins/materials/particlefx.material"
+  particle_orientation: PARTICLE_ORIENTATION_ANGULAR_VELOCITY
+  max_particle_count: 30
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 10000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_X
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Y
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Z
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+    spread: 0.3
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 300.0
+    }
+    spread: 20.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 3.0
+    }
+    spread: 2.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.12941177
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.3019608
+    }
+    spread: 0.1
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.7019608
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ROTATION
+    points {
+      y: 0.0
+    }
+    spread: 90.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ANGULAR_VELOCITY
+    points {
+      y: 10.0
+    }
+    spread: 5.0
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 7.6625104
+    }
+    points {
+      x: 1.0
+      y: 10.478123
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+    points {
+      x: 1.0
+      y: 0.86500204
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+    points {
+      x: 1.0
+      y: 2.7463124
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+    points {
+      x: 1.0
+      y: 10.386523
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.11957385
+      t_x: 0.9949079
+      t_y: 0.10078809
+    }
+    points {
+      x: 0.20659609
+      y: 1.245942
+      t_x: 0.23804364
+      t_y: -0.97125447
+    }
+    points {
+      x: 0.6756515
+      y: 0.6910322
+      t_x: 0.7841117
+      t_y: -0.6206198
+    }
+    points {
+      x: 1.0
+      y: 0.015711093
+      t_x: 0.56921566
+      t_y: -0.82218826
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ANGULAR_VELOCITY
+    points {
+      y: 15.0
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_ACCELERATION
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 10.0
+      }
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_RADIAL
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: -250.0
+        t_x: 0.003265428
+        t_y: -0.9999947
+      }
+      points {
+        x: 1.0
+        y: -8.693188
+        t_x: 7.5198716E-4
+        t_y: 0.9999997
+      }
+    }
+    properties {
+      key: MODIFIER_KEY_MAX_DISTANCE
+      points {
+        y: 500.0
+      }
+    }
+  }
+  stretch_with_velocity: true
+}
+emitters {
+  id: "emitter4"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.2
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_01"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 150
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 10000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_X
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Y
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+    spread: 0.1
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 300.0
+    }
+    points {
+      x: 0.11107492
+      y: 33.759693
+      t_x: 0.004660093
+      t_y: -0.99998915
+    }
+    points {
+      x: 1.0
+      y: 10.3574295
+    }
+    spread: 20.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 3.0
+    }
+    spread: 0.5
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.050980393
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.29803923
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: -0.5
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.42859232
+      t_x: 0.024429077
+      t_y: 0.99970156
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: -0.0012211404
+    }
+    points {
+      x: 0.08175896
+      y: 2.0447288
+      t_x: 0.14027841
+      t_y: -0.9901121
+    }
+    points {
+      x: 0.18749742
+      y: 0.12487222
+      t_x: 0.27199933
+      t_y: -0.96229744
+    }
+    points {
+      x: 0.6348273
+      y: -0.031716812
+      t_x: 0.29903722
+      t_y: 0.95424145
+    }
+    points {
+      x: 1.0
+      y: 0.009376409
+      t_x: 0.3381512
+      t_y: -0.9410918
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 6.6410265
+    }
+    points {
+      x: 0.10692182
+      y: 4.3885884
+      t_x: 0.34915915
+      t_y: -0.93706346
+    }
+    points {
+      x: 1.0
+      y: 0.22707473
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 15.942318
+    }
+    points {
+      x: 0.08151466
+      y: 4.3566136
+      t_x: 0.039131545
+      t_y: -0.9992341
+    }
+    points {
+      x: 0.5713355
+      y: 0.29830235
+      t_x: 0.96546835
+      t_y: -0.26052028
+    }
+    points {
+      x: 1.0
+      y: -0.5702326
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_ACCELERATION
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 100.0
+      }
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_RADIAL
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 0.0
+      }
+    }
+    properties {
+      key: MODIFIER_KEY_MAX_DISTANCE
+      points {
+        y: 30.0
+      }
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+  duration_spread: 0.1
+  stretch_with_velocity: true
+}
+emitters {
+  id: "emitter2"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.1
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_circle_01"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  max_particle_count: 2
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.12941177
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.3019608
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.7019608
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X
+    points {
+      y: 2.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: 2.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.0050403317
+      t_x: 0.07567246
+      t_y: 0.9971327
+    }
+    points {
+      x: 0.13013029
+      y: 1.0516063
+      t_x: 0.22336559
+      t_y: 0.9747347
+    }
+    points {
+      x: 0.31872964
+      y: 0.12317026
+      t_x: 0.44993034
+      t_y: -0.89306366
+    }
+    points {
+      x: 0.6131107
+      y: -0.03477873
+      t_x: 0.18202555
+      t_y: -0.9832938
+    }
+    points {
+      x: 0.8332248
+      y: 0.0568189
+      t_x: 0.8397494
+      t_y: 0.5429742
+    }
+    points {
+      x: 1.0
+      y: 0.0
+      t_x: 0.99995637
+      t_y: -0.009341509
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}
+emitters {
+  id: "emitter3"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.1
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_light_01"
+  material: "/builtins/materials/particlefx.material"
+  max_particle_count: 1
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 1000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.19
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.3019608
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.7019608
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X
+    points {
+      y: 2.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: 2.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 9.531683E-5
+      t_x: 0.48855478
+      t_y: 0.8725332
+    }
+    points {
+      x: 0.014885994
+      y: 1.0171621
+      t_x: 0.06842353
+      t_y: 0.99765635
+    }
+    points {
+      x: 0.31872964
+      y: 0.12317026
+      t_x: 0.44993034
+      t_y: -0.89306366
+    }
+    points {
+      x: 0.5886808
+      y: -0.99066126
+      t_x: 0.18202555
+      t_y: -0.9832938
+    }
+    points {
+      x: 0.83127034
+      y: -0.3613797
+      t_x: 0.8397494
+      t_y: 0.5429742
+    }
+    points {
+      x: 1.0
+      y: 0.0
+      t_x: 0.99995637
+      t_y: -0.009341509
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2022469
+      y: 3.2772617
+    }
+    points {
+      x: 0.38703388
+      y: 1.1423699
+      t_x: 0.3538746
+      t_y: -0.9352929
+    }
+    points {
+      x: 1.0
+      y: 0.014935664
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2027355
+      y: 3.3074327
+      t_x: 0.92783904
+      t_y: -0.3729809
+    }
+    points {
+      x: 0.38931102
+      y: 1.1156069
+      t_x: 0.26103032
+      t_y: -0.9653306
+    }
+    points {
+      x: 1.0
+      y: 0.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}
+emitters {
+  id: "emitter5"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.1
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_light_01"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  max_particle_count: 1
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 1000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 30.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.12941177
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.3019608
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.7019608
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X
+    points {
+      y: 2.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: 2.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 9.531683E-5
+      t_x: 0.48855478
+      t_y: 0.8725332
+    }
+    points {
+      x: 0.014885994
+      y: 1.0171621
+      t_x: 0.06842353
+      t_y: 0.99765635
+    }
+    points {
+      x: 0.31872964
+      y: 0.12317026
+      t_x: 0.44993034
+      t_y: -0.89306366
+    }
+    points {
+      x: 0.5886808
+      y: -0.99066126
+      t_x: 0.18202555
+      t_y: -0.9832938
+    }
+    points {
+      x: 0.83127034
+      y: -0.3613797
+      t_x: 0.8397494
+      t_y: 0.5429742
+    }
+    points {
+      x: 1.0
+      y: 0.0
+      t_x: 0.99995637
+      t_y: -0.009341509
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2022469
+      y: 3.2772617
+    }
+    points {
+      x: 0.38703388
+      y: 1.1423699
+      t_x: 0.3538746
+      t_y: -0.9352929
+    }
+    points {
+      x: 1.0
+      y: 0.014935664
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2027355
+      y: 3.3074327
+      t_x: 0.92783904
+      t_y: -0.3729809
+    }
+    points {
+      x: 0.38931102
+      y: 1.1156069
+      t_x: 0.26103032
+      t_y: -0.9653306
+    }
+    points {
+      x: 1.0
+      y: 0.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}

+ 4 - 0
examples/particles/fireworks/fw_splat_green.go

@@ -0,0 +1,4 @@
+components {
+  id: "tile_splat_green"
+  component: "/examples/particles/fireworks/fw_splat_green.particlefx"
+}

+ 1150 - 0
examples/particles/fireworks/fw_splat_green.particlefx

@@ -0,0 +1,1150 @@
+emitters {
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.2
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_01"
+  material: "/builtins/materials/particlefx.material"
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 150
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 10000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_X
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Y
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+    spread: 0.5
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 200.0
+    }
+    spread: 20.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 3.0
+    }
+    spread: 0.5
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.2039216
+    }
+    spread: 0.2
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 1.0
+    }
+    spread: 0.05
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.039215688
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: -0.5
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.42859232
+      t_x: 0.024429077
+      t_y: 0.99970156
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.12233837
+    }
+    points {
+      x: 0.08273616
+      y: 2.0447288
+      t_x: 0.14027841
+      t_y: -0.9901121
+    }
+    points {
+      x: 0.26107493
+      y: 0.40814364
+      t_x: 0.27199933
+      t_y: -0.96229744
+    }
+    points {
+      x: 0.38371336
+      y: -0.036952645
+      t_x: 0.9262474
+      t_y: 0.3769161
+    }
+    points {
+      x: 0.7171824
+      y: 0.16613448
+      t_x: 0.64932483
+      t_y: 0.76051116
+    }
+    points {
+      x: 1.0
+      y: -0.20678474
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 10.92268
+    }
+    points {
+      x: 0.105944626
+      y: 6.334795
+      t_x: 0.34915915
+      t_y: -0.93706346
+    }
+    points {
+      x: 0.30114007
+      y: 2.4454107
+      t_x: 0.14935292
+      t_y: -0.98878396
+    }
+    points {
+      x: 1.0
+      y: 1.5742594
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 15.942318
+    }
+    points {
+      x: 0.08151466
+      y: 4.3566136
+      t_x: 0.039131545
+      t_y: -0.9992341
+    }
+    points {
+      x: 0.51758957
+      y: -0.68891436
+      t_x: 0.96546835
+      t_y: -0.26052028
+    }
+    points {
+      x: 0.77581435
+      y: 0.08814634
+      t_x: 0.91469765
+      t_y: 0.40413892
+    }
+    points {
+      x: 1.0
+      y: -0.5702326
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_RADIAL
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 0.0
+      }
+    }
+    properties {
+      key: MODIFIER_KEY_MAX_DISTANCE
+      points {
+        y: 30.0
+      }
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_ACCELERATION
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 50.0
+      }
+    }
+  }
+  duration_spread: 0.1
+  stretch_with_velocity: true
+}
+emitters {
+  id: "emitter1"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.2
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_star_01"
+  material: "/builtins/materials/particlefx.material"
+  particle_orientation: PARTICLE_ORIENTATION_ANGULAR_VELOCITY
+  max_particle_count: 30
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 10000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_X
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Y
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Z
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+    spread: 0.3
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 300.0
+    }
+    spread: 20.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 3.0
+    }
+    spread: 2.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.2
+    }
+    spread: 0.3
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 1.0
+    }
+    spread: 0.1
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.1
+    }
+    spread: 0.05
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ROTATION
+    points {
+      y: 0.0
+    }
+    spread: 90.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ANGULAR_VELOCITY
+    points {
+      y: 10.0
+    }
+    spread: 5.0
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 7.6625104
+    }
+    points {
+      x: 1.0
+      y: 10.478123
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+    points {
+      x: 1.0
+      y: 11.4782715
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+    points {
+      x: 1.0
+      y: 2.8707824
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+    points {
+      x: 1.0
+      y: 2.8707824
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.11957385
+      t_x: 0.9949079
+      t_y: 0.10078809
+    }
+    points {
+      x: 0.20659609
+      y: 1.245942
+      t_x: 0.23804364
+      t_y: -0.97125447
+    }
+    points {
+      x: 0.6756515
+      y: 0.6910322
+      t_x: 0.7841117
+      t_y: -0.6206198
+    }
+    points {
+      x: 1.0
+      y: 0.015711093
+      t_x: 0.56921566
+      t_y: -0.82218826
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ANGULAR_VELOCITY
+    points {
+      y: 15.0
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_ACCELERATION
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 10.0
+      }
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_RADIAL
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: -250.0
+        t_x: 0.003265428
+        t_y: -0.9999947
+      }
+      points {
+        x: 1.0
+        y: -8.693188
+        t_x: 7.5198716E-4
+        t_y: 0.9999997
+      }
+    }
+    properties {
+      key: MODIFIER_KEY_MAX_DISTANCE
+      points {
+        y: 500.0
+      }
+    }
+  }
+  stretch_with_velocity: true
+}
+emitters {
+  id: "emitter4"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.2
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_01"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 150
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 10000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_X
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Y
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+    spread: 0.1
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 300.0
+    }
+    points {
+      x: 0.11107492
+      y: 33.759693
+      t_x: 0.004660093
+      t_y: -0.99998915
+    }
+    points {
+      x: 1.0
+      y: 10.3574295
+    }
+    spread: 20.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 3.0
+    }
+    spread: 0.5
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.2
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.2
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: -0.5
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.42859232
+      t_x: 0.024429077
+      t_y: 0.99970156
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+    points {
+      x: 1.0
+      y: 0.60587674
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 0.21502538
+    }
+    points {
+      x: 1.0
+      y: 1.6762574
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 0.24819332
+    }
+    points {
+      x: 1.0
+      y: 1.7094253
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: -0.0012211404
+    }
+    points {
+      x: 0.08175896
+      y: 2.0447288
+      t_x: 0.14027841
+      t_y: -0.9901121
+    }
+    points {
+      x: 0.1985342
+      y: -1.6654266
+      t_x: 0.27199933
+      t_y: -0.96229744
+    }
+    points {
+      x: 0.63583064
+      y: -0.031716812
+      t_x: 0.29903722
+      t_y: 0.95424145
+    }
+    points {
+      x: 1.0
+      y: 0.009376409
+      t_x: 0.3381512
+      t_y: -0.9410918
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 6.6410265
+    }
+    points {
+      x: 0.10692182
+      y: 4.3885884
+      t_x: 0.34915915
+      t_y: -0.93706346
+    }
+    points {
+      x: 1.0
+      y: 0.22707473
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 15.942318
+    }
+    points {
+      x: 0.08151466
+      y: 4.3566136
+      t_x: 0.039131545
+      t_y: -0.9992341
+    }
+    points {
+      x: 0.5713355
+      y: 0.29830235
+      t_x: 0.96546835
+      t_y: -0.26052028
+    }
+    points {
+      x: 1.0
+      y: -0.5702326
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_ACCELERATION
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 100.0
+      }
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_RADIAL
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 0.0
+      }
+    }
+    properties {
+      key: MODIFIER_KEY_MAX_DISTANCE
+      points {
+        y: 30.0
+      }
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+  duration_spread: 0.1
+  stretch_with_velocity: true
+}
+emitters {
+  id: "emitter2"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.1
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_circle_01"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  max_particle_count: 2
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.2039216
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.039215688
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X
+    points {
+      y: 2.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: 2.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.0050403317
+      t_x: 0.07567246
+      t_y: 0.9971327
+    }
+    points {
+      x: 0.13013029
+      y: 1.0516063
+      t_x: 0.22336559
+      t_y: 0.9747347
+    }
+    points {
+      x: 0.31872964
+      y: 0.12317026
+      t_x: 0.44993034
+      t_y: -0.89306366
+    }
+    points {
+      x: 0.6131107
+      y: -0.03477873
+      t_x: 0.18202555
+      t_y: -0.9832938
+    }
+    points {
+      x: 0.8332248
+      y: 0.0568189
+      t_x: 0.8397494
+      t_y: 0.5429742
+    }
+    points {
+      x: 1.0
+      y: 0.0
+      t_x: 0.99995637
+      t_y: -0.009341509
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}
+emitters {
+  id: "emitter3"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.1
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_light_01"
+  material: "/builtins/materials/particlefx.material"
+  max_particle_count: 1
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 1000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.4313726
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.30980393
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X
+    points {
+      y: 2.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: 2.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 9.531683E-5
+      t_x: 0.48855478
+      t_y: 0.8725332
+    }
+    points {
+      x: 0.014885994
+      y: 1.0171621
+      t_x: 0.06842353
+      t_y: 0.99765635
+    }
+    points {
+      x: 0.31872964
+      y: 0.12317026
+      t_x: 0.44993034
+      t_y: -0.89306366
+    }
+    points {
+      x: 0.5886808
+      y: -0.99066126
+      t_x: 0.18202555
+      t_y: -0.9832938
+    }
+    points {
+      x: 0.83127034
+      y: -0.3613797
+      t_x: 0.8397494
+      t_y: 0.5429742
+    }
+    points {
+      x: 1.0
+      y: 0.0
+      t_x: 0.99995637
+      t_y: -0.009341509
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2022469
+      y: 3.2772617
+    }
+    points {
+      x: 0.38703388
+      y: 1.1423699
+      t_x: 0.3538746
+      t_y: -0.9352929
+    }
+    points {
+      x: 1.0
+      y: 0.014935664
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2027355
+      y: 3.3074327
+      t_x: 0.92783904
+      t_y: -0.3729809
+    }
+    points {
+      x: 0.38931102
+      y: 1.1156069
+      t_x: 0.26103032
+      t_y: -0.9653306
+    }
+    points {
+      x: 1.0
+      y: 0.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}
+emitters {
+  id: "emitter5"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.1
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_light_01"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  max_particle_count: 1
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 1000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 30.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.4313726
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.30980393
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X
+    points {
+      y: 2.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: 2.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 9.531683E-5
+      t_x: 0.48855478
+      t_y: 0.8725332
+    }
+    points {
+      x: 0.014885994
+      y: 1.0171621
+      t_x: 0.06842353
+      t_y: 0.99765635
+    }
+    points {
+      x: 0.31872964
+      y: 0.12317026
+      t_x: 0.44993034
+      t_y: -0.89306366
+    }
+    points {
+      x: 0.5886808
+      y: -0.99066126
+      t_x: 0.18202555
+      t_y: -0.9832938
+    }
+    points {
+      x: 0.83127034
+      y: -0.3613797
+      t_x: 0.8397494
+      t_y: 0.5429742
+    }
+    points {
+      x: 1.0
+      y: 0.0
+      t_x: 0.99995637
+      t_y: -0.009341509
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2022469
+      y: 3.2772617
+    }
+    points {
+      x: 0.38703388
+      y: 1.1423699
+      t_x: 0.3538746
+      t_y: -0.9352929
+    }
+    points {
+      x: 1.0
+      y: 0.014935664
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2027355
+      y: 3.3074327
+      t_x: 0.92783904
+      t_y: -0.3729809
+    }
+    points {
+      x: 0.38931102
+      y: 1.1156069
+      t_x: 0.26103032
+      t_y: -0.9653306
+    }
+    points {
+      x: 1.0
+      y: 0.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}

+ 4 - 0
examples/particles/fireworks/fw_splat_red.go

@@ -0,0 +1,4 @@
+components {
+  id: "tile_splat_red"
+  component: "/examples/particles/fireworks/fw_splat_red.particlefx"
+}

+ 1150 - 0
examples/particles/fireworks/fw_splat_red.particlefx

@@ -0,0 +1,1150 @@
+emitters {
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.2
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_01"
+  material: "/builtins/materials/particlefx.material"
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 150
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 10000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_X
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Y
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+    spread: 0.5
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 200.0
+    }
+    spread: 20.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 3.0
+    }
+    spread: 0.5
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 1.0
+    }
+    spread: 0.2
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.20392157
+    }
+    spread: 0.05
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.039215688
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: -0.5
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.42859232
+      t_x: 0.024429077
+      t_y: 0.99970156
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.12233837
+    }
+    points {
+      x: 0.08273616
+      y: 2.0447288
+      t_x: 0.14027841
+      t_y: -0.9901121
+    }
+    points {
+      x: 0.26107493
+      y: 0.40814364
+      t_x: 0.27199933
+      t_y: -0.96229744
+    }
+    points {
+      x: 0.38371336
+      y: -0.036952645
+      t_x: 0.9262474
+      t_y: 0.3769161
+    }
+    points {
+      x: 0.7171824
+      y: 0.16613448
+      t_x: 0.64932483
+      t_y: 0.76051116
+    }
+    points {
+      x: 1.0
+      y: -0.20678474
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 10.92268
+    }
+    points {
+      x: 0.105944626
+      y: 6.334795
+      t_x: 0.34915915
+      t_y: -0.93706346
+    }
+    points {
+      x: 0.30114007
+      y: 2.4454107
+      t_x: 0.14935292
+      t_y: -0.98878396
+    }
+    points {
+      x: 1.0
+      y: 1.5742594
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 15.942318
+    }
+    points {
+      x: 0.08151466
+      y: 4.3566136
+      t_x: 0.039131545
+      t_y: -0.9992341
+    }
+    points {
+      x: 0.51758957
+      y: -0.68891436
+      t_x: 0.96546835
+      t_y: -0.26052028
+    }
+    points {
+      x: 0.77581435
+      y: 0.08814634
+      t_x: 0.91469765
+      t_y: 0.40413892
+    }
+    points {
+      x: 1.0
+      y: -0.5702326
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_RADIAL
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 0.0
+      }
+    }
+    properties {
+      key: MODIFIER_KEY_MAX_DISTANCE
+      points {
+        y: 30.0
+      }
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_ACCELERATION
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 50.0
+      }
+    }
+  }
+  duration_spread: 0.1
+  stretch_with_velocity: true
+}
+emitters {
+  id: "emitter1"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.2
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_star_01"
+  material: "/builtins/materials/particlefx.material"
+  particle_orientation: PARTICLE_ORIENTATION_ANGULAR_VELOCITY
+  max_particle_count: 30
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 10000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_X
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Y
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Z
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+    spread: 0.3
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 300.0
+    }
+    spread: 20.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 3.0
+    }
+    spread: 2.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 1.0
+    }
+    spread: 0.3
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.2
+    }
+    spread: 0.1
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.1
+    }
+    spread: 0.05
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ROTATION
+    points {
+      y: 0.0
+    }
+    spread: 90.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ANGULAR_VELOCITY
+    points {
+      y: 10.0
+    }
+    spread: 5.0
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 7.6625104
+    }
+    points {
+      x: 1.0
+      y: 10.478123
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+    points {
+      x: 1.0
+      y: 11.4782715
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+    points {
+      x: 1.0
+      y: 2.8707824
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+    points {
+      x: 1.0
+      y: 2.8707824
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.11957385
+      t_x: 0.9949079
+      t_y: 0.10078809
+    }
+    points {
+      x: 0.20659609
+      y: 1.245942
+      t_x: 0.23804364
+      t_y: -0.97125447
+    }
+    points {
+      x: 0.6756515
+      y: 0.6910322
+      t_x: 0.7841117
+      t_y: -0.6206198
+    }
+    points {
+      x: 1.0
+      y: 0.015711093
+      t_x: 0.56921566
+      t_y: -0.82218826
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ANGULAR_VELOCITY
+    points {
+      y: 15.0
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_ACCELERATION
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 10.0
+      }
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_RADIAL
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: -250.0
+        t_x: 0.003265428
+        t_y: -0.9999947
+      }
+      points {
+        x: 1.0
+        y: -8.693188
+        t_x: 7.5198716E-4
+        t_y: 0.9999997
+      }
+    }
+    properties {
+      key: MODIFIER_KEY_MAX_DISTANCE
+      points {
+        y: 500.0
+      }
+    }
+  }
+  stretch_with_velocity: true
+}
+emitters {
+  id: "emitter4"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.2
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_01"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 150
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 10000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_X
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_SIZE_Y
+    points {
+      y: 20.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+    spread: 0.1
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 300.0
+    }
+    points {
+      x: 0.11107492
+      y: 33.759693
+      t_x: 0.004660093
+      t_y: -0.99998915
+    }
+    points {
+      x: 1.0
+      y: 10.3574295
+    }
+    spread: 20.0
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 3.0
+    }
+    spread: 0.5
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.2
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.2
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: -0.5
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.42859232
+      t_x: 0.024429077
+      t_y: 0.99970156
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+    points {
+      x: 1.0
+      y: 0.60587674
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 0.21502538
+    }
+    points {
+      x: 1.0
+      y: 1.6762574
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 0.24819332
+    }
+    points {
+      x: 1.0
+      y: 1.7094253
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: -0.0012211404
+    }
+    points {
+      x: 0.08175896
+      y: 2.0447288
+      t_x: 0.14027841
+      t_y: -0.9901121
+    }
+    points {
+      x: 0.1985342
+      y: -1.6654266
+      t_x: 0.27199933
+      t_y: -0.96229744
+    }
+    points {
+      x: 0.63583064
+      y: -0.031716812
+      t_x: 0.29903722
+      t_y: 0.95424145
+    }
+    points {
+      x: 1.0
+      y: 0.009376409
+      t_x: 0.3381512
+      t_y: -0.9410918
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 6.6410265
+    }
+    points {
+      x: 0.10692182
+      y: 4.3885884
+      t_x: 0.34915915
+      t_y: -0.93706346
+    }
+    points {
+      x: 1.0
+      y: 0.22707473
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 15.942318
+    }
+    points {
+      x: 0.08151466
+      y: 4.3566136
+      t_x: 0.039131545
+      t_y: -0.9992341
+    }
+    points {
+      x: 0.5713355
+      y: 0.29830235
+      t_x: 0.96546835
+      t_y: -0.26052028
+    }
+    points {
+      x: 1.0
+      y: -0.5702326
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_ACCELERATION
+    rotation {
+      z: 1.0
+      w: 6.123234E-17
+    }
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 100.0
+      }
+    }
+  }
+  modifiers {
+    type: MODIFIER_TYPE_RADIAL
+    properties {
+      key: MODIFIER_KEY_MAGNITUDE
+      points {
+        y: 0.0
+      }
+    }
+    properties {
+      key: MODIFIER_KEY_MAX_DISTANCE
+      points {
+        y: 30.0
+      }
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+  duration_spread: 0.1
+  stretch_with_velocity: true
+}
+emitters {
+  id: "emitter2"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.1
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_circle_01"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  max_particle_count: 2
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.20392157
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.039215688
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X
+    points {
+      y: 2.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: 2.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.0050403317
+      t_x: 0.07567246
+      t_y: 0.9971327
+    }
+    points {
+      x: 0.13013029
+      y: 1.0516063
+      t_x: 0.22336559
+      t_y: 0.9747347
+    }
+    points {
+      x: 0.31872964
+      y: 0.12317026
+      t_x: 0.44993034
+      t_y: -0.89306366
+    }
+    points {
+      x: 0.6131107
+      y: -0.03477873
+      t_x: 0.18202555
+      t_y: -0.9832938
+    }
+    points {
+      x: 0.8332248
+      y: 0.0568189
+      t_x: 0.8397494
+      t_y: 0.5429742
+    }
+    points {
+      x: 1.0
+      y: 0.0
+      t_x: 0.99995637
+      t_y: -0.009341509
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}
+emitters {
+  id: "emitter3"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.1
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_light_01"
+  material: "/builtins/materials/particlefx.material"
+  max_particle_count: 1
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 1000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 60.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.43137255
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.30980393
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X
+    points {
+      y: 2.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: 2.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 9.531683E-5
+      t_x: 0.48855478
+      t_y: 0.8725332
+    }
+    points {
+      x: 0.014885994
+      y: 1.0171621
+      t_x: 0.06842353
+      t_y: 0.99765635
+    }
+    points {
+      x: 0.31872964
+      y: 0.12317026
+      t_x: 0.44993034
+      t_y: -0.89306366
+    }
+    points {
+      x: 0.5886808
+      y: -0.99066126
+      t_x: 0.18202555
+      t_y: -0.9832938
+    }
+    points {
+      x: 0.83127034
+      y: -0.3613797
+      t_x: 0.8397494
+      t_y: 0.5429742
+    }
+    points {
+      x: 1.0
+      y: 0.0
+      t_x: 0.99995637
+      t_y: -0.009341509
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2022469
+      y: 3.2772617
+    }
+    points {
+      x: 0.38703388
+      y: 1.1423699
+      t_x: 0.3538746
+      t_y: -0.9352929
+    }
+    points {
+      x: 1.0
+      y: 0.014935664
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2027355
+      y: 3.3074327
+      t_x: 0.92783904
+      t_y: -0.3729809
+    }
+    points {
+      x: 0.38931102
+      y: 1.1156069
+      t_x: 0.26103032
+      t_y: -0.9653306
+    }
+    points {
+      x: 1.0
+      y: 0.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}
+emitters {
+  id: "emitter5"
+  mode: PLAY_MODE_ONCE
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    z: 0.1
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_light_01"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  max_particle_count: 1
+  type: EMITTER_TYPE_CIRCLE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 1000.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 1.6
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 30.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.43137255
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.30980393
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X
+    points {
+      y: 2.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y
+    points {
+      y: 2.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 9.531683E-5
+      t_x: 0.48855478
+      t_y: 0.8725332
+    }
+    points {
+      x: 0.014885994
+      y: 1.0171621
+      t_x: 0.06842353
+      t_y: 0.99765635
+    }
+    points {
+      x: 0.31872964
+      y: 0.12317026
+      t_x: 0.44993034
+      t_y: -0.89306366
+    }
+    points {
+      x: 0.5886808
+      y: -0.99066126
+      t_x: 0.18202555
+      t_y: -0.9832938
+    }
+    points {
+      x: 0.83127034
+      y: -0.3613797
+      t_x: 0.8397494
+      t_y: 0.5429742
+    }
+    points {
+      x: 1.0
+      y: 0.0
+      t_x: 0.99995637
+      t_y: -0.009341509
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2022469
+      y: 3.2772617
+    }
+    points {
+      x: 0.38703388
+      y: 1.1423699
+      t_x: 0.3538746
+      t_y: -0.9352929
+    }
+    points {
+      x: 1.0
+      y: 0.014935664
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0156251
+    }
+    points {
+      x: 0.2027355
+      y: 3.3074327
+      t_x: 0.92783904
+      t_y: -0.3729809
+    }
+    points {
+      x: 0.38931102
+      y: 1.1156069
+      t_x: 0.26103032
+      t_y: -0.9653306
+    }
+    points {
+      x: 1.0
+      y: 0.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}

+ 4 - 0
examples/particles/fireworks/fw_trail_blue.go

@@ -0,0 +1,4 @@
+components {
+  id: "trail_blue"
+  component: "/examples/particles/fireworks/fw_trail_blue.particlefx"
+}

+ 273 - 0
examples/particles/fireworks/fw_trail_blue.particlefx

@@ -0,0 +1,273 @@
+emitters {
+  mode: PLAY_MODE_LOOP
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    y: -36.0
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_02"
+  material: "/builtins/materials/particlefx.material"
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 150
+  type: EMITTER_TYPE_CONE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 512.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 0.3
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 100.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 100.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.12941177
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.3019608
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.7019608
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.5190731
+    }
+    points {
+      x: 1.0
+      y: 0.0035842706
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.0
+      t_x: 0.07194582
+      t_y: 0.99740857
+    }
+    points {
+      x: 0.11320755
+      y: 0.99277455
+      t_x: 0.99418455
+      t_y: 0.10768964
+    }
+    points {
+      x: 0.38487023
+      y: 0.12991524
+      t_x: 0.8252495
+      t_y: -0.5647683
+    }
+    points {
+      x: 1.0
+      y: 7.7859504E-4
+      t_x: 0.9999786
+      t_y: -0.0065419343
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ANGULAR_VELOCITY
+    points {
+      y: 1.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}
+emitters {
+  id: "emitter1"
+  mode: PLAY_MODE_LOOP
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    y: -19.0
+    z: 0.5
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_02"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 128
+  type: EMITTER_TYPE_CONE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 500.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 0.3
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 100.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 50.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.5190731
+    }
+    points {
+      x: 1.0
+      y: 0.0035842706
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.0
+      t_x: 0.07194582
+      t_y: 0.99740857
+    }
+    points {
+      x: 0.11320755
+      y: 0.99277455
+      t_x: 0.99418455
+      t_y: 0.10768964
+    }
+    points {
+      x: 0.38487023
+      y: 0.12991524
+      t_x: 0.8252495
+      t_y: -0.5647683
+    }
+    points {
+      x: 1.0
+      y: 7.7859504E-4
+      t_x: 0.9999786
+      t_y: -0.0065419343
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ANGULAR_VELOCITY
+    points {
+      y: 1.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}

+ 4 - 0
examples/particles/fireworks/fw_trail_green.go

@@ -0,0 +1,4 @@
+components {
+  id: "trail_green"
+  component: "/examples/particles/fireworks/fw_trail_green.particlefx"
+}

+ 273 - 0
examples/particles/fireworks/fw_trail_green.particlefx

@@ -0,0 +1,273 @@
+emitters {
+  mode: PLAY_MODE_LOOP
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    y: -36.0
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_02"
+  material: "/builtins/materials/particlefx.material"
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 150
+  type: EMITTER_TYPE_CONE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 512.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 0.3
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 100.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 100.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 0.2
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.3
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.5190731
+    }
+    points {
+      x: 1.0
+      y: 0.0035842706
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.0
+      t_x: 0.07194582
+      t_y: 0.99740857
+    }
+    points {
+      x: 0.11320755
+      y: 0.99277455
+      t_x: 0.99418455
+      t_y: 0.10768964
+    }
+    points {
+      x: 0.38487023
+      y: 0.12991524
+      t_x: 0.8252495
+      t_y: -0.5647683
+    }
+    points {
+      x: 1.0
+      y: 7.7859504E-4
+      t_x: 0.9999786
+      t_y: -0.0065419343
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ANGULAR_VELOCITY
+    points {
+      y: 1.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}
+emitters {
+  id: "emitter1"
+  mode: PLAY_MODE_LOOP
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    y: -19.0
+    z: 0.5
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_02"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 128
+  type: EMITTER_TYPE_CONE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 500.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 0.3
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 100.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 50.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.5190731
+    }
+    points {
+      x: 1.0
+      y: 0.0035842706
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.0
+      t_x: 0.07194582
+      t_y: 0.99740857
+    }
+    points {
+      x: 0.11320755
+      y: 0.99277455
+      t_x: 0.99418455
+      t_y: 0.10768964
+    }
+    points {
+      x: 0.38487023
+      y: 0.12991524
+      t_x: 0.8252495
+      t_y: -0.5647683
+    }
+    points {
+      x: 1.0
+      y: 7.7859504E-4
+      t_x: 0.9999786
+      t_y: -0.0065419343
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ANGULAR_VELOCITY
+    points {
+      y: 1.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}

+ 4 - 0
examples/particles/fireworks/fw_trail_red.go

@@ -0,0 +1,4 @@
+components {
+  id: "trail_red"
+  component: "/examples/particles/fireworks/fw_trail_red.particlefx"
+}

+ 273 - 0
examples/particles/fireworks/fw_trail_red.particlefx

@@ -0,0 +1,273 @@
+emitters {
+  mode: PLAY_MODE_LOOP
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    y: -36.0
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_02"
+  material: "/builtins/materials/particlefx.material"
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 150
+  type: EMITTER_TYPE_CONE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 512.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 0.3
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 100.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 100.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 0.4
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 0.05
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.5190731
+    }
+    points {
+      x: 1.0
+      y: 0.0035842706
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.0
+      t_x: 0.07194582
+      t_y: 0.99740857
+    }
+    points {
+      x: 0.11320755
+      y: 0.99277455
+      t_x: 0.99418455
+      t_y: 0.10768964
+    }
+    points {
+      x: 0.38487023
+      y: 0.12991524
+      t_x: 0.8252495
+      t_y: -0.5647683
+    }
+    points {
+      x: 1.0
+      y: 7.7859504E-4
+      t_x: 0.9999786
+      t_y: -0.0065419343
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ANGULAR_VELOCITY
+    points {
+      y: 1.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}
+emitters {
+  id: "emitter1"
+  mode: PLAY_MODE_LOOP
+  duration: 1.0
+  space: EMISSION_SPACE_WORLD
+  position {
+    y: -19.0
+    z: 0.5
+  }
+  tile_source: "/assets/sprites.atlas"
+  animation: "fw_trace_02"
+  material: "/builtins/materials/particlefx.material"
+  blend_mode: BLEND_MODE_ADD
+  particle_orientation: PARTICLE_ORIENTATION_MOVEMENT_DIRECTION
+  max_particle_count: 128
+  type: EMITTER_TYPE_CONE
+  properties {
+    key: EMITTER_KEY_SPAWN_RATE
+    points {
+      y: 500.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_LIFE_TIME
+    points {
+      y: 0.3
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SPEED
+    points {
+      y: 100.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_SIZE
+    points {
+      y: 50.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_RED
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  properties {
+    key: EMITTER_KEY_PARTICLE_ALPHA
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_SCALE
+    points {
+      y: 0.5190731
+    }
+    points {
+      x: 1.0
+      y: 0.0035842706
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_RED
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_GREEN
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_BLUE
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ALPHA
+    points {
+      y: 0.0
+      t_x: 0.07194582
+      t_y: 0.99740857
+    }
+    points {
+      x: 0.11320755
+      y: 0.99277455
+      t_x: 0.99418455
+      t_y: 0.10768964
+    }
+    points {
+      x: 0.38487023
+      y: 0.12991524
+      t_x: 0.8252495
+      t_y: -0.5647683
+    }
+    points {
+      x: 1.0
+      y: 7.7859504E-4
+      t_x: 0.9999786
+      t_y: -0.0065419343
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_X
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_STRETCH_FACTOR_Y
+    points {
+      y: 1.0
+    }
+  }
+  particle_properties {
+    key: PARTICLE_KEY_ANGULAR_VELOCITY
+    points {
+      y: 1.0
+    }
+  }
+  size_mode: SIZE_MODE_AUTO
+}