Skip to content

About

Compile ActionScript 3 source code ahead-of-time (AOT) into native machine code, producing native executables — while keeping the AS3 syntax you already know.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

15 Commits

Folders and files

Repository files navigation

A native AOT compiler for ActionScript 3

Compile ActionScript 3 source code ahead-of-time (AOT) into native machine code, producing native executables — while keeping the AS3 syntax you already know.

Design philosophy: the compiler frontend only handles lexing → parsing → generating readable C, delegating optimization and machine-code generation entirely to mature C compilers — no reinventing the wheel.


🎬 Video

as3compiler-aot-promo.mp4

Compilation pipeline

ActionScript source (.as)
        │  lexer.ts      lexical analysis (tokens)
        ▼
        │  parser.ts     recursive-descent parsing (AST)
        ▼
        │  codegen.ts    semantics + C code generation
        ▼
       C source (.c)
        │  build orchestration src/build.ts
        │  (build manifest JSON + -I/-L/-l/-D + --target)
        ▼
  ┌──────┴───────┐
  │ native        │  cc/clang -O2 -lm                 → native executable (Mach-O / ELF / PE)
  │ wasm          │  clang --target=wasm32-wasip1     → WASI .wasm
  └──────────────┘

"Generating a single readable .c" is the default form (simple to build, easy to read), not a law against linking third-party libraries: when implementing heavy lifting such as graphics (skia/cairo/SDL), the correct approach is to link mature libraries (-lskia) rather than hand-rolling rasterization. See "Build & Linking" and AGENTS.md §2.9.

Running

Install (gives the as-aot command): npm install -g as3compiler (or locally npm link). If not installed, use node src/index.ts ... or npm run compile -- ... equivalently.

Requirements: Node ≥ 22.6 (native support for running .ts directly, no compilation step), and a system cc/clang; --target wasm needs the WASI SDK (WASI_SDK_HOME pointing at the SDK root, or an LLVM clang with a wasm32 backend), and running the output requires a runtime supporting the exception-handling proposal (wasmtime/wasmer, see docs/en/compile.md §2); --target wasm --package web needs the Emscripten SDK (EMSDK_HOME pointing at the emsdk root, see docs/en/html5-web.md).

# Compile (default output: a file named after the input without extension, keeping the generated .c for reading)
as-aot examples/hello.as

# Compile and run
as-aot examples/fib.as --run

# Specify output name / specify the C compiler
as-aot examples/class.as -o build/class --cc clang --run

# Generate a macOS .app Xcode project (--package xcode-project: open/build/debug in Xcode, product is an .app)
as-aot src/Main.as --target native --package xcode-project -o build/Main

# Generate a browser HTML5-rendered page (--target wasm --package web, requires the Emscripten SDK)
as-aot examples/web/hello-web.as --manifest examples/web/hello-web.build.json

Build & Linking

Full compilation instructions (CLI arguments, build manifest JSON, multi-target backends, WASI toolchain) are in compile.md.

Supports multiple targets and linking third-party libraries:

# WASI target (requires the WASI SDK or a clang with a wasm32 backend)
as-aot examples/hello.as --target wasm

# Link third-party libraries (skia/cairo/SDL etc.): include paths / library paths / libraries / macro definitions
as-aot app.as -I vendor/include -L vendor/lib -l skia -D USE_SKIA=1

# Embed bitmap asset classes from an SWC (stage ninety-five): named assets become BitmapData subclasses,
# source can directly `new logo(0, 0)`, or reflect via getDefinitionByName("logo") then new
as-aot app.as --swc assets/skin.swc

# Build manifest (JSON, paths resolved relative to the manifest directory)
as-aot app.as --manifest examples/skia-link.build.example.json

# Export top-level functions for direct JS calls (default WASI command modules only export _start)
as-aot examples/wasm-native/fib.as --target wasm --export fib

# Declarative exports: mark functions/static methods with [WasmExport] metadata to auto-export and generate .exports.json
as-aot examples/wasm-native/export-meta.as --target wasm

# Generate a browser HTML5-rendered page (--target wasm --package web, requires the Emscripten SDK)
as-aot examples/web/hello-web.as --manifest examples/web/hello-web.build.json

# Only generate C and print the compile command, without actually compiling (verify the command without a toolchain)
as-aot examples/hello.as --target wasm --dry

# Keep debug info: all three backends add -g, and wasm's default DWARF stripping is turned off (source-level debugging in DevTools)
as-aot examples/wasm-native/fib.as --target wasm --debug-info

Build manifest (JSON) fields: target (native/wasm), package (raw/xcode-project/android-project/web, default raw, see compile.md §6), c-compiler, opt, debug-info (keep debug info, default false, see below), sources (additional C/C++ sources), include-paths, link-libs, link-paths, defines, objects (precompiled .o), exports (C symbols exported to the .wasm export table), swc-paths (a list of .swc libraries; their named bitmap assets are extracted at compile time, re-encoded to PNG after un-premultiplying, and embedded into the product, decoded by Skia at runtime; vector shapes and display trees (DefineShape*/DefineSprite/PlaceObject*) as well as nine-slice (DefineScalingGrid) and button four-states (DefineButton2) are likewise baked at compile time into runtime drawing calls — see docs/en/swc.md §5/§6/§9), font-urls (font byte-stream URL list for --package web, injected into Skia at runtime), plus the xcode-project app metadata bundle-id/display-name/icon/deployment-target (see compile.md §6.4). CLI arguments override manifest fields of the same name. Path-like fields resolve relative to the manifest file's directory. Example at examples/skia-link.build.example.json.

Per-target layered linking (targets): top-level fields are the common defaults; a targets.<native|wasm> block applies only to the matching target and replaces wholesale (replace, not append) the same-named top-level values — so one manifest can serve multiple targets with mutually exclusive link sets (the typical case: native links curl, but WASI has no sockets and -lcurl makes wasm-ld fail, so it must be dropped for wasm). Merge order: default configuration → manifest top level → manifest targets.<final target> → CLI overrides. Example examples/flash-net-layered.build.example.json, see compile.md §4.1.

Debug info (--debug-info / manifest debug-info, off by default): by default the product carries no DWARF on any of the three backends — native under -O2 has none anyway; emcc -O2 strips it itself; only the wasi backend's libc.a ships DWARF and wasm-ld keeps it by default (even an empty int main drags in ~19 KB), so the wasm link adds -Wl,--strip-debug by default (fib.wasm 421 KB → 133 KB; only .debug_* is dropped, the name function-name section is kept ⇒ traps still print symbolized stacks). Turning on --debug-info adds -g to all three backends and stops stripping wasm (fib.wasm ~640 KB, containing line numbers of the C we generate ⇒ source-level debugging in DevTools).

Windows native backend (stage 126)

On Windows, --air-app uses Win32 + SDL2 + Skia D3D12 direct-to-GPU. The bit width is decided by the AIR descriptor's <application><architecture> ("32"/"64", default 32), corresponding to vendor/*/windows-x86|windows-x64:

<!-- 32-bit (AIR default, also the default behavior when <architecture> is absent) -->
<application><architecture>32</architecture></application>
<!-- 64-bit -->
<application><architecture>64</architecture></application>
  • <renderMode>direct</renderMode> (or gpu) → ASC_RENDER_WINGPU=1 + ASC_RENDER_D3D=1, additionally linking vendor/d3d_glue.cc and d3d12/dxgi/d3dcompiler (a process-level ID3D12Device/command queue/GrDirectContext, window-level CreateSwapChainForHwnd double back buffer + fence frame sync + ResizeBuffers); cpu/auto keep CPU raster + SDL streaming texture blit.
  • The GPU seam is backend-neutral: the generated C and runtime only speak sk_gpu_*/sk_window_show_gpu/as_skia_gpu_*/ w->is_gpu; ASC_RENDER_WINGPU means "this window's compositing runs on the GPU", and the concrete backend is named by ASC_RENDER_METAL (macOS) / ASC_RENDER_D3D (Windows), with the only branch point in vendor/window_glue.cc (sk_attach_gpu).
  • All differences from macOS are selected at build time, not by runtime branching: on Windows we do not link metal_glue.mm/objc/Cocoa framework, do not add -lm/-lz (m.lib/z.lib do not exist on Windows), and set AS_HAVE_ICONV=0 (non-UTF charsets loudly throw). Archive names follow gn's Windows rules (<target>.lib, no lib prefix) ⇒ a target literally named libpng links as -llibpng; this conclusion comes from the real build.ninja read out of a macOS-side gn gen target_os="win".
  • Stage3D is unavailable on Windows and does not silently downgrade: when the descriptor/source uses Context3D, the build reports AirAppError (the AGAL→HLSL translator is not yet started, see TODO.md stage 126).
  • The dependency libraries are built from source by vendor/build-windows-deps.ps1 (Skia m124 skia_use_direct3d=true, SDL2, curl, zlib, nghttp2; both x86/x64 widths, LLVM clang-cl, bit width verified with dumpbin, a mismatch hard-fails). Full details, the list of assumptions not verified on real hardware, and the Windows first-run checklist are in win32.md.

Supported language subset

