Skip to content

Release 3.5.0 - #61

Open
dimensionscape wants to merge 41 commits into
masterfrom
release/3.5.0
Open

dimensionscape wants to merge 41 commits into
masterfrom
release/3.5.0

Conversation

@dimensionscape

@dimensionscape dimensionscape commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Prepares the 3.5.0 release.

Fixes

Changes

This also releases the fixes already on master since 3.4.0. CHANGELOG.md has the full list.

Tests

Each fix has a test that fails on master, and the performance changes have tests that check their output is unchanged.

  • tests/ gains cases for fonts, both timelines, shape export, morph shapes, Animate libraries and sounds, and SWFLite export.
  • tests/tools is a new neko suite for the command-line tools, which need sys and hxp. It runs in CI as unit-test-tools.
  • unit-test-neko-defines runs the tests with each opt-in define, and with both.
  • tests/tools also exports SWF files built in code with the Animate exporter, including a shape tween, and plays them with AnimateLibrary, with and without compact timelines.
  • unit-test-html5 runs the tests in headless Chrome. They never started on HTML5 before, since OpenFL 9.4 only starts utest apps there with openfl_enable_utest_legacy_mode.
  • CI uses Haxe 4.3.7.

Merging closes #7, #21, #22, #36, #41, #42, #45, #46, #47, #49, #50, #54, #55, #56, #57 and #59. #44 stays open for its instance property work.

dimensionscape and others added 30 commits October 26, 2026 18:45
…closes #22)

The no-layout branch always skipped 2 extra bytes, which only matches a
CodeTableOffset written for fonts with no glyphs. Skip that offset only
when there are no glyphs and the tag still has bytes for it.
Merged with #54: compact commands also encode LINE_GRADIENT_STYLE, using
the same layout as BEGIN_GRADIENT_FILL, and the regression test covers it.
SymbolClass uses character ID 0 for the document class, which is not
always named *_fla.MainTimeline. Extracted from #44.
Cache Type.getInstanceFields() results per class name in SymbolTimeline and
AnimateTimeline to avoid repeated reflection during clip attachment/update.
This reduces CPU and GC pressure when many symbols are instantiated.

