2D Blueprint catalog · Test event schema · Lifecycle example · Sound/menu example · 3D input, export and widget reference
Aether 0.10.149 — 2D lifecycle, random and sound
Browser editor, shared MCP and desktop shared editor report 0.10.149. Native Studio, Player, MCP and CAD binaries remain CP139. Their packaged 2D web runtime assets have been updated; this is not a rebuild of the native renderer or full browser/native parity.
Lifecycle and startup
EvConstruction runs before EvBeginPlay, and EvBeginPlay runs once for each actor when the runtime starts. Spawned actors receive their startup once on spawn. Calling start again does not repeat startup.
EvTick now fires once per simulation step at 120 Hz. GetVar with s="DeltaSeconds" reads the step duration (1/120 second). CustomEvent named "Tick" continues to work for existing projects. If both forms are authored, both event chains execute; use one for a single update chain.
The previous 0.10.148 test harness did invoke EvBeginPlay; the regression reproduced that behavior. An authored START button is a separate widget/custom event and is not automatically clicked. The test harness now accepts those events directly, so menu-gated games can start without post-export workarounds.
Numeric equality
Equal compares Integer and Float by numeric value, including inside array/set comparisons. Add still returns Float. Add(1,2) now equals LitInt(3). String "3" and Boolean true retain their types; they do not equal numeric 3 and 1. Numeric values use float32; Equal remains exact equality, not an approximate floating-point comparison.
Random nodes
Random and RandomFloat return Float. RandomInt returns Integer. Set v to the lower bound and v2 to the upper bound; omitted bounds default to 0 and 1. RandomInt includes both endpoints. Bounds must be finite within +/-1,000,000, ordered low to high, and integers for RandomInt.
{"kind":"RandomInt","v":-3,"v2":3}
Each value evaluation advances a deterministic random stream. Save a sample using SetVar if multiple consumers must share it. The project-level randomSeed is an unsigned 32-bit integer, default 1. Replaying the same project and event sequence repeats the same sequence; change randomSeed for another sequence. This is gameplay randomness, not a cryptographic generator.
2D sound assets
Use aether_sound_synthesize or aether_sound_upsert on a project containing twoD. The tools now store assets in twoD.sounds rather than requiring program3d. The same tools still support 3D programs. A mixed document with twoD routes these sound tools to the active 2D project.
{"name":"aether_sound_synthesize","arguments":{"project_id":"YOUR_PROJECT","id":"jump","name":"Jump","recipe":{"duration":0.15,"seed":1,"layers":[{"wave":"sine","frequency":440,"endFrequency":880,"gain":0.3}]}}}
Trigger an embedded sound from an execution wire using PlaySound with s set to the sound ID:
{"kind":"PlaySound","s":"jump","exec_out":[-1]}
WAV, MP3 and OGG data URLs are embedded in the saved project and exported HTML. Limits: 32 assets, 16 MB total encoded audio, 5.6 MB per asset, 180 seconds per decoded clip, 64 MB decoded PCM, 32 concurrent voices. Browser codec support still applies. Playback unlocks through a real user interaction with Play; browser autoplay denial is surfaced as an error. Legacy sound names without assets retain the old short synthesized beep behavior. Use a saved asset for an authored sound effect.
Headless tests record requested sound IDs and simulation times under audio.events. They do not render audio and return audio.rendered=false.
Test events
Use aether_2d_project_test. frames is 0..7200 at 60 test frames per second, with two 1/120-second simulation steps per test frame. Events at frame N are applied after automatic startup and before that frame's simulation. Work budgets still apply. Up to 2048 input events and 2048 property commands are accepted.
{"project_id":"YOUR_PROJECT","frames":120,"events":[{"frame":0,"type":"widget","id":"start"},{"frame":1,"code":"Space","pressed":true},{"frame":2,"code":"Space","pressed":false},{"frame":30,"type":"event","target":"Player","name":"Turn"}]}
Widget events use an existing control ID and optional numeric value; the same visibility/enabled checks and bindings used by browser Play apply. Custom events use an unambiguous actor name and the authored CustomEvent name. Legacy frame/code/pressed input events remain valid. startup.begunActors identifies initialized actors. A missing custom event is rejected rather than silently ignored. Tests do not invent a START event for a game that did not author one.
Sprite rotation
Actor yaw is radians. SetActorProp with s="rot_yaw" accepts an absolute angle in radians through input 0 or s2. SetRelRot uses degrees relative to the actor's initial rotation. Image and primitive sprites rotate around the actor origin; sprite offsets rotate with that transform. Snapshot objects now include yaw and scale, so headless assertions can inspect rotation. The regression verifies the actual Canvas2D rotate command, not the appearance of the customer's tank artwork.
Catalog and validation
Call aether_blueprint_catalog with runtime="2d" to obtain the 2D node list and the lifecycle, random, audio and rotation contract. Without that argument the existing mission catalog is returned. aether_2d_project_read includes the 2D catalog and updated node-kind schema. Unsupported node names and invalid random ranges fail validation on import/apply/export.
Verification boundary
Automated tests cover startup ordering and once-only execution, EvTick and legacy Tick, mixed numeric equality, seeded random replay, unsupported-node rejection, START-widget/custom-event simulation, audio asset authoring and event tracing, actual exported JavaScript execution, and Canvas2D rotation commands. The actual desktop MCP produces matching HTML. Physical-GPU gameplay, audible playback and graphical Windows/Linux installation have not been certified here.
Full native modeling, CAD and native-only graph operations still require their paired desktop workspace. The 0.10.148 single-file WebGL2 export, mouse input, widget migration and cross-actor visibility changes are retained. The existing two-second Created with Aether splash remains.