Category Supported
Types int, uint, Number, Boolean, String, void, Array, Vector.<T>, Function, RegExp, Class (class reference), Dictionary (object-reference-keyed associative table), * (untyped → dynamic any boxing), class names (object types), interface names
Literals integer, float, hexadecimal (0xFF), string (single/double quotes), true/false, null, Infinity/NaN, array literal [...], object literal { ... } (keys may be numeric: {0: "a"}, stage 106), E4X XML literal <a b="1">…</a> (nested/self-closing/attributes/comments/CDATA, stage 106; {expr} interpolation is loudly rejected), regex literal /pattern/flags, Vector literal new <T>[...]
Expressions arithmetic + - * / %, comparison == != < <= > >=, logical && || !, unary - + ! ~, bitwise & | ^ << >> >>>, increment/decrement ++ -- (prefix/postfix), ternary ?:, null coalescing ?? (lowest precedence, short-circuit, the left side is only hoisted into a boxed temporary when necessary, stage 106), comma operator (a, b) (lowest precedence, result is the right operand, stage 106), E4X descendant axis x..name / x..* (pre-order, excluding self, stage 106), E4X computed names x.ns::[expr] (child axis ⇒ XMLList) and x.@[expr] (attribute axis ⇒ String) (stage 108; the ns qualifier folds per "namespace transparency"), type checks is / casts as (supporting dotted fully-qualified names), coercion syntax Type(expr), typeof, delete, membership in, array indexing a[i], property access o.x, compound assignment += -= *= /= %= <<= >>= >>>= &= |= ^=, logical assignment ||= &&=
Statements variable declarations (including multiple var a:T, b:T, c:*;), expression statements, if/else, while, do-while, for, with (obj) stmt (object members as the innermost scope), for-in (array indices / dynamic object keys / Dictionary object-reference keys), for-each-in (including the bare-identifier iteration form with var omitted), switch/case/default, break, continue, labeled statements label: while(...){ break label; }, return, throw, try/catch/finally (multi-branch catch catch (e:A) … catch (e:B) … matched in source order, clearing as_exception on a hit, rethrowing if none match, stage 106), blocks; new C (omitted argument list, equivalent to new C()) and a[i] ||= v / a[i] &&= v (short-circuit assignment with an index target; the receiver/index must be side-effect-free); arguments inside functions (a formal-parameter array generated on demand)
Functions free functions with typed parameters and return types; omitted parameter types (defaults to * per spec, stage 106); optional and default parameters function f(a:int, b:int = 1); any-typed parameter function f(message:* = ""); rest parameters function f(...args:Array); Function type and function values (anonymous function expressions, functions as arguments/return values); closures (anonymous functions capturing outer local variables, captured variables heap-allocated to escape)
Classes fields + methods + parameterized constructors + new + this + inheritance extends + override (vtable dispatch) + super calls (including the implicit no-arg super() when there is no explicit super) + super.property property read·write (field/getter/setter) + access modifiers public/private/protected/internal + static fields/methods + const constants + declaring multiple fields on one line private var a:T = 1, b:T = 2; (each declarator gets an independent slot, sharing the statement's modifiers, stage 108) + get/set accessors + final classes/methods + dynamic classes (dynamic class, undeclared properties route to a runtime slot table) + static methods as Function values (ClassName.method or bare identifiers) + dynamic class instantiation new (expr as Class)() (no-arg factory via class reference) + class-body { ... } static initializer blocks and bare statements in the class body (stage 106; order per adl measurement: first static field initializers in declaration order, then class-body blocks in source order) + import inside the class body (tolerated and ignored) and surplus ; + get/set usable as ordinary identifiers (var set:int)
Interfaces interface declaration (including extends A, B multiple parent interfaces, with methods transitively merged along the parent chain + cycle detection, stage 106) + implements (including implements A, B, interface vtable dispatch) + is/as interface type checks (runtime as_iface_lookup, folded only when statically known to be true) + interface accessors (iface.getter/iface.setter = v/iface.getter() — the zero-argument "called as a method" form — all go through the interface vtable's getter/setter slots; an accessor with arguments always throws loudly; stage 110 completed assignment and method-call forms) + interface accessors can be satisfied by "built-in accessor-type properties" (stage 118: a class inheriting Sprite/InteractiveObject's x/y/visible/alpha/mouseEnabled… satisfies get x():Number; set x(v:Number):void; even without writing a getter, matching AIR — AIR declares these as accessor pairs; a user's public var x is still rejected, likewise matching AIR)
Packages/Modules multi-file compilation (multiple .as files merged into one compilation unit); package namespace isolation (C identifier prefix); import cross-file/cross-package short-name resolution; internal package-local visibility (rejected across packages); custom namespaces public namespace/use namespace/ns::member (transparent at AOT compile time, no runtime visibility semantics)
Root classes Object built-in root class: implicit base class of all classes, toString() returns the runtime class name; Error built-in error type: new Error(message, id), .message property; built-in error subclasses TypeError/RangeError/ArgumentError/SyntaxError/ReferenceError; built-in Date class (millisecond timestamp + calendar accessors); flash.events event system Event/EventDispatcher/MouseEvent/KeyboardEvent/FocusEvent/TimerEvent/ProgressEvent/ErrorEvent/IOErrorEvent/DataEvent (addEventListener/dispatchEvent capture→target→bubble three phases, preventDefault/stopPropagation/stopImmediatePropagation; Event completes the CANCEL/CLEAR/CLOSE/CONNECT/COPY/CUT/DEACTIVATE/EXIT_FRAME/FRAME_CONSTRUCTED/FULLSCREEN/ID3/INIT/MOUSE_LEAVE/OPEN/PASTE/RENDER/SCROLL/SELECT/SOUND_COMPLETE/TAB_*/UNLOAD constants, event subclasses (stage fifty-nine) TimerEvent (TIMER/TIMER_COMPLETE), ProgressEvent (PROGRESS + bytesLoaded/bytesTotal), ErrorEvent (ERROR + text), IOErrorEvent (IO_ERROR, inheriting text), DataEvent (DATA + data), VsyncStateChangeAvailabilityEvent (VSYNC_STATE_CHANGE_AVAILABILITY + read-only available (the AIR surface, measured to be constantly false) and read-only refreshRate (the enhancement surface: AIR has no refresh-rate API at all, see "Beyond AIR" and enhancements.md §4.8 E16))); flash.display display list DisplayObject/InteractiveObject/DisplayObjectContainer/Stage/Sprite/Shape/Graphics/Bitmap/BitmapData (layering/coordinates/addChild (triggering addedToStage)/removeChild/hit testing/recursive rendering; geometry and hit testing (stage 94-6): Shape/Sprite/MovieClip all have graphics (Sprite/MovieClip as a lazy getter), width/height are derived accessors (the content bounding box through the object's own transform; stroke expansion counts, TextField being the exception — it stores real size and the getter reports "size × scaleX"), assigning to width/height is scaling (scaleX = scaleX * value / cur, writing 0 for empty content); hit testing is transform-aware (the parent-chain matrix is folded level by level down to the local bounding box, hitTestPoint takes stage coordinates); geometry/coordinate API family (stage 94-9): getRect/getBounds (content bounding box, the former excluding and the latter including strokes; targetCoordinateSpace == null ⇒ its own local space, == self ⇒ short-circuits to the exact local box), localToGlobal/globalToLocal (walking the full ancestor matrix chain, returning a new Point, a null point throwing TypeError #2007), hitTestObject (intersects two stage-space bounding boxes, strokes included, empty objects never intersect) and hitTestPoint both on DisplayObject (so Shape can use them too); MouseEvent.localX/localY and the text insertion-point index use the same folding, as_render_object dispatches by is subtype chain, user Sprite subclasses may act as containers, cacheAsBitmap subtree bitmap caching (toggle invalidates and re-bakes, the bake being pixel-identical to direct recursive rendering; incremental-redraw auto cacheAsBitmap: a static subtree's fingerprint drives automatic baking); Stage stage properties stageWidth/stageHeight/fullScreenWidth/fullScreenHeight/displayState/quality/color/align/scaleMode/frameRate/vsyncEnabled and boolean switches, plus read/write focus (InteractiveObject; assignment dispatches focusOut→focusIn per adl semantics and is the enabling condition for copy) (frameRate is, per AIR, a single application-wide value: writing it in any window/any Stage takes effect globally, and the frame loop dispatches only one application frame per tick, not stacking with the number of windows — stage 89-73; vsyncEnabled is likewise a single application-level value, measured to default to true, and when false removes the "cap when an explicit frameRate exceeds the panel refresh rate" — stage 129), constant classes StageAlign/StageScaleMode/StageQuality/StageDisplayState); flash.display.Screen (stage 89-71): Screen.mainScreen/Screen.screens/Screen.getScreensForRectangle(rect) + instance bounds/visibleBounds/colorDepth (static properties + a one-argument static method, no getScreens(); bounds is the full display mode and visibleBounds the usable area, two different quantities); every access returns a fresh wrapper object (Screen.screens[0] !== Screen.mainScreen, measured on adl), only the cached Rectangle is a live object; new Screen() throws Error #2012; the flash.display.NativeWindow family (stage 89-71, multi-window): NativeWindow/NativeWindowInitOptions + constant classes NativeWindowSystemChrome/NativeWindowType/NativeWindowRenderMode/NativeWindowDisplayState/NativeWindowResize, new NativeWindow(opts) immediately opens its own OS window (with visible=false on return, default frame 400×232 and client area 400×200, frame size taken from NSWindow), each window has its own Stage (scaleMode="showAll"/align=""; frameRate is application-level and a new window inherits the current value rather than carrying its own 24fps — stage 89-73), bounds/x/y/width/height are window-geometry proxies, close() goes through frame-boundary deferred finalization (closed is still false on the calling frame) and dispatches Event.CLOSE, plus activate/minimize/maximize/restore/orderToFront/orderToBack and 4 statics isSupported/supportsTransparency/supportsMenu/supportsNotification; inherits EventDispatcher per AIR (stage 89-72) — so a window can addEventListener, and both Event.CLOSE/ENTER_FRAME reach it (this is both the API shape and a struct layout contract: listeners/parent must precede _win, otherwise dispatchEvent reads an out-of-bounds pointer and crashes); flash.text text TextField/TextFormat (SkParagraph full layout: HarfBuzz shaping + UAX#14 breaking + real line height, multiline/wordWrap/scrollV/maxScrollV/numLines/textWidth/textHeight + background/backgroundColor background fill + border/borderColor border (default false/0x000000, four 1px solid lines on the field box's outer pixels x∈{0,width}/y∈{0,height}, drawn above the background, scaling with the field, not counted into textWidth/textHeight; all three color properties are 24-bit RGB and discard the alpha byte on write — stage 94-8); TextFormat.align horizontal alignment left/center/right/justify is implemented — with a layout width it delegates per-line alignment to SkParagraph, and with wordWrap=false (no layout width) it does a whole-block translation at the draw origin per AIR's 2px text padding, centering/right-aligning without wrapping just like AIR; this is exactly the behavior Starling's TrueTypeCompositor relies on for centered native text); flash.utils.Dictionary (new Dictionary(weakKeys): an associative table keyed by object reference, supporting in/delete/for-in, the weak-reference parameter accepted but not modeled, keys strongly held for the program lifetime); ByteArray's multibyte / boolean / AMF surface (stage 94-4): readMultiByte(length, charSet)/writeMultiByte(value, charSet)/readBoolean/writeBoolean/readObject()/writeObject(object) + objectEncoding (default ObjectEncoding.AMF3) + integer-indexed read/write ba[i] (reading a gap yields 0; writing goes through ToUint32's low byte, out-of-bounds auto-extends with zero fill, and does not affect position); charSet goes through the system iconv (native builds link -liconv), 'unicode'/'utf-16' are always UTF-16LE without BOM and the endian property has no effect, ''/unknown charsets fall back to the OS legacy encoding (MacRoman on Apple, CP1252 elsewhere), a character the target charset cannot express is hand-written '?' (not relying on //TRANSLIT), a truncated multibyte sequence lossily decodes to the empty string, an out-of-bounds read throws EOFError #2030; writeBoolean writes 1 byte, readBoolean treats nonzero as true; an AMF3 object-graph codec (write + read, byte-for-byte aligned with adl 51.4.1) covers null/undefined/bool/int (the compact U29 form)/double/String (U29S length by UTF-8 bytes)/Date/ByteArray/Array (dense section + associative section)/Vector.<T> (0x0d0x10)/Dictionary/typed object (trait table + reference table + own fields before superclass fields); flash.net.registerClassAlias/getClassByAlias are wired, aliases working along the superclass chain (measured: an alias registered under a base-class name is written into subclass instances); readObject/writeObject share the same codec between ByteArray and URLStream, and AMF0 is not yet implemented (objectEncoding = AMF0 throws loudly rather than silently writing AMF3); flash.utils.Proxy (stage 94-1): dynamic class X extends Proxy uses the flash_proxy namespace's ten interceptors to take over dynamic property access (getProperty/setProperty/deleteProperty/hasProperty/callProperty/getDescendants/nextNameIndex/nextName/nextValue/isAttribute), real slots take precedence, and an uncovered operation throws #2088…#2107 per adl measurement; flash.utils.Timer (stage sixty): a repeating timer, inheriting EventDispatcher, constructor Timer(delay, repeatCount=0), delay setter validates negative/non-finite values throwing RangeError; repeatCount setter does not validate (int truncation, negatives preserved, NaN→0), currentCount/running read-only, start/stop/reset; dispatches TimerEvent.TIMER per interval, TimerEvent.TIMER_COMPLETE when repeatCount>0 is exhausted, repeatCount=0 repeats indefinitely; driven by the frame loop as_timer_tick (off-screen uses tickTimers() to pump manually, WASI degrades to second granularity); flash.geom 2D geometry (stage fifty-eight) Point/Rectangle/Matrix/ColorTransform/Transform (Point static distance/interpolate/polar and instance add/subtract/offset/normalize/setTo/copyFrom/clone/equals/toString; Rectangle read-only top/bottom/left/right and intersection/union/contains/containsPoint/containsRect/intersects/equals/inflate/offset/clone/setEmpty/isEmpty/toString; Matrix identity/translate/scale/rotate/concat/invert/transformPoint/deltaTransformPoint/createBox/createGradientBox; ColorTransform 8 channels + concat; Transform holds identity matrix/colorTransform, now wired to DisplayObject.transform (Matrix applied to the Skia canvas transform)); Vector3D/Matrix3D (stage seventy-nine, flash.geom 3D geometry, pure logic, no GPU): Vector3D x/y/z/w four components (geometric ops normalize/dotProduct/crossProduct/distance/angleBetween/length/lengthSquared use xyz only, w the homogeneous coordinate; add/subtract/scaleBy/negate four-component; equals(allFour), toString + static constants X_AXIS/Y_AXIS/Z_AXIS); Matrix3D 4×4 column-major (rawData a column-major 16-element Vector.<Number>, identity/append/prepend/invert (in-place, returning Boolean invertibility)/transpose/transformVector/transformVectors/deltaTransformVector/pointAt/interpolate/recompose/decompose/copyFrom/clone + translation/scale/rotation constructors + static identity/interpolate, decompose/recompose round-trip consistent); AGALTranslator (stage eighty, AGAL bytecode kernel, flash.display3D pure-static bridge, not an AS3 runtime API): translate(bytes:ByteArray, target:String):String translates AGAL1/2/3 bytecode into readable MSL ("msl") or GLSL ES ("glsl") source — parses the 7-byte header + variable-length instruction tokens (dest [num:16][mask:8][type:8], source [num:16][offset:8][swizzle:8][type:8][reltype:8][relsel:16], sampler [num:16][lod:8][0:8][samplerbits:32]), 28 base instructions with swizzle/write-mask expansion + AGAL2 control flow (ife/ine/ifg/ifl/els/eif) + derivatives (ddx/ddy) + tex sampling; register type is shader-relative encoding (vc=fc=1, vt=ft=2, op=oc=3, fs=vs=5) dispatched by vertex/fragment; basic validation (magic/version/opcode/truncation/instruction count) throws Error); Stage3D/Context3D (stage 8183, flash.display3D CPU state machine + optional Metal GPU backend): Stage.stage3Ds returns a Vector.<Stage3D> (single slot), Stage3D.requestContext3D(mode) lazily creates a Context3D and synchronously dispatches Event.CONTEXT3D_CREATE, context3D/x/y/visible read/write; Context3D state machine configureBackBuffer/setBlendFactors/setDepthTest/setCulling/setStencilActions/setScissorRectangle/setStencilReferenceValue/setProgram/setVertexBufferAt/setTextureAt/setProgramConstantsFromMatrix (transposed=false uploads the column-major matrix transposed to row-major, true copies verbatim)/setProgramConstantsFromVector (AGAL3, uploading Vector.<Number> to vc/fc; numRegisters defaulting to -1 means deriving the register count from the vector length — Starling's BlurFilter/ColorMatrixFilter pass only a vector, see stage 89-21)/createVertexBuffer/createIndexBuffer/createProgram/createTexture/createCubeTexture/createRectangleTexture/setCubeTextureAt/setRectangleTextureAt/drawTriangles/drawTrianglesInstanced (AGAL3 instancing)/clear/present/drawToBitmapData/setRenderToTexture/setRenderToBackBuffer + read-only driverInfo/profile/maxBackBufferWidth/maxBackBufferHeight; resource classes VertexBuffer3D/IndexBuffer3D (uploadFromVector/uploadFromByteArray record a CPU copy, the latter reading little-endian float32/uint16 widened into the vector)/Program3D (upload records bytecode)/Texture/TextureBase (uploadFromBitmapData records the source BitmapData and synchronously uploads the GPU texture, see below; for miplevel != 0 it uploads that level by the region rule measured on adl — taking the source bitmap's top-left lw×lh (lw = max(1, width>>level), read by the source's row stride), computing the layer count from max(width,height) and rejecting out-of-range levels, while setting the texture's "has chain" flag; stage 128)/CubeTexture (six-face BitmapData descriptor)/RectangleTexture (an NPOT single-face descriptor; createRectangleTexture(..., optimizeForRenderToTexture=true) really allocates a GPU texture usable as a render target — Starling's Texture.empty(...) non-compressed/non-mip textures all take this path, and the filter off-screen pass depends on it, see stage 89-21); Texture.uploadCompressedTextureFromByteArray (stage 89-21): format 3/5 in the ATF container (raw DXT1/DXT5) is CPU-decoded to straight-through alpha ARGB and goes through the normal texture upload path (no premultiply, matching adl handing raw DXT5 to the GPU), while other format/cubemap cases throw Error #3680 loudly (no silent blank texture); 16 constant classes Context3DBlendFactor/Context3DBufferUsage/Context3DClearMask/Context3DCompareMode/Context3DCubeMapFace (int)/Context3DFillMode/Context3DMipFilter/Context3DProfile/Context3DProgramType/Context3DRenderMode/Context3DStencilAction/Context3DTextureFilter/Context3DTextureFormat/Context3DTriangleFace/Context3DVertexBufferFormat/Context3DWrapMode; **GPU backend (stage 8283)**: when the build manifest defines ASC_RENDER_STAGE3D=1 + links vendor/stage3d_glue.mm (raw Metal: MTLBuffer vertex/index/constant, MTLTexture 2D, MSL compilation, off-screen render-to-texture), drawTriangles/drawTrianglesInstanced are the sole synchronization point, deferred-uploading all bound resources and drawIndexedPrimitives-ing to screen (instancing via instanceCount); a frame's draws batch into a single MTLCommandBuffer, committing + waiting only once at the frame boundary (stage 104: previously every drawTriangles did commit + waitUntilCompleted, measured at cpu=0.01ms/gpu=0.04ms while wait≈0.5ms ⇒ that 0.5ms was pure round-trip latency, and with Starling's fps monitor on, just 1.6 extra draws per frame directly ate 0.81.0ms/frame; after batching, draws/batch 79, wait 0.93ms per frame, Benchmark peak object count +39%, and the stats-on gap narrowed from −14% to −6%); blend state (stage 89-22): Metal bakes blend state into MTLRenderPipelineState (no per-draw setter), so the glue retains the compiled vertex/fragment functions and caches pipelines by blend-factor pair, selecting by the current setBlendFactors when encoding each draw (lazily building on miss, LRU cap 12); depth/stencil state is likewise cached in a keyed LRU (S3D_MAX_DSS slots + s3d_select_dss, so away3d alternating depth state per draw no longer creates a new MTLDepthStencilState each draw — measured dss=2 over 1680 draws, stage 128) — so changing blend mode mid-way on the same Program3D now truly takes effect (Starling's Blend Modes scene previously changed the label but not the image), and drawToBitmapData reads back the current render target's pixels (render override preferred, ARGB↔BGRA conversion), otherwise pure-C mode is only a state machine (as_s3d_* no-op wrappers keep it link-clean); web target (stage 89-30): the same generated C in the browser instead links vendor/stage3d_webgl.cc (WebGL2/GLES3) + build-time ASC_S3D_GLSL=1, with shaders emitted as GLSL ES by the same AGAL translator (ASC_AGAL_TARGET selects MSL/GLSL at build time) — the s3d_* signatures are identical on both ends, so the Context3D state machine and the as_s3d_* wrappers are unchanged; the GL side's Y-axis flip (gl_Position.y = -gl_Position.y in the vertex stage, so texture v=0 and readback row order both match AS3), BGRA↔RGBA swap, per-register uniform vec4 vcN/fcN, the DEPTH24_STENCIL8 off-screen FBO and separate front/back stencil APIs, caching sampler state per texture object, and sharing a single WebGL2 context with Ganesh (every s3d_* entry that touches GL calls sk_gr_reset_context()) are all handled inside vendor/stage3d_webgl.cc, and examples/air-starling-demo's 12 scenes each render in the browser and match the AIR adl reference (120 fps / 0 drops; see docs/en/html5-web.md §3.3); presentation currently goes through CPU readback (as_s3d_readback_render + as_skia_canvas_draw_bgra, measured at 98% of single-frame CPU cost), with direct-to-GPU listed as later optimization; texture upload timing (stage 89-18): in AIR uploadFromBitmapData uploads synchronously, so it is legal for the caller to BitmapData.dispose() immediately after — so the AOT likewise builds the MTLTexture immediately in uploadFromBitmapData (Texture remembers the Context3D's glue handle, creating it via s3d_texture_from_pixels but not binding a sampler slot, with Context3D_submit then calling s3d_bind_texture by slot), rather than deferring the upload to the next drawTriangles (deferring would read empty/stale data from a pixels already freed after dispose(): Starling's glyph rasterization is literally "draw → fromBitmapData → dispose", which once left the text texture never uploaded and the sampler slot retaining the previous atlas page's contents, rendering as colorful garbage); flash.filters filters (stage sixty-one) BitmapFilter (abstract base class, clone())/BlurFilter (blurX/blurY/quality + clone)/DropShadowFilter (distance/angle/color/alpha/blurX/blurY/strength/quality/inner/knockout/hideObject + clone)/GlowFilter (color/alpha/blurX/blurY/strength/quality/inner/knockout + clone) + constant class BitmapFilterQuality (LOW/MEDIUM/HIGH); DisplayObject.filters read/write (Array access); BitmapData.applyFilter (BlurFilter implemented via separable box blur, DropShadowFilter/GlowFilter rasterization deferred throwing errors); flash.display completion (stage sixty-two) MovieClip (currentFrame/totalFrames + play/stop/gotoAndPlay/gotoAndStop, frame-loop driven, currentFrame wraps to 1 when out of bounds, totalFrames writable to simulate multi-frame timelines)/SimpleButton (upState/overState/downState/hitTestState four state references)/Loader (content/contentLoaderInfo + load(url) async dispatch of INIT (sync)/COMPLETE (next frame tick); an http(s):// URL is explicitly recognized and goes through the same transport seam as URLLoader — native + ASC_HAVE_CURL runs as_http_perform on a worker / web + ASC_HAVE_FETCH starts a fetch and decodes in the frame-boundary pump (stage 89-56 wired up the web side; before that this branch had only a curl implementation on web, so every remote Loader.load reported "this build has no HTTP backend" without sending a single request), with no backend dispatching a distinguishable honest ioError; cross-origin images in the browser are subject to the same-origin policy: the image can display but its pixels cannot be read, and Skia presentation needs pixels, so the CDN must return Access-Control-Allow-Origin, otherwise we truthfully report a CORS ioError)/LoaderInfo (bytesLoaded/bytesTotal/url + COMPLETE/INIT/OPEN/UNLOAD/PROGRESS/IO_ERROR constants); flash.net/flash.ui (stage sixty-three, the API surface completed at stage 89-48; http(s):// networking opt-in at 89-49) URLRequest (the full AIR property surface: url (default null)/method (default "GET")/data (any, default null)/contentType (default null, measured on adl; the documented application/x-www-form-urlencoded is the send default, not the property value — only a body-carrying request that did not declare one sends that MIME string, and a bodyless request sends none, stage 89-69)/requestHeaders (default an empty Array, directly push-able)/authenticate/cacheResponse/followRedirects/manageCookies/useCache (all default true)/idleTimeout (default 0)/userAgent (an OS-derived Flash/AIR-form UA string)/digest; the latter 6 are, per the official "initialized from the URLRequestDefaults.X property", read from URLRequestDefaults at construction + instance method useRedirectedURL(sourceRequest, wholeURL=false, pattern=null, replace=null) (first a domain/whole-segment replacement by wholeURL, then pattern→replace on the result, supporting both String and RegExp pattern))/URLRequestMethod (GET/POST/PUT/DELETE/HEAD/OPTIONS six constants)/URLRequestHeader (name/value, constructor defaults ""/"")/URLRequestDefaults (7 static properties authenticate/cacheResponse/followRedirects/idleTimeout/manageCookies/useCache/userAgent, read/write matching AIR defaults; setLoginCredentialsForHost deferred — needs an authenticating HTTP stack)/URLLoader (data/dataFormat/bytesLoaded/bytesTotal + load(request)/close(), inheriting EventDispatcher, constructor URLLoader(request=null) starting the load when passed; asynchronous (next frame tick); reads local files for file:///relative paths, and http(s):// really networks with native + ASC_HAVE_CURL (build manifest link-libs: ["curl"]) (GET/POST/status codes/HTTPS), dispatching a distinguishable honest ioError without a backend; event order open (only when the request reaches transport) → progress → httpStatus (carrying only status; 0 for local/backendless loads) → complete (on failure: httpStatus(0) → empty data → ioError); data is published per dataFormat as a GC-tracked string (text)/ByteArray (binary)/URLVariables (variables); bytesLoaded/bytesTotal are constantly 0 during loading and set to the byte count on completion (AIR behavior); close() really aborts an in-flight load (no further terminal events afterward), throwing an invalid stream error with no stream)/URLVariables (dynamic class, undeclared string-keyed properties written into a runtime slot table, toString() serializing to a query string, decode(source) decoding a query string into the instance (values percent-decoded, keys not — matching AIR))/Keyboard (static key-code constant table AZ/NUMBER_0~NUMBER_9/SPACE/ENTER/TAB/ESCAPE/BACKSPACE/DELETE/SHIFT/CONTROL/LEFT/RIGHT/UP/DOWN + read-only isAccessible)/Mouse (static hide/show + writable cursor/read-only supportsCursor/supportsNativeCursor); flash.filesystem (stage sixty-four) File (nativePath + read-only properties url (file:// form)/exists/isDirectory (getter, via stat()) + resolvePath/createDirectory/deleteFile/deleteDirectory + static read-only applicationStorageDirectory/applicationDirectory/desktopDirectory/documentsDirectory/userDirectory (the latter resolved at runtime via getenv("HOME")), POSIX stat/mkdir/remove)/FileStream (open/openAsync (async dispatch of ProgressEvent.PROGRESS + COMPLETE)/close/readUTFBytes/writeUTFBytes + read-only position/bytesAvailable, FILE* handle as opaque void* not GC-tracked)/FileMode (READ/WRITE/APPEND/UPDATE constants); flash.net.SharedObject (stage 89-40): SharedObject.getLocal(name, localPath?) returns a local shared object (inheriting EventDispatcher, fqn = flash.net::SharedObject, not dynamic, throwing ReferenceError #1056 on assignment to an undeclared property just like AIR), data a read-only-getter Object (a key-value table, supporting data[k] read/write/delete/for-in), size returning the byte count of the representation to be persisted, flush() returning SharedObjectFlushStatus.FLUSHED ("flushed")/throwing loudly on failure, clear() emptying the data and deleting the on-disk file, close() having no effect on a local object (an empty implementation), setDirty() an empty implementation, setProperty writing data; getLocal with the same name returns the same instance (a process-wide instance table, static fields as permanent GC roots); defaultObjectEncoding/preventBackup/client/objectEncoding/fps accessors and ObjectEncoding (AMF0=0/AMF3=3/DEFAULT=3), SharedObjectFlushStatus (FLUSHED/PENDING) constant classes all modeled on measured AIR values; persistence to [<localPath>/]<name>.json under applicationStorageDirectory, automatically flushed at application exit (an atexit hook, matching AIR's "write local shared objects when the application closes" behavior — even if flush() was never called); getRemote/connect/send require running on a Flash Media Server and this runtime throws loudly (rather than silently pretending success)
Builtins trace(...); Array methods push/pop/shift/unshift/splice/slice/indexOf/join/concat, .length; String methods charAt/charCodeAt/indexOf/lastIndexOf/substring/substr/slice/split/match/search/replace/toUpperCase/toLowerCase/concat/localeCompare/valueOf/toLocaleLowerCase/toLocaleUpperCase/startsWith/endsWith, static String.fromCharCode, .length; Number/int/uint methods toFixed/toExponential/toPrecision/toString(radix)/valueOf, Number static constants MAX_VALUE/MIN_VALUE/NaN/POSITIVE_INFINITY/NEGATIVE_INFINITY, int/uint static constants MAX_VALUE/MIN_VALUE; Math constants PI/E/LN10/LN2/LOG10E/LOG2E/SQRT1_2/SQRT2 and methods abs/floor/ceil/round/sqrt/pow/min/max/random/sin/cos/tan/asin/acos/atan/atan2/exp/log; global functions parseInt/parseFloat/isNaN/isFinite; flash.utils.getTimer() (milliseconds since process startup, not a Unix timestamp, used for 60Hz frame-loop timing); flash.utils.setTimeout(closure, delay) / flash.utils.clearTimeout(id) (scheduling/canceling one-shot function callbacks, triggered by the frame loop after delay ms, returning a uint timer id; callbacks bound via function-value closure); flash.utils.setInterval(closure, delay, ...args):uint / flash.utils.clearInterval(id) (stage 94-3): shares the same table and the same id counter as setTimeout/clearTimeout (measured: consecutive calls give ids 1,2,3…), so the two cancel each other (clearInterval can cancel a timeout's id, clearTimeout can cancel an interval's id), and an unknown/0 id is a silent no-op; a repeating timer schedules the next one after the callback ends, fires at most once per frame, and stops when clearInterval is called inside its own callback; a negative/NaN delay throws RangeError #2066; a null closure still consumes an id and never fires; flash.utils.getQualifiedClassName(value:*):String (stage eighty-six, reflection: returns the object's fully-qualified class name package::Class, primitives returning "null"/"Number"/"Boolean"/"String"/"void"/"Array"/"Function") and flash.utils.getQualifiedSuperclassName(value:*):String (stage 94-3: the qualified name of the value's class's superclass, walking multi-level chains up, returning null when there is no superclass) and flash.utils.getDefinitionByName(name:String):Object (returns a class reference by name, closing a round-trip with the former, supporting both ::/. separators; from stage 127 built-in classes are also in the registry (getDefinitionByName("flash.display.BitmapData") works), and a miss throws AIR's Error #1065: Variable <last segment> is not defined. (errorID = 1065); describeType(value):XML returns a <type name="package::Class"/> description tree, implemented in stage ninety-three); flash.system.System memory statistics (totalMemory(uint)/totalMemoryNumber(Number)/freeMemory(Number)/privateMemory(Number) four purely static read-only properties: totalMemory is the runtime self-managed heap used bytes (returns 0 beyond 4 GiB), totalMemoryNumber same value unclamped, freeMemory is the arena allocated-but-unused gap, privateMemory is the real process resident memory (macOS mach_task_basic_info/Linux getrusage×1024/Windows GetProcessMemoryInfo/WASI degrades to totalMemory); flash.system.Capabilities (stage sixty-five): a final static read-only class (same pattern as System, no instantiable class) — version (a fixed AIR-compatible "<platform-prefix> 50,0,0,0", aligned with Adobe AIR's final major, the AS-AOT marker carried by manufacturer), os (Mac OS/Windows/WASI/Linux via conditional compile), cpuArchitecture (ARM/x86), cpuAddressSize (32/64), supports64BitProcesses/supports32BitProcesses (derived from address size), playerType ("Desktop"), manufacturer ("AS-AOT"), isDebugger (false), touchscreenType ("none"), language (locale-derived ISO 639-1), screenResolutionX/screenResolutionY (SDL2 primary-display size, 0 in headless builds), screenDPI (72.0 fallback, no per-display DPI query), screenColor ("color"), pixelAspectRatio (1.0), hasAudio (true); type conversion String(x)/Number(x)/Boolean(x)/int(x)/uint(x); built-in constructor calls Array(...)/Object(...)/Vector.<T>(...) (also allowed without new, but Vector.<T>(arrayLike) is a "conversion", not a "construction" — semantically different from new Vector.<T>(length), see the type-mapping table below); Object(x) with an argument returns identity, boxing primitives as any; URI encoding/decoding encodeURI/decodeURI/encodeURIComponent/decodeURIComponent/escape/unescape; Boolean methods toString/valueOf; undefined global constant; object literals {} (string-keyed associative arrays); top-level JSON class stringify/parse (recursive serialization/parsing of objects, arrays, and primitives); exceptions throw/try/catch/finally (based on setjmp/longjmp); Date class (constructor overloads new Date()/new Date(ms)/new Date(year,month,day,...)/new Date(str), static Date.parse(str), accessors getTime/getFullYear/getMonth/getDate/getDay/getHours/getMinutes/getSeconds, formatting toDateString()/toUTCString()); RegExp class (regex literals /pattern/flags and new RegExp(pattern, flags): test/exec/source/global/ignoreCase/multiline/dotall/extended/lastIndex, supporting the five flags i/m/s/g/x; an embedded self-built ES3 backtracking regex VM: capturing/non-capturing groups, backreferences, lookahead, lazy/greedy quantifiers, character classes and \d\w\s escapes; String.match/search/replace regex variants: match returns the capture array or null, search returns the first match position, replace supports $1~$9/$&/$$ substitutions and function replacement repl:Function); Vector.<T> type-safe arrays push/pop/join/indexOf/slice/concat/splice/forEach/map/filter/sort/reverse, read/write .length, parameterized constructor new Vector.<T>(length, fixed), vector literal new <T>[...], indexed read/write with bounds checks; Array.sortOn(field, options) (sorting by object field, supporting Array.NUMERIC(16)/Array.DESCENDING(2) and NUMERIC | DESCENDING combinations), Array.concat accepting dynamic elements; Function.apply(thisArg, argsArray) (calling a function value with arguments taken from an array); dynamic method calls (when a receiver of type Object or any misses a static signature, dispatched by name through the method reflection table as_dyn_call to class methods)
Semantics Every subexpression is evaluated only once (stage 89-38): AS3's evaluation rule is "each operand in an operation is evaluated once, left to right", but several shapes of generated C inline the same operand in multiple places (member writes include a write barrier, property-getter reads go through the vtable, as tests then takes the value, interface == compares two fields, a Function value call reads the closure and its env, regex arguments read compiled/global, Boolean(str) reads the string twice) — so any operand that may have side effects (where isPureExpr is false) is first stored in a temporary (hoistImpure), so box.get().label = "Z" runs the getter once (three times before the fix), and h.getFn()() and s.replace(h.mkRe(), …) each run once (twice before the fix); module-level var initialization (the other path of emitTopLevel), a for init, and a throw value got the same sequenceValueExpr pass. Truthiness semantics (stage 89-38, measured against AIR 51.4.1): Boolean(x)/if (x) are always true for a non-null reference (object/array/Vector/Dictionary/class instance/interface value/function) (previously judged by ToNumber(x) != 0, which was false for any object), and always false for NaN (C's if (d) treats NaN as true, so a new as_num_truthy(x) = x != 0 && !isnan(x) was added, and both static Number conditions and the any boxing path use it); / is always Number (AS3 semantics); %'s zero divisor is defined per AS3 semantics (5 % 0 yields NaN, var r:int = 5 % 0 yields 0, INT_MIN % -1 yields 0), guarded by value via as_int_rem/as_uint_rem (C's integer % is UB on a zero divisor / INT_MIN % -1, and traps per spec under wasm); + auto-concatenates and boxes when encountering strings, and when a dynamic (*) operand is involved the runtime value decides (stage 89-34): emitBinary calls the as_add_v runtime helper (ES3 ToPrimitive — a String at runtime, or an object that stringifies, concatenates; otherwise the operands add), boxing the result as any. Measured: var a:Array=["x","y"]; a[0]+a[1] yields "xy" (was 0), var d:*="x"; d + 1 yields "x1" (was 1), null + 1 yields 1 (was a C compile error, (NULL + 1)). Known simplification: object/array boxes still render through as_v_str_val on the concatenation side, so [Array] + 1 gives [Array]1, not AS3's 1,21; trace/String(Number) output the IEEE-754 double's shortest 17-digit representation (trace(1/3) → 0.3333333333333333); Date.getTime() returns the real millisecond timestamp (gettimeofday); is/as perform runtime type checks via the vtable super chain; array elements are dynamic types (as_value boxing), heterogeneous elements handled automatically; exceptions jump via setjmp/longjmp to the nearest active catch, finally always executes (also available on the wasm target: stage 89-35 connected the EH link — -lsetjmp + the standard exception-handling proposal's try_table, and 9 examples containing try/catch produce byte-identical output across native/wasm); bitwise operations convert operands to 32-bit integers per AS3 semantics (>>> is unsigned right shift); dynamic index/property access on Object/any types goes through the reflection table (field offset + method table) onto real class instances, falling back to record slots on miss (obj[key]/obj.prop/obj[key] = v/obj.prop = v); conditional contexts (if/while/?:/&&/||/!) determine any values per AS3 truthiness (null/undefined/empty string are falsy, non-zero numbers and non-empty objects are truthy); a static String uses the same rule (an empty string is falsy, via as_str_truthy evaluated once, stage 125); the top-level script scope is the whole top-level statement tree (stage 89-34): a var/const written inside a block / if / for init / switch case / try shares the same C file-scope global as a top-level declaration (for (var i… emits for (g_i = 0; …), and trace(i) after the loop reads that same slot), and closures read/write that global directly instead of a snapshot (three closures over one loop variable all see the final value); the loop variable of a top-level for-in/for-each is likewise hoisted to a script-scope global (stage 89-37): its C type is not in the source (it depends on the iterable — int index for Array, char* key for a dynamic object, a boxed value for Dictionary/dynamic objects, the element type for Vector.<T>, with source annotations taking precedence), so collectScriptDecls and emitModuleVars derive it with the same loopVarType rule, and thus trace(k) after the loop reads the final key (matching AIR; measured on AIR the variable indeed survives). Loop variables inside a function body still stay block-local per this subset's function-level hoisting convention

Type → C mapping

AS3 C
int int
uint unsigned int
Number double
int64 int64_t (opt-in enhancement: the type name does not exist in AIR, taking effect only when written; literal 123L, conversion int64(x))
uint64 uint64_t (likewise; literal 123UL/123LU, conversion uint64(x))
Boolean bool
String char* (concatenation/boxing via as_str_* runtime helpers)
Array as_array* (dynamic growth, heterogeneous elements boxed as as_value; element type is dynamic *)
Vector.<T> as_vector_<T>* (monomorphized by element type T: contiguous element array T* data + length/capacity; an out-of-bounds index throws RangeError #1125; compile-time element type enforcement; push/pop/join/indexOf/slice/concat/splice/forEach/map/filter/sort/reverse, read/write .length, parameterized constructor new Vector.<T>(length, fixed), vector literal new <T>[...]). T may be * (stage 98-1: elements are as_value-boxed) and Class/Dictionary (stage 109: Class was already as_class* and Dictionary already had a reflection name, so adding the monomorphization decision ⇒ the wall at away3d's 7 Vector.<Class> call sites is cleared, with element slots as GCT_PTR_ARRAY + write barrier); dynamic access on a */Object receiver (.length read/write, integer-indexed read/write, the 16 methods) is available since stage 98-2 (out-of-bounds/negative index #1125), forwarding to the same monomorphized helpers as the static path. The two call forms differ semantically (stage 109, item-by-item against adl 51.4.1): Vector.<T>(arrayLike) is a conversion (element-by-element converting copy, length read dynamically per the array-like protocol, a scalar/null throwing TypeError #1034, zero arguments throwing ArgumentError #1112, a sealed instance per ReferenceError #1069); new Vector.<T>(length) is a construction (the argument must be uint, otherwise ArgumentError #2005; the fixed formal is accepted but not enforced in this subset)
Function as_fn (a pointer to the closure record { thunk, env }; each function used as a value generates a thunk that unboxes the boxed argument list, calls the typed implementation, and boxes the result back into as_value; closures capturing outer locals additionally generate an environment struct + heap-allocated constructor, with env pointing at that environment)
Object literal {} as_object* (string-keyed associative array, property values boxed as as_value)
RegExp RegExp* ({ vtable; as_regex* compiled; source; flags; lastIndex; global/ignoreCase/multiline/dotall/extended }; compiled is the compiled artifact of the embedded backtracking VM, compiled at construction time, compile errors throw SyntaxError)
Class Foo struct Foo + Foo*; first member is Foo_vtable* (vtable: super chain + method/getter/setter function pointers, a unified flat slot list keeping a subclass vtable layout-compatible with the parent prefix); fields laid out flat (parent-class fields first); methods compiled as Ret Foo_method(void* this, ...), invoked via obj->vtable->method(obj, ...); instance getters/setters are likewise virtual dispatch (obj->vtable->get_prop(obj) / obj->vtable->set_prop(obj, v)), while static accessors and super.property remain direct static calls; classes within namespaces use package-prefixed names (foo.bar.Baz → foo_bar_Baz)
Interface I struct I (reference pair: void* obj + I_vtable* vt); method dispatch via ref.vt->method(ref.obj, ...); each implementing class generates an interface vtable instance Class_I_vt
Error / exceptions struct Error (vtable + message); throw normalized to as_throw(Error*), exception state stored in the global as_exception, jump stack using setjmp/longjmp; TypeError/RangeError/ArgumentError are Error subclasses (same layout, independent vtables), catch (e:Type) uses as_is to match precisely along the super chain
static members class-level fields/methods: file-scope globals Class_field / Class_method(...) (no this receiver)
trace generates printf format strings by type; objects print as class names (as_obj_to_str reads the vtable's name)

Semantic authority sources

Before implementing new features, consult the authoritative specification to confirm real AS3 semantics, never reverse-engineering from memory or C behavior. The complete tiered list, red-line comparisons, and decision divergences are in docs/en/as3-semantics.md. Core sources:

  • ES4 draft specification (syntax/type system/coercion canon): http://archives.ecma-international.org/2006/misc/es4lang-Jan06.pdf
  • AVM2 Overview (object model trait/slot/dispatch semantics, borrowing semantics only, not generating ABC): http://hackipedia.org/raw/File%20formats/Containers/F4V,%20Flash%20Video/ActionScript%20Virtual%20Machine%202%20(AVM2)%20Overview%20by%20Adobe%20(2007-05).pdf
  • avmplus source (tie-breaker when the spec is ambiguous): https://github.com/adobe/avmplus
  • AS3 language reference (standard library surface): https://airsdk.dev/reference/actionscript/3.0/
  • ECMA-262 3rd edition (source of numeric conversions ToInt32/NaN/Infinity)

Beyond AIR (enhancements, non-alignment)

Our product is a readable C file handed to clang -O2, able to link Skia/libcurl/SQLite, benefit from LTO/PGO, interoperate with host C, and compile to native/WASI/web — so we can add enhancements where AIR does not define / does not support / has no counterpart (enhancements must be opt-in and never silent). The criterion: the same input that adl runs correctly but we cannot ⇒ a legacy defect; something adl already errors on or an API that does not exist ⇒ an enhancement.

Implemented (6 / 16):

  • Display refresh-rate query — VsyncStateChangeAvailabilityEvent gains a read-only refreshRate:Number (AIR has no refresh-rate API at all; the read-only available is measured to be constantly false)
  • Multi-format image decoding — WebP / BMP / ICO (--features formats; default reports #2124 just like AIR)
  • Camera RAW / DNG — Loader.load("*.dng") yields an image directly (--features raw, native)
  • SVG runtime decoding — Loader.load("*.svg") → Bitmap (--features svg, native)
  • 64-bit integers — int64 / uint64 (AIR has no such type name)
  • LTO / PGO build switches — manifest lto/pgo, CLI --lto/--pgo

The full 16-item list (the rest being Lottie, native shaders, FFI, server-side rendering…) and the five criteria are in docs/en/enhancements.md.

Examples

  • examples/hello.as — expressions, string concatenation, trace, if/else
  • examples/fib.as — functions, while, for, recursion boundary
  • examples/class.as — classes, fields, methods, new, this
  • examples/features.as — division/modulo, comparison, logic, increment, string equality
  • examples/syntax.as — uint, hexadecimal, do-while, switch, ternary, break/continue, Infinity/NaN
  • examples/ctor.as — parameterized constructors, new with arguments
  • examples/inherit.as — inheritance extends, field/method inheritance
  • examples/override.as — override method overriding, polymorphic dynamic dispatch
  • examples/super.as — constructor super(...), method super.method(...)
  • examples/visibility.as — access modifiers public/private/protected
  • examples/isas.as — is / as type checks and casts
  • examples/array.as — array literals/indexing/push/pop/splice/for-in/multidimensional arrays/heterogeneous elements
  • examples/object.as — object literals {} (associative arrays), property read/write, nested objects
  • examples/any-add.as — dynamic + (one side *): runtime-decided concatenation vs. numeric add, null operands, and += reusing the same path (stage 89-34)
  • examples/any-dot-write.as — dot writes through a dynamically-typed (*) receiver, incl. compound writes: reflectable fields land on the real field, an unknown property on a sealed instance neither crashes nor corrupts, record slots are added, and an array's element buffer is not clobbered (assertion regression for the stage 89-33 crash fix)
  • examples/stdlib.as — String methods, Math, global functions, type conversion, readable object trace
  • examples/oop2.as — const/static fields and methods/get/set accessors
  • examples/interface.as — interface/implements/interface is/as/interface method dispatch
  • examples/stage4.as — stage four synthesis: interfaces + static members + accessors + final + Object.toString + Number default NaN
  • examples/stage5.as — stage five synthesis: default parameters, rest parameters, Function values and anonymous functions
  • examples/stage6.as — stage six synthesis: package/import syntax compatibility layer (namespace flattening)
  • examples/stage7.as — stage seven synthesis: throw/try/catch/finally, built-in Error, exception rethrow and nesting
  • examples/stage8.as — stage eight synthesis: bitwise & | ^ ~ << >> >>> and compound assignment, labeled statements break label/continue label
  • examples/stage9.as — stage nine synthesis: Error subclasses TypeError/RangeError/ArgumentError precise catch and bubbling, Date class calendar accessors
  • examples/stage12/ — stage twelve synthesis (multi-file): package foo cross-file class definitions, import then instantiate and call, same-package internal visibility
  • examples/stage10.as — stage ten synthesis: Vector.<T> type-safe arrays (push/pop/indexed read/write/.length) and out-of-bounds RangeError
  • examples/stage11.as — stage eleven synthesis: closures (capturing outer locals, escaping, independent counting, parameterized closures)
  • examples/stage13.as — stage thirteen synthesis: null boxing semantics (string concatenation/comparison of object null), string arena allocation stress test
  • examples/stage14.as — stage fourteen synthesis: trace/String(Number) 17-digit double shortest representation, Date.getTime() millisecond clock
  • examples/stage15.as — stage fifteen synthesis: module-level const/var visible to free functions (file-level scope), untyped-variable truncation protection, module-level variable ordered initialization
  • examples/stage16.as — stage sixteen synthesis: String.replace (string variant, replaces first), Number.toFixed/toExponential/toPrecision (including exponent leading-zero stripping)
  • examples/stage17.as — stage seventeen synthesis: Vector.<T> join/indexOf/.length assignment (shrinking)/parameterized constructor new Vector.<int>(3, true)
  • examples/stage18.as — stage eighteen synthesis: primitive-type is/as (static scalar compile-time evaluation + any runtime tag determination)
  • examples/stage19.as — stage nineteen synthesis: Array/Vector join optimization (memcpy pointer advancement), intentionally simplified items verified (closure snapshots, array out-of-bounds null)
  • examples/stage21.as — stage twenty-one synthesis: Number/int/uint toString(radix) (base 2~36), valueOf, MAX_VALUE/MIN_VALUE/NaN/infinity static constants
  • examples/stage22.as — stage twenty-two synthesis: String concat/fromCharCode/localeCompare/valueOf/toLocaleLowerCase/toLocaleUpperCase/startsWith/endsWith
  • examples/stage23.as — stage twenty-three synthesis: Boolean.toString/valueOf, undefined constant, URI encoding/decoding encodeURI/decodeURI/encodeURIComponent/decodeURIComponent/escape/unescape
  • examples/regexp.as — stages twenty-four~twenty-seven synthesis: regex literals/new RegExp, test/exec/capture groups/lastIndex global state machine, String.match/search/replace regex variants ($1/$&/repl:Function), character classes/quantifiers/backreferences/lookahead, i/m/s/x flags, invalid regex throwing SyntaxError
  • examples/stage28.as — stage twenty-eight synthesis: Array()/Object()/Vector() constructor forms (new Array()/new Object() construction + function-style calls without new, Object(x) with-argument identity/boxing semantics)
  • examples/stage33.as — stage thirty-three synthesis: Event/EventDispatcher three-phase event dispatch (capture→target→bubble, stopPropagation/stopImmediatePropagation/clone)
  • examples/stage34.as — stage thirty-four synthesis: display list DisplayObject/DisplayObjectContainer/Stage/Sprite (addChild/removeChild/getChildAt/getChildByName/contains/setChildIndex/root/stage)
  • examples/stage35.as — stage thirty-five synthesis: interaction events and hit testing (inside-out dispatch, mouseChildren=false parent absorption, visible=false skipping, MouseEvent/KeyboardEvent/FocusEvent)
  • examples/stage36.as — stage thirty-six synthesis: minimal Skia closed loop (one Shape → Stage.render off-screen PNG, no-op without Skia)
  • examples/stage37.as — stage thirty-seven synthesis: Shape/Graphics (beginFill/beginGradientFill/drawRect/drawCircle), Bitmap/BitmapData (getPixel/setPixel), nested Sprite + rotation/alpha recursive rendering
  • examples/stage38.as — stage thirty-eight synthesis: TextField/TextFormat (SkParagraph text rendering, textWidth/textHeight)
  • examples/air-native/ — multi-file synthesis (boot.as + src/demo/*.as): Air-style document class Main (Sprite subclass) + implicit super()/addedToStage event-driven + Date/Array/ByteArray/JSON four demos + stage fifty-eight~sixty-four test cases (Geometry/Events/Timer/FilterDisplay/NetUi/File six *Demos.run() assertions + FilterDisplayDemos.visualize() stage filter visualization) + TweenDemo (GreenSock TweenLite tween animation, driving Shape movement via ENTER_FRAME in window mode), linking Skia to output air-native.png
  • examples/air-starling-demo/ — end-to-end Starling 2.x demo (flash.display3D render pipeline, shaders, events, tweening), running in a window
  • examples/window.as — stage thirty-nine synthesis: Stage.showWindow windowing (Shape blue rectangle + TextField text → off-screen Skia → SDL2 upload + event loop), using examples/window.build.example.json to link Skia + arm64 SDL2
  • examples/window_click.as — stage forty: real mouse clicks in the window → AS3 event dispatch (mouseDown/mouseUp/click + bubbling + click color-change re-render), using examples/window_click.build.example.json
  • examples/textflow.as — stage thirty-eight: TextField layout assertions (numLines/maxScrollV/scrollV viewport math, wordWrap wrapping, appendText/textHeight), valid under pure C / Skia builds
  • examples/wheel.as — stage forty-five: mouse wheel semantics (1 delta = 1 line, scrollV -= delta, clamped [1,maxScrollV], no dispatch on miss), pure C regression
  • examples/frame.as — stage forty-six: ENTER_FRAME broadcast semantics (stage/child/grandchild depth-first dispatch), pure C regression
  • examples/stage41.as — stage forty-one synthesis: Stage stage property read-back (stageWidth/stageHeight/color/quality/align/scaleMode/displayState/frameRate/boolean switches) + four constant classes, off-screen (included in regression)
  • examples/stage67.as — stage sixty-seven: DisplayObject.cacheAsBitmap subtree bitmap caching (default false, get/set readback, inheritance across Shape/TextField/Stage subclasses, toggle-invalidation safety), off-screen (included in regression)
  • examples/cacheasbitmap.as — cacheAsBitmap render verification (offscreen + manifest: a container subtree (rect + circle) rendered to a PNG once with cacheAsBitmap on and once off, byte-identical output; the bake is pixel-identical to direct recursive rendering), requires examples/cacheasbitmap.build.json to link Skia
  • examples/autobake.as — incremental-redraw auto cacheAsBitmap verification (offscreen + manifest: a static subtree rendered across several frames triggers fingerprint-driven auto-baking, f4/f5 pixel-identical to the direct f1; moving the subtree invalidates and re-bakes, moved/f8 identical and distinct from f1), requires examples/autobake.build.json to link Skia (off-screen, included in regression)
  • examples/bakecrisp.as — bake resolution and BitmapData.draw geometry behavior (aligned with adl)
  • examples/stage83.as — Stage3D alignment hardening (CubeTexture/RectangleTexture, render-to-texture pixel assertions, instanced drawing)
  • examples/stage86.as — flash.utils reflection (getQualifiedClassName/getDefinitionByName/dynamic instantiation)
  • examples/stage87.as — Context3D skeleton method completion (stencil/scissor/buffer upload readback/drawTriangles)
  • examples/stage88.as — AS3 language-feature gap fill (object-literal string keys, logical assignment, for each, namespaces, etc.)
  • examples/stage89.as — AS3 language-feature gaps, second batch (strict equality, generic default parameters, for multiple variable declarations, etc.)
  • examples/stage82.as — Metal end-to-end colored triangle (AGAL→MSL translation + Context3D full chain + pixel readback)
  • examples/stage81.as — stage eighty-one: Stage3D + Context3D skeleton (Stage.stage3Ds single slot + requestContext3D lazy creation + synchronous CONTEXT3D_CREATE dispatch + Context3D state machine (blend/depth/cull/program/vertex streams/textures/matrix constants) full-path calls + 15 constant class value assertions), off-screen (included in regression)
  • examples/stage80.as — stage eighty: AGAL bytecode kernel (hand-written vertex+fragment AGAL1 bytecode per the official AGALMiniAssembler encoding, asserting the MSL/GLSL translation contains the expected instructions, register mapping and swizzle/write-mask expansion, the full-mask form of the compare instructions (GLSL mix(vec4(0.0), vec4(1.0), vec4(greaterThanEqual(a, b))) / MSL select(float4(0.0), float4(1.0), a >= b)) and the partial-mask component-ternary form, and that an invalid opcode throws), off-screen (included in regression)
  • examples/stage79.as — stage seventy-nine: Stage3D geometric prerequisites (Vector3D four-component/geometric ops/static axis constants + Matrix3D column-major matrix multiply/invert/transpose/transform-vector/rotation-scale-translation constructors + decompose/recompose round-trip assertions), off-screen (included in regression)
  • examples/stage66.as — stage sixty-six: Vector.<T> higher-order/sequence methods (slice/concat/splice/forEach/map/filter/sort/reverse) and the new <T>[...] literal, off-screen (included in regression)
  • examples/stage65.as — stage sixty-five: flash.system.Capabilities environment query (version (fixed AIR-compatible "50,0,0,0"), os/cpuArchitecture conditional-compile constants, cpuAddressSize + supports64BitProcesses/supports32BitProcesses, fixed desktop values playerType/manufacturer/isDebugger/touchscreenType/screenColor/pixelAspectRatio/hasAudio, locale-derived language, screenResolutionX/screenResolutionY/screenDPI), off-screen (included in regression)
  • examples/stage64.as — stage sixty-four: flash.filesystem (File path bundle + exists/isDirectory/resolvePath/createDirectory/deleteFile/deleteDirectory + static directories applicationDirectory/userDirectory/documentsDirectory/desktopDirectory, FileStream open/openAsync (async PROGRESS+COMPLETE)/close/readUTFBytes/writeUTFBytes read/write roundtrip + read-only position/bytesAvailable, FileMode constants), off-screen (included in regression)
  • examples/stage63.as — stage sixty-three: flash.net/flash.ui (URLRequest value bundle + default method, URLLoader asynchronous local file read (pumped via tickTimers()) success/failure dispatching COMPLETE/IO_ERROR, URLVariables dynamic properties + toString() serialization, Keyboard key-code constant subset + isAccessible, Mouse static hide/show + read-only cursor), off-screen (included in regression)
  • examples/http-request-api.as — flash.net semantic surface (URLRequest property defaults, URLRequestDefaults, URLVariables.decode, useRedirectedURL)
  • examples/loader-url.as — Loader.load source dispatch and error codes (#2124/#2035, remote via the transport seam)
  • examples/urlloader-contract.as — URLLoader contract (event order, close(), dataFormat, failure error #2032)
  • examples/urlloader-network-unsupported.as — remote URL honest failure under a backendless build
  • examples/stage62.as — stage sixty-two: flash.display completion (MovieClip frame timeline play/stop/gotoAndPlay/gotoAndStop + wrapping, SimpleButton four states, Loader/LoaderInfo async load (INIT sync/COMPLETE next frame) + constants), off-screen (included in regression)
  • examples/stage61.as — stage sixty-one: flash.filters filters (BitmapFilter/BlurFilter/DropShadowFilter/GlowFilter defaults/custom construction/clone/is checks, BitmapFilterQuality constants, DisplayObject.filters read/write roundtrip, BitmapData.applyFilter box blur and deferred rasterization throwing), off-screen (included in regression)
  • examples/stage60.as — stage sixty: flash.utils.Timer (repeated triggering/TIMER_COMPLETE/stop/reset/delay setter validation + repeatCount int truncation), off-screen (included in regression)
  • examples/stage59.as — stage fifty-nine: flash.events event subclasses (TimerEvent/ProgressEvent/ErrorEvent/IOErrorEvent/DataEvent + full Event constant assertions), off-screen (included in regression)
  • examples/stage58.as — stage fifty-eight: flash.geom 2D geometry (Point/Rectangle/Matrix/ColorTransform/Transform assertions + DisplayObject.transform matrix read-back and render wiring), off-screen (included in regression)
  • examples/stage57.as — stage fifty-seven synthesis: precise GC leak assertion (after 50000 temporary record+array objects, System.gc() reclaims to zero, totalMemory does not grow linearly), off-screen (included in regression)
  • examples/gc_strings.as — stage fifty-seven GC-2: strings in the GC heap leak assertion (after 100000 string concatenations, System.gc() reclaims to zero), off-screen (included in regression)
  • examples/gc_incremental.as — stage fifty-seven GC-4: incremental marking bounded-memory assertion (800 frames each allocating temporaries, gc_step() reclaims slices per frame, heap does not grow linearly with frame count), off-screen (included in regression)
  • examples/gc_barrier.as — stage fifty-seven GC-4: write-barrier stress assertion (200 class-instance chains, 10200 nodes after direct field writes, object graph complete with no dangling after System.gc()), off-screen (included in regression)
  • examples/gc_midframe.as — mid-frame System.gc() assertion (guarding the conservative stack-scan root source)
  • examples/closure_const.as — assertion that a typed const captured by a closure behaves correctly
  • examples/sharedobject.as — flash.net.SharedObject local storage (read/write/flush/disk readback/size/clear)
  • examples/gc_alloc_threshold.as — automatic reclamation at the allocation threshold for non-GUI targets
  • examples/gc_bytes.as — ByteArray/BitmapData byte buffers included in the GC
  • examples/loop-once.as — loop conditions and for updates evaluated only once per iteration
  • examples/field-shadow.as — same-named field shadowing each occupying its own C slot + container-element increment + branch-local side effects not leaking out
  • examples/null-eq.as — null has only one representation (==/!=/===/!==/typeof/truthiness/is Object)
  • examples/async-io.as — async IO contract (data is null before the terminal event, PROGRESS before COMPLETE, concurrent requests)
  • examples/socket.as — flash.net socket layer (Socket/ServerSocket/XMLSocket loopback assertions)
  • examples/proxy.as — flash.utils.Proxy / flash_proxy interception
  • examples/with.as — the with statement
  • examples/stage94c.as — getQualifiedSuperclassName + setInterval/clearInterval
  • examples/stage94d.as — ByteArray multibyte/boolean/indexed read-write/AMF3 object read-write
  • examples/stage94e.as — Batch A legacy hard-problem push (as Object, Function-value member calls, reflection, AMF3 traits)
  • examples/stage94f.as — DisplayObject geometry and transform-aware hit testing
  • examples/stage94g.as — editable TextField model and defaults
  • examples/stage94h.as — TextField.border/borderColor and the 24-bit behavior of color properties
  • examples/stage94i.as — DisplayObject geometry/coordinate API family (getRect/getBounds/localToGlobal/hitTestObject)
  • examples/stage94j.as — dispatch semantics of MouseEvent.DOUBLE_CLICK
  • examples/stage94k.as — #1009/#1006 semantics for member access on an empty receiver
  • examples/stage94l.as — Tab/Shift+Tab focus traversal
  • examples/stage94m.as — TextField.restrict and multiline Return
  • examples/stage94n.as — visual-line navigation (PageUp/PageDown + soft-wrap Up/Down)
  • examples/stage94o.as — displayAsPassword masking
  • examples/stage94p.as — IME composing state (marked text) preview
  • examples/stage94q.as — escape decoding in string literals
  • examples/stage94r.as — the TextField border is a 1px screen-space line (not polluting local metrics)
  • examples/stage94s.as — hitTestPoint's true branch is the content area (not the bounding box)
  • examples/stage94t.as — int64/uint64 64-bit integers (enhancement, see docs/en/enhancements.md §4.7)
  • examples/textline.as — TextField.getLineMetrics / TextLineMetrics
  • examples/bytearray-index.as — the full semantics of the ByteArray index form
  • examples/vector-coerce.as — Vector.<T>(arrayLike) is a conversion, new Vector.<T>(length) is a construction
  • examples/vector-dynamic.as — Vector.<*> and dynamic access on a * receiver
  • examples/embed.as — [Embed] assets (image/byte/audio → Bitmap/ByteArray/Sound subclasses)
  • examples/strcoerce.as — implicit object → string coercion
  • examples/flash-net-layered.build.example.json — a minimal example of per-target manifest layering (not a .as; for build-layer assertions)
  • examples/builtin-class.as — the built-in class registry & Class values + in/delete/indexing
  • examples/wasm-native/ — --target wasm (WASI) products, including the --export and [WasmExport] export surfaces
  • examples/vsyncevent.as — VsyncStateChangeAvailabilityEvent (the AIR surface + the refreshRate enhancement surface) and Stage.vsyncEnabled

Each example, after compilation, leaves a same-named .c file beside it so you can directly read the compiler-generated C code.

Acknowledgments

This project stands on the shoulders of the following projects and third-party libraries, for which we are grateful:

  • TypePHP (official site) — an AOT compiler that compiles PHP into native binaries. The overall approach of "the compiler frontend only translates, delegating optimization and machine-code generation to mature C compilers — no reinventing the wheel", along with the build manifest (project.yml) and multi-target backend design, is borrowed from it.
  • Ruffle (official site) — the open-source Rust reimplementation of Adobe Flash. Its flash.events.* event flow, flash.display.* display list, and interactive hit-testing implementations for AS3/AVM2 are the authoritative reference for this project's GUI/event-system semantics.
  • Skia (official site) — the 2D graphics library and rendering backend. This project links Skia for rasterization via the C++ glue layer (using the Aseprite precompiled static libraries m124).
  • SDL (official site) — the cross-platform window/input library, the windowed backend (Stage.showWindow) uploads and runs its event loop via SDL2.
  • miniaudio (v0.11.25) — a single-header audio library, the audio backend for flash.media (its own translation unit vendor/audio_glue.c; Sound/SoundChannel/SoundMixer/SoundTransform etc. are driven by it onto Core Audio; on the web it lands on Web Audio, and WASI honestly reports the absence of a backend).
  • libcurl (official site) — the HTTP/HTTPS client for flash.net. The native build links the static archives under vendor/curl/ (curl 8.11.1 + nghttp2 1.64.0 for HTTP/2 + zlib 1.3.1 to decode gzip/deflate, with TLS via the system SecureTransport), leaving no libcurl.4.dylib dynamic dependency in the product.
  • Emscripten (official site, 3.1.44) — the toolchain for --target wasm --package web browser products (build-tools/emsdk), compiling and linking the wasm Skia via emcc; the web audio backend also uses its bundled emscripten/webaudio.h (AudioWorklet).
  • HarfBuzz — the text-shaping engine pulled in with Skia's precompiled static libraries, performing the flash.text TextField/TextFormat layout (SkParagraph + HarfBuzz shaping + UAX#14 line breaking).

About

Compile ActionScript 3 source code ahead-of-time (AOT) into native machine code, producing native executables — while keeping the AS3 syntax you already know.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages