diff --git a/animation-editor.md b/animation-editor.md
index 14719ee..11be25e 100644
--- a/animation-editor.md
+++ b/animation-editor.md
@@ -1,9 +1,15 @@
The animation editor can be accessed from the main editor menu (when within a mod, press _Tab_ to open the editor), then click on the text at the top. The menu entry is near the bottom.
-_Warning: Save your map before you enter the animation editor!_ The particle viewer unloads the current map and you will lose changes if you don't save!
+_Warning: Save your map before you enter the animation editor!_ Entering the animation editor unloads the current map and you will lose changes if you don't save!
_Compatibility note_: This article describes the OSE version. Older versions have a severely crippled animation editor that is a pain to use. Don't!
+
+# Getting started with animating
+
+See [animation tutorial](animation-tutorial).
+
+
# User interface
The box in the middle displays the currently loaded animation. Only one animation can be loaded at a time.
@@ -39,7 +45,7 @@ Most of the buttons have a hotkey assigned but some don't.
* _Warning_: This applies the skin on top of the currently loaded skeleton. This _does_ change textures recorded in the animation file if you save afterwards.
* ___M___ - Selection mode
* The first mode selects the bone that is closest to the mouse (red highlight).
- * The second mode selects bones with the keyboard. Press arrow up or down to cycle through bones (blue highlight).
+ * The second mode selects bones with the keyboard. Press arrow up or down to cycle through bones (blue highlight). There is probably no reason to use this mode, ever.
* ___B___ - Toggle bounding boxes and center points
* ___E___ - Toggle between [[normal edit mode|#normal-mode]] and [[strip edit mode|#strip-edit]].
* Normal mode = grey background
@@ -76,6 +82,237 @@ These apply to whichever bone is currently selected. Each function can be combin
# Workflow
+TODO
+
## Normal mode
+TODO
+
## Strip edit mode
+
+TODO
+
+## Grid edit mode (2023 update)
+
+TODO
+
+
+# Anatomy of an Animation (XML) file
+
+Example:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Animation layers
+
+An animation is made of multiple simultaneously playing _layers_ that can _include_ or _ignore_ certain bones,
+eg. you can play one animation that affects the upper body while playing another animation that affects the legs.
+
+At least one animation layer must exist. In most cases you will not need special behavior so you can leave it at the default:
+```xml
+
+
+
+```
+
+When nothing is specified, an animation layer affects all bones.
+
+Compare this to the animation layers in _naija.xml_:
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+Each anim layer is indexed starting from 0. Higher (ie. further down) animation layers override lower anim layers, ie. the topmost anim layer with an active playing animation wins.
+An animation layer that does not actively play an animation is ignored.
+This is evaluated for each bone separately.
+Note that the animation editor always plays its animation on layer 0, therefore you should always leave it at the default `` and not exclude any bones.
+
+NB: The ANIMLAYER_* constants as defined by [ScriptInterface.cpp](https://github.com/AquariaOSE/Aquaria/blob/master/Aquaria/ScriptInterface.cpp)
+refer directly to the animation layers as defined by naija.xml.
+It's recommended not to change the anim layers in naija.xml because the game expects them to exist in this order.
+
+To modify the anim layers: Use a text editor! The animation editor does not touch them.
+
+## Bones
+
+The `` section has all the bones that take part in an animation.
+This section can also not be modified with the animation editor and you'll need a text editor to modify bones.
+
+### Bone attributes (and their defaults)
+
+- __idx__ - Numeric index of the bone. Used by Lua function *entity_getBoneByIdx()*. Must be unique. Does not need to be ordered, and you can leave holes in your numbering, but don't use negative indices.
+- __gfx__ ("") - The texture name to use (without file extension, as usual).
+- __name__ ("") - Sometimes it's useful to reference bones by name. Leave empty if not needed.
+ It's certinly easier to name a bone "Head" than to remember the ID for each different skeleton that has a head. Used by Lua function *entity_getBoneByName()*.
+- __pidx__ - _idx_ of parent Bone. Set this to attach this bone to a parent, so that when the parent moves, this bone moves with it.
+ Think of it like your arm (attached to the body), and when you move it around the lower arm follows, and the hand follows the lower arm, etc.
+ (The skeleton is actually a [Scene graph](https://en.wikipedia.org/wiki/scene_graph)).
+ Use `parent="-1"` to denote a root bone (that is not attached to a parent). You need at least one root bone in each animation.
+ The parent bone obviously needs to exist or bad things may happen.
+- __fh__ (0) - Set to 1 to flip bone horizontally. It is recommended not to use this and make a flipped version of the texture instead.
+- __fv__ (0) - Set to 1 to flip bone vertically. Definitely avoid using this because it doesn't do what you think it should do.
+- __gc__ (0) - Set to 1 to generate a collision mask for this bone. Use for bones that should partake in skeletal collision.
+
(See also: `entity_handleShotCollisionsSkeletal` and the `entity_collideSkeletal*()` family of Lua functions).
+- __cr__ (0) - Collide radius. Can be used instead of `gc=` if a simple circle collision is enough.
+- __sz__ ("1 1") - Scale factor; __TWO__ values. Affects children. Use the same value for both X and Y direction for a uniform scale.
+- __rq__ (1) - Render quad. Set to 0 to not render the bone by default. Can be changed later with `bone_setVisible()`.
+- __rbp__ (0) - Render before parent. Normally a bone is drawn after its parent (ie. on top of it). This flag inverts this so the bone is drawn underneath the parent.
+- __sel__ (1) - Selectable. Set to 0 to make this bone non-selectable to make sure you don't accidentally grab and move it.
+- __pass__ (0) - Layer pass. Higher numbers get drawn more in front regardless of the parent/child hierarchy.
+ This is an advanced setting, make sure you understand the [draw order](#skeleton-draw-order) first!
+- __prt__ ("") - Attaches particle effects to the bone. The particle effects are initially disabled but can be controlled with a bone command.
+ The string is a list of (slot, name) pairs, ie. `"0 explode 1 fire"` will allocate two slots, IDs 0 and 1 with a particle effect each.
+- __strip__ - Enable bone `strip` mode. Two numbers; the first is 1 if vertical, 0 if horizontal; the second is the number of segments. Incompatible with __grid__.
+- __grid__ - Enable bone `grid` mode. Two numbers, the size of the grid points in X and Y directions. Each must be >= 2. Incompatible with __strip__.
+- __io__ ("0 0") - Two numbers. Sets internal offset of bone (ie. shift away from the center without changing the rotation point).
+ Similar to __offx__ / __offy__, but does not affect children.
+
+
+
+Less commonly used attributes:
+
+- __c__ (1) - Enable collision. Can be set to 0 to explicitly disable collision even if `cr` or `gc` are set.
+- __offx__, __offy__ (0) - Offset the bone from its center. This offset affects child bones.
+- __rt__ (0) - Repeat texture. Set to 1 to enable repeating texture mode. Can use `quad_setRepeatTexture()` instead.
+
+## Animation section
+
+Each animation has an entry here, of which each is a list of keyframes.
+
+The `
+```
+
+You can break it into multiple lines:
+
+```xml
+
+```
+
+The parser doesn't care and it's much easier to see the individual commands that way.
+
+## Skeleton draw order
+
+Note that drawing a bone first means it may get overdrawn by other bones drawn after it.
+So to have bones appear on top of everything, you want them drawn as late as possible.
+
+The following rules apply, in this order, recursively:
+
+- For each _layer pass_:
+ - Scan the bone list top to bottom
+ - For each _root_ bone (ie. those with `pidx="-1"`):
+ - drawBone(_root_)
+
+And _drawBone(**b**)_ does this:
+
+ - Scan the bone list top to bottom:
+ - If a bone has _**b**_ as parent and `rbp="1"`:
+ - drawBone(that bone)
+ - If _**b**_ has `pass=` equal to current _layer pass_:
+ - Draw _**b**_ to the screen
+ - Scan the bone list top to bottom:
+ - If a bone has _**b**_ as parent and `rbp="0"`:
+ - drawBone(that bone)
+
+If you want your skeleton to be drawn precisely in a specific way you need to take care of the correct bone ordering.
+
+The layer pass depends on the layer that the entity is on. For most layers there is only a single pass with id 0,
+but by default LR_ENTITIES goes from passes -2 to 5, inclusive.
+
+You can use the Lua function `setLayerRenderPass()` to change a layer's begin and end pass but that comes at a cost of overall render performance.
+
+Here are some rules of thumb that make the above easier to remember:
+
+- Bones with a greater _layer pass_ are drawn on top of bones with a lower _layer pass_
+- Bones towards the end of the list are drawn later.
+- Bones with `rbp="1"` are drawn earlier
+
+
+# Common problems, Q&A
+
+* _Help, I've set ``
+ - If it's only one value, the other is interpreted as zero, so it's squished infinitely thin and you can't see it.
+
+* _Help, I'm moving one bone around and another unrelated bone follows whenever I release the mouse button?!_
+This can happen if two (or more) bones accidentally share the same ID. Check that bone IDs are unique.
+To fix this, pick the bone that is less annoying to animate, change its ID to something unique in a text editor, then reload the animation.
+You'll need to fix all animations but the _Shift_ and _Shift+Ctrl_ modifiers should help to get this done quickly.
+
+* _Help, i modified the anim XML by hand and now it doesn't load anymore!_
+ Your edits probably added an error, making the XML invalid. Check that:
+ - Each `` is properly closed with ``
+ - Each single-line tag is closed at the end (`` - note the trailing __/__)
+ - Attributes appear only once in a tag (`` is invalid, since `rq` appears twice)
+ - Attributes must be quoted, `idx=0` is invalid, should be `idx="0"`.
+
+* _Help, i modified the anim XML by hand and now the game crashes when trying to load it?!_
+ - Check that all bones referenced with `pidx="..."` exist
+ - `pidx="-1"` for no parent is fine too
+ - Check that you didn't set any bone's `idx=` and `pidx=` to the same value
+ - Check that you didn't create a cycle - ie. if you have two bones like this: `` and ``
+ they try to set one another as parent and that will crash. Always make sure that following all `pidx` links will eventually lead to a bone with `pidx="-1"`.
+
+
+* _I've set a bone's `pass=` to something other than 0, in the editor it's fine but in-game that bone doesn't show up?_
+ - Make sure the entity is spawned on LR_ENTITIES. This is the default if you don't move it in the entity script.
+ - If you really want the entity on another layer, make sure that that layer has the correct pass limits set -- use `setLayerRenderPass()`.
+ - NB: The animation editor spawns its animation puppets on LR_ENTITIES. If you use non-standard layer pass limits then you'll want to make sure that the pass limits of
+ LR_ENTITIES are set to cover the full range of render passes any of your animations use, otherwise you won't see those bones that exceed the pass limits.
+
+* _I've set up bones to render across different layer passes and it's working in the editor, but in-game the passes are completely ignored?_
+ - Make sure that the entity script doesn't call `entity_setRenderPass()` -- if the _entity_ has a render pass set, all bones will use the render pass of the entity they belong to and ignore their own.
+ This is special-cased in the engine for backwards compatibility reasons, and there's hardly any reason to set a render pass for an entire entity at once. Use bone passes and never set entity passes.
diff --git a/animation-tutorial.md b/animation-tutorial.md
new file mode 100644
index 0000000..1046258
--- /dev/null
+++ b/animation-tutorial.md
@@ -0,0 +1,114 @@
+# Animation tutorial
+
+TODO
+
+
+# Best practices
+
+## Save often!
+
+This applies to the rest of the editor, too. It's easy to mess up, undo is not always reliable, and in some cases loading an old version is the only sane way to fix a mess.
+
+## Proper centering
+
+If you plan to make an animation file that has more than a small handful of animations,
+it's highly recommended you design your graphics in such a way that the rotation points are centered.
+
+It may seem like a small issue but if you don't do this then you will quickly rack up technical debt that will be a real headache to fix the later you decide to fix it.
+Therefore try to make ALL your graphics with proper rotation points to avoid the issue altogether.
+They didn't do this in the base game so most animations actually exhibit this issue.
+
+To understand the problem, here's an illustration. These are 3 tiles used in the "mia" animation:
+
+
+![](images/leg1-original.png)
+![](images/leg2-original.png)
+![](images/arm1-original.png)
+
+The images have a grey box around them for clarity, and the image centerpoint is marked with a pink dot. When rotated, the image rotates around this point.
+
+![](images/mia-original.png)
+![](images/mia-original-rot.png)
+
+On the left, the animation is in its original state. When we try to rotate a couple bones, the joints detach because the rotation is around the center, not where we'd expect the joint to be.
+This animation frame can be fixed by also adjusting the position of the rotated bones so that the joints again line up properly,
+but this is prone to look bad when the animation is playing. The only solution is to add more animation keyframes but this is a lot of work.
+
+The lower leg clearly needs to be rendered before the parent (so that the parent is drawn over it; `rbp="1"` in the XML file), otherwise the blackness around the "knee" would show up and look weird.
+
+Also, there is only one arm tile, so the other arm needs to have `fh="1"` set, which may cause issues.
+
+------
+
+The solution is to pad the graphics with transparency so that the center point is also the point where the joint logically rotates around.
+
+To avoid `fh="1"`, we introduce a second, flipped version of the arm sprite.
+
+![](images/mia-frontleg1-skin.png)
+![](images/mia-leg2-centered.png)
+![](images/mia-backarm1-skin.png)
+![](images/mia-frontarm1-skin.png)
+
+The lower leg has also been changed to look better, and render with `rbp="0"` instead. Naija's legs are very well done to mask the knee transition, use that as a guide in case you design legs.
+
+
+With this change, the rotation around the joints looks more natural, and no position adjustment is needed:
+
+![](images/mia-better.png)
+![](images/mia-better-rot.png)
+
+For a good coomparison, check naija.xml (good) vs. mia.xml or li.xml (bad).
+
+Also note that the head is an exception and doesn't need to be centered on the neck. Just use naija.xml as a reference and it'll be fine.
+
+
+### Fixing this later
+
+In case you decided to ignore this issue until the point where it can't be ignored anymore, or want to change/extend some existing (bad) animations and properly center them,
+there's a way to do this:
+
+First, modify the graphics of all offending bones so that they are properly centered. Load the animation; it will look messed up.
+To fix it, pick a pose to use as a reference (usually "idle" is fine), then move all bones back into a good-looking position while holding _Ctrl+Shift_.
+
+Afterwards, go through all animations and all keyframes and make sure they look good. __DON'T hold _Ctrl+Shift_ anymore at this point!!__
+Most should be OK and not require touch-ups, but some will still need manual fixing.
+
+Good luck and don't forget to save often!
+
+
+## Layer passes are global
+
+Try to not use layer passes (ie. anything that is not `pass="0"`) if you can avoid it. If you have some bones rendered in the wrong order,
+try to fix it with re-arrangement or changing `rbp=` of some bones if possible.
+
+If you really do need to set a layer pass that is not 0, keep this in mind:
+
+The layer pass applies to ALL entities in that layer, ie. when the layer is drawn, the passes are drawn in order.
+That means first the game goes over all entities and all their bones and draws anything that is to be drawn in that pass. Then it repeats that for each pass.
+
+Therefore, don't think about an entity in isolation, think about how it might look when it goes around and mingles with other entities.
+If you need eg. the front arm to be in front and its bones have a high pass, it will look fine in isolation.
+But when the entity goes behind another entity, then the arm will still be rendered in front because the game draws all passes separately and the arm goes on a higher pass than anything else.
+What you'll end up with is a detached looking arm floating in front while the entity it's attached to is covered by something else.
+
+TL;DR Layer passes work best when used in cutscenes and stationary animations, but avoid using this for bone ordering for regular gameplay.
+
+Fun fact: Layer passes were introduced for _The Hug_ (ie. Naija and Li hugging when you leave them alone for a few seconds):
+- Naija is always drawn in front of Li.
+- To make sure his arm goes over her body when hugging, it's set to a higher pass value while the hug is active, and set back to 0 when the hug ends.
+- To see this in action, enter hugging state, then hold _Shift+F_ in developer mode to slow down time, then right-click the pair to break the hug.
+ The arm immediately goes behind her body because the layer pass is reset.
+
+### Modify layer passes for single animations
+
+If you need layer passes for an animation, cutscene, or other specific things, you can change a bone's pass on the fly, even mid-animation.
+Use the __AC_SET_PASS__ and __AC_RESET_PASS__ bone commands for this. If you just need to change the pass for a single animation, put all __AC_SET_PASS__ on the first keyframe.
+
+To make sure the pass settings don't stick and affect other animations played afterwards, add the `resetPassOnEnd` tag to each animation that uses these bone commands:
+```xml
+
+...
+
+```
+
+This way, you don't have to take care of __AC_RESET_PASS__ or extra scripting to reset the pass back to its original value.
diff --git a/images/arm1-original.png b/images/arm1-original.png
new file mode 100644
index 0000000..1a6ec46
Binary files /dev/null and b/images/arm1-original.png differ
diff --git a/images/leg1-original.png b/images/leg1-original.png
new file mode 100644
index 0000000..f31fae2
Binary files /dev/null and b/images/leg1-original.png differ
diff --git a/images/leg2-original.png b/images/leg2-original.png
new file mode 100644
index 0000000..d43245f
Binary files /dev/null and b/images/leg2-original.png differ
diff --git a/images/mia-backarm1-skin.png b/images/mia-backarm1-skin.png
new file mode 100644
index 0000000..f831013
Binary files /dev/null and b/images/mia-backarm1-skin.png differ
diff --git a/images/mia-better-rot.png b/images/mia-better-rot.png
new file mode 100644
index 0000000..018ad29
Binary files /dev/null and b/images/mia-better-rot.png differ
diff --git a/images/mia-better.png b/images/mia-better.png
new file mode 100644
index 0000000..02109b6
Binary files /dev/null and b/images/mia-better.png differ
diff --git a/images/mia-frontarm1-skin.png b/images/mia-frontarm1-skin.png
new file mode 100644
index 0000000..3ff7655
Binary files /dev/null and b/images/mia-frontarm1-skin.png differ
diff --git a/images/mia-frontleg1-skin.png b/images/mia-frontleg1-skin.png
new file mode 100644
index 0000000..aa18ad5
Binary files /dev/null and b/images/mia-frontleg1-skin.png differ
diff --git a/images/mia-leg2-centered.png b/images/mia-leg2-centered.png
new file mode 100644
index 0000000..74a68a8
Binary files /dev/null and b/images/mia-leg2-centered.png differ
diff --git a/images/mia-original-rot.png b/images/mia-original-rot.png
new file mode 100644
index 0000000..2e4e065
Binary files /dev/null and b/images/mia-original-rot.png differ
diff --git a/images/mia-original.png b/images/mia-original.png
new file mode 100644
index 0000000..42956ee
Binary files /dev/null and b/images/mia-original.png differ