The PR's change to only clear filters on reset is left out, since it is a
separate behavior change.
…nimate classes when generate="true" (closes #47)

Both library branches now share one cache, obj/libraries/<name>.classes.json,
holding the prefix, the classes to compile and the generated templates. The
templates are added again on a cache hit, because Lime deletes generated
files that are no longer project assets.

With generate="true", Animate libraries now compile their generated classes,
so symbols are created as their linkage class even when nothing else
references it. Classes that depend on ActionScript classes from outside the
library, such as fl.controls.* components, are left out, since they would
not compile.
…g them (closes #46)

Generated MovieClip and SimpleButton classes always initialized from the
library they were generated for, so another library exporting the same class
name created instances with the wrong symbol. Libraries now record the symbol
being instantiated, and generated classes use it when they are that class or
one of its base classes, falling back to their own library when created with
"new".
Linked DefineSound symbols are exported as sounds/<id>.mp3, or as WAV for
uncompressed PCM, and AnimateLibrary resolves their linkage names in
getAudioBuffer() and loadAudioBuffer(). On HTML5, bundled sounds are decoded
from the bundle bytes, which Lime does not do itself. ADPCM, Nellymoser and
Speex sounds cannot be exported, so they are skipped with a warning.

Speex now maps to its SWF format value (11) instead of 7, which made exports
of SWF files with Speex sounds fail, and SWFLiteExporter records linked sound
class names.

This keeps the sound export from #45 without its additional linkage
discovery or the list() changes.
…WFLite exports

Adds tests for each fix in this release: DefineFont2/3 parsing, clipDepth
masks and instance reuse on both timelines, named child fields, shape
export output and line gradients, Animate libraries without a UUID, linked
sounds, and SWFLite root and sound linkage.
The tools need sys and hxp, so they run as a separate neko suite in
tests/tools. They cover generated class templates and paths, the classes
compiled with generate="true", the generated class caches, the root
symbol, and linked sound and line gradient export.
… on Flash

On Flash, ByteArray.position is UInt, and Haxe 3 does not allow comparing
it with an Int.
Generated classes are named with the library prefix, but symbols looked up
their class by the linkage name, so they were created as a plain MovieClip.
Generated MovieClip and SimpleButton classes now register themselves by
library and symbol ID, and symbols use that class first.

A generated class whose base class comes from the same library now extends
that base class's generated name, with the same prefix.
Haxelib.getVersion() without an argument returns the version of Lime. The
version now comes from the haxelib.json next to run.n.
With -D swf_compact_animate_timelines, Animate timeline events are kept in
compact numeric buffers instead of one AnimateFrame and AnimateFrameObject
graph per frame and event, and are decoded during playback.

Changes from #57: the default path shares instance placement and masking
with the compact path, unchanged, so both apply clipping masks and clip
depths the same way. Filters are kept parsed and created by the same code
as the default path, so unknown filter types only skip that filter. Frame
objects without a symbol, depth or clip depth, such as the DESTROY records
the exporter writes, are stored with 0 instead of null. Tests
check that both paths play the same frames the same way, and CI runs the
tests with the define.
With -D swf_hardware_bitmap_cache, bitmaps used directly share one
BitmapData each, and release their decoded CPU image after the texture is
uploaded.

Changes from #56: shapes are not probed with OpenFL's hardware graphics
check. OpenFL only draws rectangles, quads and triangles in hardware, so
Animate shapes, which are drawn with lineTo and curveTo, always use
software rendering and need the pixels of their bitmap fills. Bitmaps used
by shapes are now marked readable when the library loads, from both compact
and expanded shape commands, which also covers scale9 grids. CI runs the
tests with the define, and with both opt-in defines.
Finding the embedded font for a dynamic text field looks through every
registered font, and with regular expressions when there is no exact match.
Each symbol now keeps the result until another font is registered. The
matching itself is unchanged.

From #42, without its class resolution caches, which saved little and could
hide classes from SWF files loaded later.
The SWF parser imports format, but haxelib.json did not declare it, so
installing swf from haxelib did not install it. CI now checks that
haxelib resolves format through swf.

Also refreshes the haxelib release note, notes the new LineGradientStyle
enum constructors in the CHANGELOG, and runs CI with Haxe 4.3.7.
calculateMaxBits() counted 8 bits for each decimal digit of a value, so
larger values overflowed the bit count fields when publishing: from 10 in
color transforms, from 100 in shape edges, and from 1000 in matrices and
rectangles. A signed -1 also got 0 bits. It now returns the smallest size
that holds every value.
The tools suite exports a SWF built in code with the Animate exporter,
loads the result with AnimateLibrary and checks each frame, including
rewinding, then runs again with compact timelines.
OpenFL 9.4 and later only start utest apps on HTML5 with
openfl_enable_utest_legacy_mode, so the HTML5 tests never ran. CI now runs
them in headless Chrome, with and without the opt-in defines.

Howler plays sounds on HTML5 without exposing their samples, so the sound
tests check for its sound there instead of the sample rate.
swf now declares the format dependency, so haxelib no longer resolves swf
without it. haxelib install swf installs it, but haxelib dev does not, so
the samples job installs it like the other jobs.
The compact timeline kept blend modes as strings and cast them to
BlendMode, which OpenFL only stores as a string on Flash, so they were not
applied on other targets. They are now converted when the timeline is
parsed, as the default timeline does. The test comparing the compact and
default timelines now checks blend modes.
TagDefineMorphShape.export() turned every style change into a move, so a
fill change in the middle of a path moved the pen to the origin, and it
paired a move in the end edges with the next start edge. It also rounded
each edge on its own, so paths could stay open between the start and the
end. getMorphedShape() now tracks the start and end pen positions, adds
the moves either side makes, and rounds positions instead of deltas.
Edges that do not match throw an error.

Morphed fill styles also handle focal gradients and keep the gradient
spread and interpolation modes, lines with a fill change width, and
DefineMorphShape line styles start with their flags off.
Animate libraries skipped DefineMorphShape and DefineMorphShape2, so shape
tweens were missing on HTML5 and native targets. The exporter now draws
each morph shape at every ratio its timelines use, and frame objects carry
the ratio, which both timeline paths apply by drawing the closest shape.
Paths are joined by matching points, so the start and end shapes can have
different commands, and cannot be interpolated as commands at runtime.

Morph shapes whose start and end edges do not match are skipped with a
warning, and bitmaps used by their fills stay readable with
swf_hardware_bitmap_cache. The round trip test exports a shape tween and
plays it, and the timeline test plays one on both timeline paths.
Headless Chrome hung in one HTML5 test run until the job limit of 6 hours,
which also kept the rest of that run from being rerun. Each attempt now
stops after 2 minutes, the step tries up to three times, and the step has
its own time limit.
Before Haxe 4.2, the HashLink standard library creates the thread message
queues without a lock, so when Lime starts a loading thread and sends it a
message, both threads can set them up at once and one reads a null array.
It crashed the Haxe 4.0.5 tests before any test ran, in two runs in a row.
Lime's force-synchronous define loads assets without threads, so the
HashLink tests use it with Haxe 4.0.5 and 4.1.5.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrect capitalisation in package directory

4 participants