SwfMesh Plugin documentation

Plugin Features

⚠️ Closed Beta — SwfMesh is not yet on sale. Contact us for beta access.

Supported Features This page covers what you can do with your SWF content once it's inside your engine.

SwfMesh converts .swf files into real scene geometry. Use it to control materials, lighting, color palettes, clip attachment, and more - all directly in your engine to support your game development needs.

Overview#

Capability Unity Godot
3D and 2D rendering Godot ships a dedicated SwfNode2D
Editor integration Drop-in import, live preview, frame scrubber
Materials Replace every surface at once
Colour-pair overrides Target one authored fill colour
Scene lighting Diffuse only, off by default
Attaching clips Flash's addChild, kept
Hit boxes Box, circle, capsule
Timeline audio Through your own buses
Sorting layers Godot 2D uses z_index; 3D orders by world Z
Scale and pivot Three overriding levels
Scripting API Same surface, per-engine casing
Offline mesh baking Required for tessellator-free targets

Your SWF is geometry, not a movie#

SwfMesh tessellates the vector art into triangles and draws it with ordinary engine meshes and shaders. There is no offscreen surface, no baked sprite sheet, no video.

  • Resolution independent. Curves are triangulated as geometry, not rasterised. Punch the camera in and everything stays clean.
  • It shares your scene. SWF content becomes a true scene object.
  • Every fill is a surface you can replace with your own materials - see below.
  • It can be lit by scene lights, per player.
  • It can collide. Regions you author in Flash become engine-native colliders.
  • It is cheap to repeat. Each shape is triangulated once and reused everywhere it appears, so a crowd of copies shares one set of meshes.
Unity Godot
Component / node SwfPlayer on any GameObject SwfNode3D or SwfNode2D
3D scenes SwfNode3D
2D scenes SwfNode2D

Godot's two nodes are the same player in a different dimension - one shared player core under two node shells - so the scripting surface is identical between them and a script written against one works against the other.

Editor integration#

The parts you touch every day, in both engines:

  • Drop-in import. Drag a .swf in and it becomes an engine asset. No conversion step, no intermediate format, no export dialog - reimporting is just saving over the file.
  • A clip dropdown, populated from the symbols you exported for ActionScript, so choosing which timeline to play is a menu rather than a string you have to remember.
  • A playback block on the inspector - play, loop, random-frame and a frame scrubber
    • so you can find the frame you want without entering play mode.
  • Live preview of the running animation in the editor viewport.
  • The frame-script table, read out of the SWF at import and shown read-only on the inspector: what the timeline will do, and on which frame, before you press play.
  • Gizmos and selection in the viewport, with generated render objects kept out of your saved scene file.

Materials#

Every surface a clip draws gets a SwfMesh material by default: unlit, vertex-coloured, correct in both gamma and linear projects. You can replace it wholesale.

Unity Godot
Inspector Material Override on the Swf Player component material_override on the node
From script player.materialOverride = mat; material_override = mat

This is all-or-nothing - it replaces the material on every surface in the clip, gradients and bitmap fills included. Reach for it when you want one look across the whole thing (a silhouette, a dissolve, a hologram); reach for colour pairs, below, when you want to target part of the art.

Unity - keep overrides on a SWF shader. Use SwfMesh/SwfCombined (or SwfCombinedLit, SwfUnlit, SwfUnlitLit) and display order stays correct by construction. SwfMesh/SwfCombined also keeps your gradients: it resolves the authored fill and multiplies your Tint over the top. Other shaders work, but can z-fight where overridden fills overlap under a tilted camera - the console and inspector warn you when that happens.

Godot - a custom ShaderMaterial should declare cull_disabled in its render_mode. Tessellated triangles can face either way, and the automatic back-face fix only applies to StandardMaterial3D.

Colour-pair material overrides#

Instead of replacing every surface, target a single fill colour and give just that colour its own material.

Your hero's hat is #FF0000 in Flash. Map #FF0000 to an emissive material and the hat glows, while the rest of the character keeps rendering exactly as authored, in the same animation, at the same depth.

Unity Godot
Inspector Color Material Map - a list of (colour swatch, material) pairs, with an eyedropper color_material_map - a typed Dictionary of ColorMaterial
From script assign colorMaterialMap, then Refresh() assign color_material_map - applies immediately
csharp
// Unity - usually set in the inspector; from script it is a serialized array.
player.colorMaterialMap = new[] {
    new SwfPlayer.ColorMaterialEntry { colorValue = Color.red, material = gold },
};
player.Refresh();
gdscript
# Godot
var gold := StandardMaterial3D.new()
gold.albedo_color = Color8(255, 200, 40)
gold.emission_enabled = true
gold.emission = Color8(255, 160, 0)

color_material_map = { Color8(255, 0, 0): gold }   # every #FF0000 fill turns gold

What is and is not matched:

  • The key is RGB. Alpha is not part of it, so a 50%-alpha red fill matches the same entry a solid red one does.
  • Solid fills only. A gradient or bitmap fill is not one colour, so it cannot be keyed.
  • Strokes differ by engine. Unity also matches line colours; Godot matches fills only. If you need a stroke and a fill to take different overrides, give them different colours when you author the SWF - that works in both engines.
  • Your material asset is never touched. Each player duplicates it, so two characters sharing one gold material do not fight over it, and editing the source material updates every player live in the editor.

⚠️ Cost: a player with overrides renders on its own, outside the shared frame-mesh cache and the instanced path. That is the right trade for a handful of hero characters; it is the wrong one for five hundred background props.

Scene lighting#

Off by default - flat Flash art usually wants to stay flat. Turn it on per player (Unity enableLighting, Godot enable_lighting) and the default fills swap to lit variants.

⚠️ Godot 2D can only brighten. A Light2D adds to a canvas item, so it never darkens, and saturated art cannot respond at all. Use SwfNode3D if lighting is central to the look.

Attaching one clip inside another#

Flash's addChild, kept. Attach a second player into a named clip instance of a running one and it renders at that clip's depth in the display list, inheriting its animated transform and its colour transform.

csharp
// Unity - a sword that follows the hero's hand, through the whole animation
hero.Clip.GetClip("hand").AddChild(sword);
gdscript
# Godot - the same, with the child built inline
var sword := SwfNode3D.new()
sword.swf_resource = load("res://sword.swf")
$Hero.clip.get_clip("hand").add_child(sword)
  • The attached player keeps its own timeline - it can be playing its own animation while it rides along.
  • Attach depth is respected: if the hero's arm draws over the hand on this frame, the sword draws under the arm too.
  • Attachments survive a clip switch on the host, and are re-applied for you.
  • Detaching (RemoveChild / remove_child) hands the child back its own rendering.
  • Lifetime is non-owning: destroy either side in any order and the other detaches cleanly.
  • Godot can attach across dimensions - a SwfNode2D into a SwfNode3D's clip slot and the reverse.

Before you author for it:

  • The target must be a named MovieClip instance - name it in Flash's Properties panel. The root timeline is not an attach point.
  • The child draws through the host's renderer, so it inherits the host's ordering rather than sorting independently.
  • Attachment takes SWF players, not arbitrary engine objects (support planned).

Attaching a symbol out of the same .swf is in MovieClip Library.

Hit boxes#

Draw a shape in Flash, export it as HitBox, HitBoxCircle or HitBoxCapsule, and it becomes an engine-native collider at runtime - never rendered, visible only while you author. Because it lives on the timeline, the active set is frame-scoped: a hurtbox that exists on frames 5–10 of an attack exists for exactly those frames, with the position, rotation and scale the animator gave it.

You get pooled trigger colliders, enter and exit events, and a query for the currently active set, in both engines.

Hit Boxes - authoring them, the shape each kind realises, flat versus extruded in 3D, and the events.

Timeline audio, routed your way#

Sounds authored into the timeline play through your engine's audio system, not a private mixer - so they obey your buses, your snapshots and your volume sliders.

Unity Godot
On / off, per player enableAudio enable_audio
Routing audioMixerGroup audio_bus
Volume audioVolume audio_volume_db
3D positional positionalAudio positional_audio
Cut everything now StopAllSounds() stop_all_sounds()

Voices are pooled and audio is shared per imported file, so a crowd of players from one .swf decodes one copy. Editor previews are silent.

Draw order#

Inside a clip, order is always the display order the animator authored. Between players, you get the engine's own tools:

  • Godot 2D - a SwfNode2D is a Node2D, so z_index, z_as_relative, y_sort_enabled and CanvasLayer all work on it, with no plugin-specific concept to learn.
  • Unity - Sorting Layer and Order in Layer on the component, exactly as on a SpriteRenderer, so "this clip is always in front of that one" is a setting rather than a camera-distance accident. SortingGroup works too.
  • Godot 3D - order players by world Z. There is no sorting-layer equivalent: the render-priority range is spent entirely on getting the inside of a clip to paint in the right order. layering_mode picks how that is done - Strict Display Order (the default) pins each layer's priority; Depth-Tested Compatibility relies on small Z steps instead.

Scale and pivot, in three layers#

Flash's coordinate scale is nothing like engine units, and the origin sits wherever the animator put the registration point. Set both at three levels, each overriding the one above:

Level Unity Godot
Project default Project Settings > SwfMesh - Global Scale, Default Pivot Offset Project Settings > swf_mesh - global_scale, global_scale_2d, default_pivot_offset
Per imported asset Scale / Pivot Offset on the importer Scale / Pivot Offset in the Import dock
Per player scaleOverride scale_override, pivot_override

Set the project default once to match your units and most content just lands right.

Playback the timeline cannot express#

Small things, but they are the difference between a movie and a game object:

  • Run at your frame rate, not Flash's. Turn off Use SWF Frame Rate and drive the clip at any rate you like - including one you animate.
  • Random start frame. Spawn two hundred copies of one idle loop and they all breathe in lockstep; turn on Random Frame and they don't. Unity also exposes a fixed StartFrame.
  • Loop or hold, per player, without editing the SWF.
  • Per-clip transform overrides. Nudge, rotate or scale a nested clip - an arm, a head - from script while its animation keeps playing. See Scripting API.

Offline mesh baking#

Unity only, today. Normally SwfMesh tessellates a character's geometry the first time it is drawn. Baking moves that work to import time: every surface is triangulated on your desktop and stored in the asset, so the runtime needs no tessellator at all.

Turn it on with Project Settings > SwfMesh > Bake Mesh Geometry (off by default); every .swf reimports.

Two reasons to want it:

  • Console builds require it. The Nintendo Switch plugin ships without a tessellator, so a Switch build fails preflight unless every asset carries a current bake. See Platforms.
  • No first-use hitch. Nothing is triangulated at play time, so the first frame a character appears on costs no more than the tenth.

And two reasons not to leave it on everywhere:

  • Assets get bigger - triangles take several times the space of the vectors they came from.
  • Morph tweens multiply. Each distinct interpolation step placed on a timeline bakes as its own mesh.

Baked output is verified pixel-identical to live tessellation, so switching it on is a build-size and timing decision, not a visual one.

See also#