dragonbones 0.4.0
dragonbones: ^0.4.0 copied to clipboard
Pure-Dart runtime for the DragonBones 5.x skeletal animation format: parses DragonBones Pro exports and evaluates armature, bone, mesh and IK timelines. Zero dependencies.
dragonbones #
A pure-Dart runtime for DragonBones skeletal animation (text/JSON format 5.x).
The defining property of this package is that it has zero dependencies — no Flutter, no platform channels, no third-party packages. That is not minimalism for its own sake:
- it can be verified with a bare Dart SDK, with no GPU and no device, which is how the maths is proven correct (see Correctness);
- it runs anywhere Dart runs, including the web and headless on a server;
- it can back a Flutter renderer, a game engine's component, or your own
Canvascode, without dragging a gameplay engine along.
import 'dart:convert';
import 'package:dragonbones/dragonbones.dart';
final factory = HeadlessFactory();
factory.parseDragonBonesData(jsonDecode(skeJson), 'Dragon');
factory.parseTextureAtlasData(jsonDecode(texJson), null, 'Dragon');
final armature = factory.buildArmature('Dragon', 'Dragon')!;
armature.animation.play('stand');
armature.advanceTime(1 / 24);
// Read back the frame as a framework-agnostic draw list.
for (final slot in armature.buildDrawList()) {
print('${slot.name}: ${slot.matrix}');
}
HeadlessFactory is a concrete BaseFactory that binds no renderer at all. A
real binding subclasses BaseFactory and Slot instead, and draws the displays
— that is exactly what
dragonbones_flutter does.
Correctness #
This is a faithful transcription of the upstream TypeScript runtime
(DragonBonesJS) — but a transcription is a claim, not a proof, so it is
diffed against the official runtime:
tool/parse_check.dart structural: 1527 assertions over the parsed model
tool/check_against_oracle.dart replays every fixture frame by frame and compares
bone matrices, slot draw data, posed mesh vertices
and nested-armature slots against dumps produced
by the official runtime
Result on the current commit:
1353695 numeric comparisons over 56 assets (56 clean, 0 failing)
205259 mesh values, 1228 nested-armature slots
RESULT: PASS
~5e-7 is the rounding precision of the reference dumps themselves, so the port is effectively exact. Both scripts run in CI on every push.
The 56 assets are the hand-picked ladder (Dragon, 龙, mecha_1004d), the
entire DragonBones Unity SDK demo set, and the feature fixtures — animated
IK, Surface bones and animation blending. One of them (you_xin/body) is 71
frames, 70 bones, 6,816 slot draw data and 47,357 mesh values in a single asset;
another (shizuku) has 117 Surface bones.
What is implemented #
- geom:
Matrix,Transform,Point,Rectangle,ColorTransform - model: the full 5.x data model — armature, bone, slot, skin, display, animation, timeline, texture atlas, user data, including mesh/geometry/weight data and constraints
- parser:
ObjectDataParserfor the text/JSON format, including the packed binary frame arrays that format 5.5 embeds in the JSON - armature:
Armature,Bone,Slot(render hooks left abstract),TransformObject,IKConstraint,Surface - animation:
WorldClock,Animation,AnimationStateand the timeline states — bone all/translate/rotate/scale, slot display/colour, action, z-order, deform (FFD), animated IK,Surfacedeformation, animation blending (AnimationProgress/Weight/Parameter), and alpha/z-index - events:
EventObjectandIEventDispatcher— frame events and sound events placed on the timeline, thestart/loopComplete/complete/fadeIn/fadeOutlifecycle events, andgotoAndPlayactions, all dispatched (buffered) after the frame is posed - render:
Armature.buildDrawList(), which flattens nested child armatures and emits the complete per-slot geometry a renderer needs
What is NOT implemented #
Each of these is parsed but not evaluated, so a file using it will load and mostly animate, then be subtly wrong rather than fail loudly.
- Path constraints (
PathConstraint) — data parsed, never built. - Binary
.dragonbonesinput (BinaryDataParser) — JSON export only.
That is the whole list. Animated IK, Surface bones and animation
blending were implemented in 0.4.0 and are verified against the official
runtime.
Deviations from upstream (deliberate) #
- No object pooling. Upstream implements a per-class pool
(
BaseObject.borrowObject). Dart's GC handles this, so objects are constructed directly. This is the single biggest structural difference from the reference implementation, and it has not been benchmarked. - JS array growth. Upstream grows arrays with
list.length = n, which in JS creates holes. Dart cannot do that for non-nullable element types, so those sites were rewritten to append. - An upstream bug was NOT transcribed.
Slot.set displayFrameCount, removal branch, readsfor (let i = prevCount - 1; i < value; --i)— the condition is never true, so the upstream loop body never runs. The port usesi >= valueso the removal actually happens. - Unused-member and redundant-cast lints are silenced in
analysis_options.yaml, because a transcription keeps members a given milestone does not exercise yet.
See also #
- Documentation site — https://docs.page/RafaelBarbosatec/dragonbones_flutter
dragonbones_flutter— theCanvasrenderer.- The repository, for the oracle harness and the reference dumps: https://github.com/RafaelBarbosatec/dragonbones_flutter.
Licence #
MIT. The DragonBones runtime and format are MIT (© DragonBones team and contributors).