How to Try Defold Morph Targets - First Indie Blend Shape Spike 2026

If you are searching defold morph targets, you do not need another “Defold now does 3D” pitch. You need a Monday path: pin Defold ≥ 1.13.0, import one glTF with blend shapes, prove model.play_anim can drive morph weights or drive them from Lua with model.set_blend_weights, confirm the material actually samples morph data, then decide keep / hold / rewrite before anyone promises facial dialogue on a Steam week.
On June 22, 2026, the Defold Foundation shipped 1.13.0 with native morph target (blend shape) support for model components (release post, forum notes). The model animation manual documents import, play_anim, get_blend_weights / set_blend_weights, and the shader path (morph_targets sampler + morph_targets_weights). The engine work landed through PR #12192; stable tag v1.13.0 followed on GitHub.
This evening is not Defold 1.13.1 lights (editor Light components / LightBuffer — still a beta story). It is not the Defold Steam collection and save audit (packaging). It is not Roblox Animation Graphs (different platform). It is defold morph targets on a spike branch — one face or prop, receipt, honest animation limits.
| If you are… | Start here | Done when |
|---|---|---|
| Beginner | Glossary → import one morph glTF → Play one morph clip | You can see a shape change on screen |
| Working Lua / TA | Gates M1–M6 → set_blend_weights + shader | Receipt JSON + screenshot + HTML5 note |
| Studio lead | Keep/hold table + diligence | Written promote condition + dual owners |
Time: about 90–120 minutes for a fresh spike project. Longer if your DCC export is broken or your custom vertex shader needs a morph pass.
Why this matters now
Three clocks make defold morph targets worth an evening this month:
- Stable morphs finally shipped. The 1.13.0 release calls morph targets one of the most important 3D additions — facial animation, dialogue mouth shapes, damage morphs, stylized deformation without mesh swaps. Discord will ask “did you try morphs?” — you need a receipt, not vibes.
- Script control is first-class. Official docs expose
model.get_blend_weights()andmodel.set_blend_weights()so gameplay can drive expressions without baking every combination into clips (model animation manual). - Honest limits still surprise teams. A model component plays one
model.play_animlane at a time — you cannot dual-play a skeletal clip and a separate morph clip. You can play skeletal animation and override morph weights from script. Shader materials must opt in; editor morph preview is not there yet. HTML5 / GLES2 paths need an honest note.
Also in the 1.13.x wave (do not confuse with tonight’s keyword): 1.13.1-beta Light components, morph-target instancing follow-ups, build and editor tooling. Tonight’s primary keyword is defold morph targets on 1.13.0+ stable.
Glossary - plain words
| Term | What it means |
|---|---|
| Morph target / blend shape | Alternate vertex positions (plus normal/tangent deltas) for the same mesh; a weight blends how much of that shape applies. |
| Weight 0 → 1 | 0 = no effect; 1 = full target shape. Values outside that range can exaggerate if the asset/shader allow it. |
| glTF morph data | Morph targets and initial weights imported from .gltf / .glb into the Model. |
| Morph animation clip | A glTF animation that keys morph weights — playable with model.play_anim() like skeletal clips. |
model.set_blend_weights |
Lua override applied after animation each frame until cleared. |
model.get_blend_weights |
Reads current weights for the first morphed mesh in the model. |
morph_targets texture |
Engine-generated sampler2DArray holding position/normal/tangent deltas per target. |
morph_targets_weights |
Vertex uniform (vec4 packs of four weights) the shader reads. |
| One play_anim lane | One model animation at a time — skeletal or morph clip via play_anim, not both clips at once. |
| Keep / hold / rewrite | Keep = adopt morph path for ship; hold = lab only until shader/HTML5 proven; rewrite = wrong feature for this vertical slice. |
What Defold 1.13.0 morph support actually ships (true summary)
From the 1.13.0 release, forum notes, model animation manual, model component manual, and PR #12192:
- glTF morph / blend target import on model components (mesh morphs come in with the mesh).
- Morph weight animations playable with
model.play_anim()when the animation set includes them. - Runtime Lua control via
model.get_blend_weights()andmodel.set_blend_weights()(one-based Lua indices; clear override with nil / empty call). - Shader constructs —
morph_targets_weightsuniform andsampler2DArray morph_targets(three array layers per target: position, normal, tangent deltas). - Official examples referenced from the release post (Morph Target Animation playback; Morph Target Weights for script-driven blends).
- Honest limits (from PR / docs): instancing needs more work; cannot mix skeletal + morph as two simultaneous
play_animcalls; cannot play multiple morph clips at once the same way; editor morph preview not available yet (#ifndef EDITORwrappers in shader examples); some shader helpers (textureSize) are not GLES2-friendly.
This is stable channel capability (1.13.0+), unlike editor Light components which remain a 1.13.1-beta keep/hold. Still use a spike branch — morph-aware materials and animation policy are ship risks even when the editor version is stable.
Keep / hold / rewrite - Monday decisions
| Situation | Keep | Hold | Rewrite |
|---|---|---|---|
| Dialogue face on desktop with morph glTF ready | Spike morphs on 1.13.0+ branch | Merging untested morph shader into fest depot tonight | Claiming “faces done” after import alone |
| Need run + smile at once via two play_anim calls | — | Redesign to skeletal + set_blend_weights |
Expecting dual play_anim morph+skel |
| HTML5 demo on WebGL1 / ES2 | — | Morph shaders until GLES3/WebGL2 path proven | Shipping morph VS that requires textureSize on ES2 |
| Pure 2D pixel game | — | Optional prop morph only | Forcing facial pipeline into a sprite ship |
| Custom skinned materials without morph sample | Port morph pass after spike | Dual materials forever | Deleting working skinning mid-milestone |
| Partner diligence zip | Receipt + screenshot + limit notes | “It twitched in Play once” | Shipping without owners or promote condition |
Default indie posture: keep the spike workflow and receipt on 1.13.0+; hold ship merge until M1–M6 are green and animation policy is written (one play_anim lane + script morph overrides).
Prerequisites
- Git (or zip backups) — morph material mistakes are easier to revert than to debug mid-week.
- Defold editor 1.13.0 or newer (stable). Confirm version in Help → About / project settings before you start.
- A tiny 3D collection: one Model with a morph-capable glTF (or Defold’s morph examples), Camera, floor, light or unlit proof color so you can see deformation.
- Optional: existing HTML5 export if you must answer the web gate tonight.
- 90–120 minutes uninterrupted.
If you have never audited a Defold Steam desktop bundle, keep Steam collection save audit for another evening. If you still need editor lights, that is a separate beta night — 1.13.1 lights.
For Lua message patterns around models, skim Game Development with Lua Scripting — tonight’s depth is morph weights and shaders, not general Lua architecture.
Beginner path - first morph on screen (no jargon first)
Goal: one model whose shape clearly changes when you press Play.
- Install or confirm Defold ≥ 1.13.0 (v1.13.0 release or newer). Do not mix this spike with a 1.12.x ship install without a second editor.
- Create a new project or clone onto a branch named
spike/defold-1130-morph. - Import a glTF that includes morph targets (start from Defold’s morph examples linked from the 1.13.0 post if your art pipeline is not ready).
- Add a Model component; assign the mesh, skeleton if present, animation set, and a material that supports morphs (builtins path or the manual’s morph vertex shader pattern).
- In a script
init, either:model.play_anim("#model", "smile", go.PLAYBACK_LOOP_FORWARD)if you have a morph weight clip namedsmile, or- read weights, set
weights[1] = 1, callmodel.set_blend_weights("#model", weights).
- Press Play. Confirm the mesh deforms. Raise and lower the weight or stop the animation to see the base shape return.
- Screenshot Play mode. Fill the receipt at the end of this article. Do not treat “imported without crash” as ship-ready faces.
That is the beginner win. Everything below is the working-dev gate set.
Working-dev gates M1–M6
| Gate | What you prove | Artifact |
|---|---|---|
| M1 Version pin | Editor reports ≥1.13.0; ship install untouched if separate | about_version.txt or screenshot |
| M2 Morph import | Model Outline shows morph-capable mesh; no import error | gltf_import_note.md |
| M3 Morph play_anim | One morph weight clip plays visibly | play_anim_morph.gif or screenshot |
| M4 Script override | set_blend_weights changes shape; clear restores anim/base |
weights_override_log.txt |
| M5 Material morph path | Vertex shader samples morph_targets / weights (or proven builtin) |
Material path + compile clean |
| M6 HTML5 + owners | Web note filed; receipt signed; keep/hold written | defold_1130_morph_receipt_v1.json |
M1 - Pin Defold ≥ 1.13.0 without wrecking ship
Morph APIs do not exist on older stables the same way. Print version. If your Steam branch is still on 1.12.x, keep two installs or upgrade the spike project only. Record both spike_version and ship_version in the receipt.
M2 - Import one morph glTF cleanly
Per the model manual, morph targets import with the mesh from glTF. If the file has multiple meshes, Defold reads the first — author for that rule. Skeleton + morph data can coexist; animation policy still matters later.
Fail: import succeeds but no morphs exist in the asset (DCC export forgot blend shapes). Fix in Blender/Maya/etc., re-export, re-import — do not invent Lua weights for missing targets.
M3 - Play a morph animation clip
function init(self)
model.play_anim("#model", "smile", go.PLAYBACK_LOOP_FORWARD)
end
If the clip is skeletal-only, you will not see blend-shape motion. Confirm the animation set actually keys morph weights (manual).
Honest limit: you cannot also play_anim a separate skeletal clip on the same model at the same time. Plan one clip lane.
M4 - Drive weights from Lua
function init(self)
local weights = model.get_blend_weights("#model")
weights[1] = 0.75
weights[2] = 0.25
model.set_blend_weights("#model", weights)
end
-- later, clear override:
-- model.set_blend_weights("#model")
-- model.set_blend_weights("#model", nil)
Docs: override applies after animation every frame until cleared; indices are one-based; extras ignored; missing values treated as zero for meshes with more targets.
Recommended production pattern for locomotion + face: play skeletal locomotion with play_anim, drive mouth/brows with set_blend_weights from dialogue state — not two competing play_anim calls.
M5 - Morph-aware material (the silent fail)
If the vertex shader never samples morph_targets and applies weighted deltas, weights do nothing visible. The model animation manual shows the morph_targets_weights array packing (four weights per vec4) and apply_morph_target pattern. Editor preview of morph textures is limited — trust runtime Play, not editor scrub alone.
Fail: “weights print in Lua but mesh frozen” → material path, not Lua.
M6 - HTML5 honesty + receipt + owners
Document whether tonight’s shader uses features that break on OpenGL ES 2.0 / WebGL1 (manual notes textureSize-style samples are not ES2-safe). Desktop GREEN does not equal HTML5 GREEN. Name ship_owner and spike_owner. Decision must be keep, hold, or rewrite with a promote condition.
Proof table - what “GREEN” looks like
| Check | GREEN | RED |
|---|---|---|
| Version | ≥1.13.0 on spike | Guessing from Discord |
| Import | Morph targets present on mesh | Empty morph list |
| play_anim morph | Visible deformation | Clip plays but shape static |
| set_blend_weights | Shape tracks script values | Values change, mesh ignores |
| Clear override | Returns to anim/base | Stuck in last override |
| Material | Morph sample in VS | Unmorphed skinned/unlit only |
| Dual play_anim attempt | Documented as unsupported | “Bug report” filed against intended limit |
| HTML5 | Explicit pass/hold/n/a | Assumed same as desktop |
| Receipt | JSON on disk with owners | Slack memory only |
Discord-ready brief (creator share hook)
Paste this after the evening:
Defold 1.13.0+ morph targets (blend shapes) are real. We spiked branch
spike/defold-1130-morph: one morph glTF,play_animorset_blend_weights, morph-aware material, receipt filed. We do not dual-play_animskeleton + morph clips. HTML5 marked hold/n/a until WebGL path proven. Ship merge waits on M1–M6.
Creators: that message is the shareable outcome. Developers: the receipt below is the bookmark.
Evening timeline (90–120 minutes)
| Block | Minutes | Focus |
|---|---|---|
| 0–15 | Confirm ≥1.13.0; branch project | M1 |
| 15–40 | Import morph glTF; Model wired | M2 |
| 40–65 | play_anim morph clip smoke | M3 |
| 65–85 | set_blend_weights + clear | M4 |
| 85–100 | Material morph path verify | M5 |
| 100–120 | HTML5 note + receipt + Discord brief | M6 |
If you run long, cut HTML5 build and mark hold with reason — still file M6.
Common mistakes (and fast fixes)
| Mistake | Symptom | Fix |
|---|---|---|
Dual play_anim skel + morph |
Second clip “wins” or looks broken | Skeletal play_anim + set_blend_weights for face |
| Unmorph material | Weights change, mesh frozen | Add morph sample path from manual |
| Zero-based weight indices | Wrong target moves | Use one-based Lua indices |
| Forgot to clear override | Anim clips never recover | set_blend_weights("#model") / nil |
| Editor-only judgment | “Works in Outline” | Trust runtime Play; editor morph preview limited |
| Mixing lights beta tonight | Context switch chaos | Morphs on stable 1.13.0; lights another night |
| Mixing Steam save audit | Depot thrash | Morphs tonight; save audit later |
| glTF multi-mesh surprise | Wrong mesh imported | Author first mesh or split files |
| ES2 HTML5 morph VS | Black / compile fail on web | Hold morph on web or simplify shader |
| Shipping without promote rule | Mid-fest morph merge | Receipt promote_after filled |
If packaged Steam saves already misbehave, fix that on the ship channel with the save-root help article — do not debug saves while learning morph weights.
Animation policy - write this before art scales
Pin a one-page policy in the spike folder:
- Locomotion / body — skeletal clips via
model.play_anim. - Face / damage / stylized mesh — morph weights via
set_blend_weights(and/or a single morph clip when idle). - Never schedule two competing
play_animcalls expecting blend. - Material — every morphed hero uses a reviewed morph-capable material ID.
- Platform — desktop first; HTML5 morph is a separate gate.
That policy is what companies want in a diligence zip more than a pretty GIF.
Company / diligence paragraph
For a publisher or contractor zip:
- Spike channel is Defold ≥1.13.0 on an isolated branch with
defold_1130_morph_receipt_v1.json. - Morph adoption requires M1–M6 green and written animation policy (one play_anim lane + script morph overrides).
- HTML5 products document WebGL / ES version requirements or a non-morph fallback.
- Art pipeline exports morphs into the first mesh Defold reads, or splits assets intentionally.
- No production player traffic on experimental morph shaders until promote condition clears.
Cost/ROI: one evening now vs a week of “faces broken on build machine” and mid-fest dual-animation fights. Governance: two named owners (ship vs spike).
Templates for Defold save-path audits live under 12 free Defold / GDevelop / Ren'Py save-path resources — different format ladder, same evidence habit. Pair morph receipts with BUILD_RECEIPT culture when you promote builds.
Receipt template - defold_1130_morph_receipt_v1.json
{
"receipt": "defold_1130_morph_receipt_v1",
"project": "YOUR_GAME",
"collected_at": "2026-07-28",
"spike_version": "1.13.0_or_newer",
"ship_version": "VERSION_YOU_SHIP",
"release_url": "https://defold.com/2026/06/22/Defold-1-13-0/",
"branch": "spike/defold-1130-morph",
"gates": {
"M1_version_pin": true,
"M2_morph_import": true,
"M3_play_anim_morph": true,
"M4_set_blend_weights": true,
"M5_morph_material": true,
"M6_html5_owners": true
},
"asset": "path/to/morph.glb",
"morph_clip": "smile_or_none",
"script_override_tested": true,
"material": "morph_aware_material_id",
"play_mode_screenshot": "artifacts/play_mode_screenshot.png",
"html5_morph": "n/a",
"html5_note": "desktop-only spike; WebGL morph deferred",
"animation_policy": "skel_play_anim_plus_script_morph_weights",
"decision": "hold_pending_html5_or_keep_desktop",
"ship_owner": "NAME",
"spike_owner": "NAME",
"promote_after": "M1-M6 green on ship candidate; animation policy reviewed",
"notes": "One play_anim lane; set_blend_weights for face; see manuals model-animation + PR #12192"
}
Store next to your other evidence folders. Re-run M3–M5 after every material or glTF export change.
Comparison - where this sits vs other keep/holds
| Topic | Engine | Question |
|---|---|---|
| This article | Defold 1.13.0+ | Can we smoke morph / blend shapes with honest animation policy? |
| Defold 1.13.1 lights | Defold beta | Can we light a collection with editor Light components? |
| Roblox Animation Graphs | Roblox | Can we ship locomotion blends without Luau state-machine theater? |
| Phaser Spine Mesh2D | Phaser | Can we smoke slot objects without batch-break theater? |
| MonoGame 3.8.5 | MonoGame | DesktopVK / Content Builder without breaking DesktopGL? |
Same keep/hold discipline; different primary keywords. Do not cannibalize Defold lights vs morph targets.
Secondary 1.13.x features (park for later)
Do not expand tonight’s receipt to cover everything in the 1.13 wave:
- Editor Light components (1.13.1-beta) — use the lights evening
- Morph-target instancing for crowds (called out as future work in PR notes)
- Mixing multiple simultaneous morph clips as first-class (also future)
- Metal / warm-build / archive size work from adjacent releases
Each deserves its own evening. Tonight is morph targets.
Stretch goals (only after M1–M6 green)
- Wire dialogue lines to a small weight table (viseme-ish) without claiming full lip sync.
- Compare CPU cost: morph on vs off on mid laptop (one paragraph in receipt notes).
- Export a second morph prop (crate damage) to prove pipeline repeatability.
- Attempt HTML5 build with a GLES3/WebGL2-safe morph shader and update
html5_morph.
Stop at one stretch if the clock hits 120 minutes — file the receipt first.
Key takeaways
- defold morph targets shipped in Defold 1.13.0 (June 22, 2026) as stable glTF blend-shape support for models.
- Control morphs with
model.play_anim(weight clips) and/ormodel.set_blend_weights(script override). - A model has one
play_animlane — do not expect skeletal + morph dual clips. - Recommended pattern: skeletal locomotion via
play_anim+ face viaset_blend_weights. - Materials must opt in to sample
morph_targets/morph_targets_weightsor weights are invisible. - Lua weight indices are one-based; clear overrides deliberately.
- Editor morph preview is limited — prove deformation in Play.
- HTML5 / ES2 may reject morph shader helpers — file an honest hold.
- Keep morphs off the same night as lights beta or Steam save audits.
- File
defold_1130_morph_receipt_v1.jsonwith dual owners and a promote condition. - Write animation policy before art scales facial targets.
- Discord brief + receipt beats “the mouth twitched once” when partners ask.
FAQ
What are Defold morph targets?
Alternate mesh shapes (blend shapes) imported from glTF and blended by weights. Defold 1.13.0+ supports them on model components with animation and Lua weight APIs — see the model animation manual and 1.13.0 release.
How do I set morph weights from Lua?
Call model.get_blend_weights("#model"), edit the table (one-based indices), then model.set_blend_weights("#model", weights). Clear with model.set_blend_weights("#model") or nil.
Can I play a walk animation and a smile animation at the same time?
Not as two model.play_anim calls. Play the skeletal walk, drive smile weights with set_blend_weights, or redesign clips. Official docs state one model animation at a time via play_anim.
Why do my blend weights do nothing?
Usually the material vertex shader does not apply morph deltas. Second: no morph targets on the imported mesh. Third: override cleared incorrectly or wrong component URL.
Is morph support still beta?
Morph targets landed in 1.13.0 stable. Editor Light components are the separate 1.13.1-beta story — do not conflate them.
Will morph targets work on HTML5?
Only if your morph shader and graphics context support the required features. Manual examples that use textureSize are not OpenGL ES 2.0 friendly. Prove desktop first; mark HTML5 hold until tested.
Is this the same as the Defold lights article?
No. Lights = LightBuffer / ambient-directional-point-spot on 1.13.1-beta. This URL = morph / blend shapes on 1.13.0+. Link them; do not merge keywords.
Where should studios put diligence evidence?
defold_1130_morph_receipt_v1.json, Play screenshot, animation policy paragraph, HTML5 note, ship vs spike owners, promote condition.
Do morph targets replace skeletal animation?
No. They complement it for surface deformation (faces, damage, stylized squash). Skeletal animation still owns bone-driven motion.
How does this relate to Lua scripting generally?
Morph weight tables are a Lua API concern; message architecture and update loops still follow normal Defold script patterns — see Lua scripting overview.
Related reading
- How to Use Defold 1.13.1 Lights - First Indie Lit Scene Evening
- Your First Defold Steam Desktop Collection and Save Audit
- Defold Steam Save Root Outside Collection Map - Fix
- Game Development with Lua Scripting
- 12 Free Defold GDevelop Ren'Py Save-Path Audit Templates
- How to Try Roblox Animation Graphs - First Indie Locomotion Blend Spike
- Official: Defold 1.13.0 release · Model animation manual · Forum 1.13.0 notes · PR #12192
Bottom line
defold morph targets in 1.13.0+ are the first evening worth running if you care about facial dialogue, damage morphs, or stylized deformation in Defold — and the first evening worth not merging if you still dual-play_anim by habit or ship an unmorph material. Pin the version, import one morph glTF, prove play_anim or set_blend_weights, verify the shader path, record HTML5 truth, file the receipt, keep animation policy boring. When ship promotes, M1–M6 are already rehearsed.