Skip to content

feat(stdlib): motion binding — animateMini/tween/spring/ease (bindings #4 → ●) - #436

Merged
hyperpolymath merged 1 commit into
mainfrom
feat/bindings-4-motion-complete
May 28, 2026
Merged

feat(stdlib): motion binding — animateMini/tween/spring/ease (bindings #4 → ●)#436
hyperpolymath merged 1 commit into
mainfrom
feat/bindings-4-motion-complete

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Summary

Promotes bindings roadmap row #4 (motion) from ◐ scaffold to ● usable by landing the four deferred surfaces flagged in docs/bindings-roadmap.adoc:

  • motionAnimateMini — lightweight variant of animate (no autoplay, no built-in thenable).
  • motionTween — one-shot interpolation between explicit from/to values.
  • motionSpring — physics-based spring animation (stiffness/damping/mass).
  • motionEase + opaque Easing type — easing-function constructor by canonical motion name.

Changes

  • stdlib/Motion.affine: 4 new extern fn declarations + the new extern type Easing opaque carrier; module docstring updated to reflect the now-comprehensive surface.
  • lib/codegen_deno.ml: 4 new runtime helpers (__as_motionAnimateMini / __as_motionTween / __as_motionSpring / __as_motionEase) inserted right after __as_motionCancel in the prelude; 4 matching lowering-table entries inserted after b "motionCancel". Each helper resolves the host method on globalThis.__as_motion lazily, so partial mocks still work for the rest of the surface.
  • tests/codegen-deno/motion_smoke.{affine,harness.mjs}: extended in place with smokeAnimateMini / smokeTween / smokeSpring / smokeEase wrappers + arg-routing and return-value assertions for every new extern (the original animate + cancel assertions are preserved).
  • docs/bindings-roadmap.adoc: row ci: Bump actions/cache from 5.0.2 to 5.0.4 #4 status ◐ scaffold● usable; rationale lists the full extern surface, calls out the smoke fixture, and notes the remaining (out-of-scope-for-●) follow-ups (typed keyframe shapes, typed transform-property surface, migration to a dedicated affinescript-motion package).

Test plan

  • dune build bin/main.exe clean.
  • bash tools/run_codegen_deno_tests.sh — all 8 harnesses pass, including the extended motion_smoke with 4 new wrappers and full ease/spring/tween/animateMini coverage.
  • CI green on the standard PR matrix.

Notes for reviewers

Closes part of bindings roadmap #4.

🤖 Generated with Claude Code

@hyperpolymath
hyperpolymath enabled auto-merge (squash) May 28, 2026 12:57
@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 81 issues detected

Severity Count
🔴 Critical 4
🟠 High 10
🟡 Medium 67

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action actions/checkout@v6 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action denoland/setup-deno@v2 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in affine-vscode-publish.yml",
    "type": "unknown",
    "file": "affine-vscode-publish.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "unknown",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "unknown",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

…#4 → ●)

Promotes bindings #4 (motion) from ◐ scaffold to ● usable by adding the
four deferred surfaces flagged in docs/bindings-roadmap.adoc:

- motionAnimateMini — lightweight variant (no autoplay / no thenable).
- motionTween       — one-shot from/to interpolation.
- motionSpring      — physics-based spring with stiffness/damping/mass.
- motionEase        — easing-function constructor + opaque Easing type.

stdlib/Motion.affine gains the four extern fns plus the new opaque
`Easing` type. The Deno-ESM codegen prelude gains `__as_motionAnimateMini`
/ `__as_motionTween` / `__as_motionSpring` / `__as_motionEase` runtime
helpers (each resolves the host method on globalThis.__as_motion at call
time so a partial mock still works); the lowering table gains the four
matching extern entries.

The motion_smoke fixture is extended (same .affine + .harness.mjs pair —
no new files) with smokeAnimateMini / smokeTween / smokeSpring / smokeEase
wrappers and arg-routing + return-value assertions for each. All 8
codegen-deno harnesses pass locally.

The bindings-roadmap row #4 flips ◐ → ● and the rationale lists the full
surface; remaining follow-ups (typed keyframe shapes, typed transform
properties, migration to a dedicated affinescript-motion package) are
explicitly out of scope for the ● promotion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath
hyperpolymath force-pushed the feat/bindings-4-motion-complete branch from 02515ac to e7dd3de Compare May 28, 2026 13:18
@hyperpolymath
hyperpolymath merged commit c50ffdc into main May 28, 2026
13 of 23 checks passed
@hyperpolymath
hyperpolymath deleted the feat/bindings-4-motion-complete branch May 28, 2026 13:19
@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 81 issues detected

Severity Count
🔴 Critical 4
🟠 High 10
🟡 Medium 67

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action actions/checkout@v6 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action denoland/setup-deno@v2 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in affine-vscode-publish.yml",
    "type": "unknown",
    "file": "affine-vscode-publish.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "unknown",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "unknown",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

hyperpolymath added a commit that referenced this pull request May 31, 2026
…ngs #1) (#502)

## Summary

Extends the Tier-1 PixiJS binding (#446 row #1) with the 11
most-load-bearing accessors + on/off pointer-event registration. This is
the **largest single chunk** of idaptik's `src/bindings/Pixi.res`
surface still not bound — 215 `src/app/*.res` files depend on Container
transforms and FederatedPointerEvent handlers, so this PR is a forward
unblocker for the ReScript→AffineScript migration.

## What lands

`stdlib/Pixi.affine` (+46 lines): 11 new `extern fn`s.

| Surface | Externs |
|---|---|
| Container transforms | `pixiContainerSetScale`, `SetPivot`,
`SetRotation`, `SetAlpha`, `SetZIndex`, `SetSortableChildren`,
`SetEventMode`, `SetCursor` |
| FederatedPointerEvent registration | `pixiContainerOn`,
`pixiContainerOff` |
| Sprite | `pixiSpriteSetAnchor` |

`lib/codegen_deno.ml` (+22 lines): 11 `__as_*` prelude helpers + 11
entries in the existing `deno_builtins` dispatch block, matching the
existing wasmCall/motion/pixi pattern.

`tests/codegen-deno/pixi_smoke.{affine,harness.mjs}` (+80 lines
combined): new `smokeAccessorsFlow` exercises every new extern via the
existing harness pattern. `MockContainer` grows `scale`/`pivot` Point
mocks + handler `Map` + the new fields; asserts handler identity is
preserved across `on(...)` → `off(...)`.

`docs/bindings-roadmap.adoc` row #1 status note expanded — Container 8.x
transform-and-event surface promoted from "deferred" to "landed";
remaining deferred items (typed `FederatedPointerEvent` accessors,
`parent` read accessor with Option-null handling, Point/Rectangle/Circle
helper types, sprite atlases, filters, hitArea) listed explicitly.

## Design notes

**Why `pub extern fn pixiContainerSetEventMode(c, mode: String)` rather
than a sum type?** Pixi 8's `eventMode` values are open strings
(`"static"` / `"dynamic"` / `"passive"` / `"none"` / `"auto"`). A sum
type would either freeze the set or require codegen-tagged-variant
lowering that doesn't yet exist on the Deno-ESM backend (deferred to
json.affine v0.3, mirroring the `WasmValue` decision in #467). Matches
the existing pattern in `stdlib/PixiUI.affine` for `slider.orientation`.

**Why `handler: Json`?** The `FederatedPointerEvent` reaches the handler
as a JS object; AffineScript-side code uses existing `Json` accessors to
read `e.global.x`, `e.target`, etc. A typed `FederatedPointerEvent`
extern type with dedicated accessor `extern fn`s is the natural
follow-up — captured in the roadmap row as a deferred item, not in this
PR's scope. The Json handler avoids forcing every caller through a typed
surface they may not want.

**Anchor is on Sprite, not Container.** Pixi 8 keeps the same split as
7.x — `Container` has no `anchor`. The binding mirrors that with
`pixiSpriteSetAnchor` rather than putting it on
`pixiContainerSetAnchor`.

## Test plan

- [x] `dune build bin/main.exe` — clean (only the expected parser
warnings)
- [x] `dune runtest` — 354 tests pass
- [x] `tools/run_codegen_deno_tests.sh` — all 17 harnesses including
extended `pixi_smoke.harness.mjs` OK
- [ ] CI build job
- [ ] CI `tools/run_codegen_deno_tests.sh` job
- [ ] CI governance + Hypatia (known baselines per repo CLAUDE.md may be
red — those are not from this PR)

## Refs

- Umbrella: #446 (Tier 1 — idaptik blockers)
- Tier-1 sub-issue: #450
- Row updated: `docs/bindings-roadmap.adoc` row #1
- Prior PixiJS-related PRs for context: #429 (restart on Deno-ESM), #435
(@pixi/ui MVP), #436 (motion ●), #437 (@pixi/sound)
- Compile-time pattern doc: `docs/specs/zig-ffi-patterns.adoc` (PR #474
— non-conflicting siblings)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant