About This File
What is this?
The Advanced Animation Framework (AAF) provides a variety of tools for modders to play animations from a scalable number of animation packs.
Download Location & Instructions
The latest version of AAF is hosted at the AAF discord. The reason for this is that Nexus has terms for hosting files that I find unreasonable (once uploaded they gain the right to distribute a mod forever). Also, AAF is not an adult mod by itself and there are non-adult mods using it. So, LL, being an adult-focused site is not the right place to host. The issue has already been debated extensively in this thread. You can dig through the pages to find those discussions if interested. However, the matter is considered closed now. Further discussion about where AAF is hosted, how that impacts anyone or anything, is not allowed in this thread. If you wish to discuss those things, please bring them up in some other thread.
For the latest AAF version, news and information:
Official AAF discord
For NSFW user support with the TFM guide:
Donations
If you are interested in supporting this project, you can donate through my Patreon page.
Edited by dagobaking
What's New in Version 1.5.5
Released
# Version 1.5.5 (2026-04-12)
Hotfix for a scene-breaking cascade bug. A single broken third-party position (e.g. missing animationGroup) could silently wipe the tag data of every position loaded after it, causing "no matching animations" errors for completely unrelated scenes.
## Fixed
- A position whose `initialize()` threw an exception (e.g. from a broken positionTree chain) aborted the entire position initialization loop. Every position loaded after the broken one was left with empty tags and a null animation reference — making those positions invisible to scene filters. Now each position initializes inside its own error boundary; a broken one is cleanly removed without affecting the rest.
- Null-check `positionTree` reference before calling `.validate()` to prevent a null-pointer crash when `Model.positionTree.getByID()` returns null (tree not found).
- `BranchNode.validate()` now also checks that the referenced position has a valid animation reference, not just that the position exists. Catches broken sub-positions at validation time instead of letting them throw downstream.
- Animation group stages that reference a missing animation ID are now warned via the Errors tab (`$MISSING_ANIMATION_DATA`) instead of being silently dropped. Previously there was no indication of why a group had no playable stages.
- Position initialization exceptions caught by `Model.processData` are now surfaced in the AdminWindow Errors tab. Previously they were only visible with `troubleshooting_level >= 2` (off by default), making cascade failures completely invisible to users.
# Version 1.5.4 (2026-04-09)
Hotfix for the 1.5.x line. Restores compatibility with several mods that were silently broken when xmlutility switched to libxml2 in 1.5.2. No changes to the F4SE plugin, ESM, scripts, or Flash — only `xmlutility.dll` and `aaf.xsd` are updated.
## Fixed
- libxml2 strict parsing rejected XML files with minor W3C violations (duplicate attributes, unescaped `<` in attribute values, attribute construct errors) that the pre-libxml2 hand-written parser silently tolerated. xmlutility now parses with `XML_PARSE_RECOVER`, producing a usable tree even when the XML has recoverable errors. The first parse error is logged as `XML parse recovered in <file> (line N): <msg>` to `xmlutility.log` for diagnosis. Restores loading for files with duplicate `value=` attribute on `<morph>`.
- 0-byte XML files (commonly placed by patch mods to block other mods' files via load-order conflict) were surfaced as `Failed to read file` errors and counted in the in-game `XML_ERRORS_SUMMARY` notification. They are now silently skipped, restoring the pre-1.5.2 behavior the patch ecosystem depends on. A single `File is empty (0 bytes), skipping: <path>` info line is written to `xmlutility.log` for diagnosis.
- XSD validation failures now log a warning to `xmlutility.log` and the file still loads, instead of being rejected entirely. The `aaf.xsd` schema lagged behind real-world XML usage (custom attributes, capitalised booleans, missing element types), and rejecting otherwise-valid files for schema mismatches caused mod animations to silently fail. Validation warnings are still useful for diagnosis but no longer break loading.
- xmlutility error reporting now distinguishes three failure modes that previously all collapsed into `Failed to read file`: `Failed to open file:` (true I/O failure), `File is empty (0 bytes), skipping:` (benign empty file), and `File contains only BOM, skipping:` (BOM-only file). Bug reports from `xmlutility.log` are now actionable.
## XSD Schema
- Added `idle` and `mfg` as valid child elements of `actorType`. The Flash code (`ActorNode.as`) explicitly supports both the old format (`<actor><idle form="..." source="..."/></actor>`) and new format (`<actor idleForm="..." idleSource="..."/>`). The XSD previously only allowed the new format, rejecting any animationData file using the old format. The orphan `idleType` definition is now wired into `actorType`.
- Replaced `xs:boolean` everywhere with a new `aafBoolean` simpleType that accepts case-insensitive `True`/`False`/`TRUE`/`FALSE`/`true`/`false`/`0`/`1`. AAF Flash has always parsed boolean attributes case-insensitively (via `.toLowerCase()`), and the wiki itself documents `False` (capitalised) as a default value. `xs:boolean` only accepts strict `true`/`false`/`0`/`1`, which rejected valid mods.
- Made `<defaults>` element optional (`minOccurs="0"`) in all 32 dataType definitions where it was previously required. Mods that don't need to set defaults can omit the element entirely.
- Added `form` and `source` attributes to `mfgSetType`. Both are documented in the wiki and read by `MFGSetNode.as`, but were missing from the schema.
# Version 1.5.3 (2026-03-31)
## Added
- DLL-accelerated body morph path via F4SE templates. Falls back to Papyrus automatically if the DLL call fails.
- Consolidated DLL logging into shared `Log.cpp` to prevent log corruption from multiple file handles.
- Localization strings `$MORPH_DLL_FAILED` [096] and `$MORPH_DLL_EXCEPTION` [097] for morph error reporting.
- SEH crash protection (`SafeCall.cpp`) compiled with `/EHa` in isolation to catch engine-level exceptions without affecting F4SE exception handling.
## Changed
- Theme `version` attribute in XSD changed from `xs:float` to `xs:string` to support semver (e.g. `"0.5.1"`).
# Version 1.5.2 (2026-03-22)
## Added
- `protect_custom_equipment` INI setting (default `true`). When enabled, equipmentSets (startEquipmentSet) will not unequip items that have customEquipment states defined. This prevents multi-slot items from being stripped before equipmentRules can change their state. Equipment rules (via action tags) manage custom equipment instead.
## Fixed
- Fixed custom equipment state not reverting to normal at scene end. When a stopEquipmentSet with `resetAll="true"` fires, custom equipment that was state-changed during the scene is now properly reverted to its default state.
- Fixed equipmentRules wiki documentation showing slot numbers instead of slot names in the example.
## Previously Added
- libxml2 XML parser replaces the hand-written parser in xmlutility.dll, providing detailed parse error messages with file paths and line numbers instead of generic "Failed to parse XML structure" messages.
- XSD schema validation for new-format XML files. When `aaf.xsd` is present alongside `xmlutility.dll`, XML files are validated against the schema and violations are reported with file path, line number, and a description of what is wrong (e.g., unknown attributes, missing required attributes). Controlled via `XSDPath` setting in `xmlutility.ini`. Disabled by default when the XSD file is absent.
- XML loading errors are now visible to all users in the AdminWindow Errors tab, not just in debug mode. A summary notification is shown after loading if any files had errors.
- XML loading errors are also written to `xmlutility.log` immediately during parsing, so errors are preserved even if the game crashes during initialization.
- XSD schema updated: all data type definitions now allow empty content (only root element and defaults present), supporting the workflow of commenting out all content temporarily. `source` attribute added to `race` elements in raceData.
- `%NONE%` animation for immediate switchTo. AnimationGroup stages can use `animation="%NONE%"` with a `switchTo` attribute to instantly switch positions without playing any animation. Useful for positionTree navigation where no intermediate animation is needed.
- Cross-tree back navigation. When a switchTo navigates from one positionTree to another, the left arrow now goes back to the previous tree at the branch the user was on. Maintains a per-scene history stack supporting multiple levels of back navigation.
- Animation group stages can now navigate position trees via treeOutcome (back/advance) for random-outcome decision loops.
- forceComplete on a positionTree branch locks the tree widget during treeOutcome decision loops until an outcome fires.
- Updated XSD schema with treeOutcome and treeTarget attributes.
## Changed
- aaf.log (F4SE plugin log) is now truncated on each game launch instead of appending indefinitely.
## Fixed
- Fixed switchTo on animationGroup stages not changing the visible animation on actors. The game engine's animation graph was not accepting new idles when switched rapidly; a graph reset is now forced before applying new idles during switchTo transitions.
- Fixed switchTo on animationGroup stages within a positionTree not navigating the tree. Previously, switchTo bypassed the tree menu entirely — the position changed but the tree widget, branch selection, and forceComplete state were not updated, causing the tree to desync or cycle back. switchTo now properly navigates the tree menu to the target branch (searching current level first, then sibling level), keeping the tree widget, branch state, and forceComplete in sync.
- Fixed switchTo and treeOutcome on animationGroup stages permanently breaking stage progression when the target position was not found. Previously, an unresolved switchTo target would halt all stage cycling. Now logs a warning and continues normal stage progression.
- Fixed transition lookup inconsistency for positionTree nodes. Transitions with a positionTree as the destination now correctly resolve to the tree's root position ID, matching the existing behavior for source positionTree nodes.
- positionConfig attributes (isHidden, stopEquipmentSet, tags, location, etc.) now properly apply to positions auto-created from animationGroupData and positionTreeData XML. Previously only the id and group/tree reference were copied, causing isHidden and other positionConfig attributes to be ignored.
- AnimationGroupNode.parse() now falls back to id when animation attribute is omitted on stage nodes, matching StageNode behavior.
- Position removal messages now include the specific reason for removal (e.g. which animation or animationGroup was not found) instead of a generic "due to error" message.
- Fixed XML files with UTF-8 BOM (byte order mark) failing to load in xmlutility, causing all animations in the affected file to be missing. Common with files saved by Windows text editors.
## Documentation
- Position XML marked as legacy/obsolete; positionConfig is the recommended approach.
- Wiki updated for treeOutcome, treeTarget, and forceComplete interaction with positionTree.
# Version 1.5.1
## Added
- Ability to tie a morphSet to an AAF stat. This way an author could change morph values on an actor and also have that change affect AAF conditions.
- More sensitivity to the gender override keywords. If added, should affect Actors on next AAF scene without needing to reset AAF or other workarounds.
- Individual animation nodes can now specify isHidden to override the positionConfig-level default, eliminating the need to split animations into separate files based on visibility.
- positionTreeData defaults now supports prefix, which is applied to both tree IDs and branch positionID values.
- Updated the .xsd file on moddingham.com
- Restored: MCM hotkey to reset the fly-cam back to the player's location during animations. Tested with no actors going invisible.
- Restored: Power Armor is now protected equipment by default, preventing AAF from removing it during animations.
- Restored: Increased default actor and furniture scan radius from 500 to 1500 units.
- In positionTree branches, id and positionID are now interchangeable — each falls back to the other if omitted. In animationGroup stages, id can now be used in place of animation.
## Fixed
- Auto-position creation from positionTree XML initialization order.
- altLocation not working when no animations with the location property were registered in XMLs.
- Fixed suffix variations (e.g. "-one", "-2ndVariation") not being created when any old-style positionTree entry was present in the load order.
- Flycam speed was stuck going too fast.
- Silent freeze at 11% when AAF DLL is missing or no data files are found; now displays actionable error messages instead of hanging.
- Fix AAF DLL failing to load on game version 1.11.191+ (F4SE 0.7.7+) due to missing F4SEPlugin_Version export, which caused AAF to freeze at 11% initialization.
## Compatibility
- This version of AAF only works with game versions 1.10.163 and 1.11.191.
# Version 1.5.0
## Fixed
- Bug where animations with combined gender+skeleton requirements were being matched incorrectly. The system now validates gender and skeleton combinations together instead of separately, preventing incompatible actor pairings from passing filter checks.
- EquipmentLayerDataSet XML warning about missing plugin null incorrectly.
- Protected equipment handling interfering with other equip/unequip actions.
- Protect MFG effects of protected equipment.
## Added
- Users can now omit position XML files for animationGroup and positionTree definitions by including a positionConfig key in their XML. The system will automatically generate positions with the appropriate animationGroup or positionTree attribute references, reducing redundant XML file creation.
- Improved XML loading/parsing speed.
- Real-time keyword validation for actors, allowing for dynamic keyword queries during scene execution. Replaces the old keywordWatchData system.
- Code optimizations for scene start/filtering.
- Code optimizations for scene loop code. Should allow better scaling in terms of simultaneous scenes and/or more actors in a scene at once.
- Feature to override actor scale defaults per animation or per XML file (see animationData documentation).
- positionID and position tags to OnSceneInit.
- 2-Way sync for ActorValues when used with AAF stats.
- A per action (from animationData) tryRate and chance over-ride for topicGroup calls (see animationData documentation).
## Compatibility
- This version of AAF only works with game versions 1.10.163 and 1.11.191.