Skip to content

feat(stdlib): @pixi/ui binding (bindings #3) - #435

Merged
hyperpolymath merged 1 commit into
mainfrom
feat/bindings-3-pixi-ui
May 28, 2026
Merged

feat(stdlib): @pixi/ui binding (bindings #3)#435
hyperpolymath merged 1 commit into
mainfrom
feat/bindings-3-pixi-ui

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Summary

Adds an MVP @pixi/ui binding (stdlib/PixiUI.affine + Deno-ESM codegen lowerings) so idaptik's HUD + menu layer (src/bindings/PixiUI.res) can move off ReScript. Follows the pattern proven by wasmCall (#422) / motion (#422 bundle) / Pixi (#429 open).

Row #3 in docs/bindings-roadmap.adoc moves -> scaffold.

Surface

  • 5 opaque host types: Button, FancyButton, Slider, Switch, Container (re-declared opaque so this module can be consumed without a hard dependency on stdlib/Pixi.affine).
  • 11 extern fns: ctor + primary event-callback registrar + zero-cost AsContainer upcast for each component.
  • 11 __as_pixiUi* runtime helpers + deno_builtins table entries in lib/codegen_deno.ml.
  • Consumer sets globalThis.__as_pixi_ui = PixiUI once at module-init.

Deferred (follow-ups)

  • Input (text-entry + focus + value)
  • ScrollBox (scroll position + viewport)
  • Full event surface (onHover / onOut / onDown / onUp)
  • FancyButton textures-per-state, Slider min/max/step accessors

Test plan

  • dune build bin/main.exe clean
  • bash tools/run_codegen_deno_tests.sh — 9/9 harnesses green (was 8/8; +pixiui_smoke with 17 assertions)
  • All new files MPL-2.0 SPDX; no .as / AGPL / PMPL
  • Hypatia security scan: no new findings (delta-only — pre-existing baselines ignored per repo CLAUDE.md)

Note: pre-existing flaky E2E Node-CJS Codegen tests #4/#5 unrelated.

🤖 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

Adds an MVP @pixi/ui surface for idaptik's HUD + menu layer
(`src/bindings/PixiUI.res`), following the Deno-ESM pattern proven by
wasmCall (#422) / motion (#422 bundle) / Pixi (#429 / open).

Coverage in this version (row #3 status `○` -> `◐` scaffold):

- 5 opaque host types: `Button`, `FancyButton`, `Slider`, `Switch`,
  `Container` (the last re-declared opaque so this module can be
  consumed without a hard dependency on `stdlib/Pixi.affine`; the JS
  values coincide at runtime because @pixi/ui's components are real
  PIXI.Container subclasses).
- 11 extern fns: `new`-style constructor + primary event-callback
  registrar + zero-cost `AsContainer` upcast for each component
  (Input + ScrollBox deferred to follow-up — see row #3).
- 11 `__as_pixiUi*` runtime helpers + lowering-table entries in
  `lib/codegen_deno.ml`. Consumer sets `globalThis.__as_pixi_ui =
  PixiUI` at module-init (mirrors the motion `__as_motion` pattern
  and the prospective Pixi `__as_pixi` pattern).
- `tests/codegen-deno/pixiui_smoke.{affine,harness.mjs}` — 17
  assertions covering ctor-options round-trip, callback-identity
  preservation through `.connect()`, and identity upcast for all
  four components.
- `docs/bindings-roadmap.adoc` row #3 updated: status, package home
  set to `stdlib/PixiUI.affine`, deferred follow-ups enumerated.

Test plan:

- [x] codegen-deno suite: 9/9 harnesses green (was 8/8; +pixiui_smoke)
- [x] `dune build bin/main.exe` clean
- [x] All new files carry SPDX `MPL-2.0` headers
- [x] No `.as` files added; no AGPL / PMPL headers anywhere

Out of scope (deferred):

- `Input` (text-entry, focus, blur, value accessor)
- `ScrollBox` (scroll position, content add/remove, viewport)
- Full event surface (onHover / onOut / onDown / onUp beyond the one
  primary callback per component)
- FancyButton textures-per-state accessors
- Slider min/max/step accessors
- Migration from `stdlib/` to a separate `affinescript-pixijs`
  sub-module per the eventual Pixi #1 split (additive,
  source-compatible).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath
hyperpolymath force-pushed the feat/bindings-3-pixi-ui branch from 0ab8b91 to 3561472 Compare May 28, 2026 13:17
@hyperpolymath
hyperpolymath merged commit d7deeeb into main May 28, 2026
@hyperpolymath
hyperpolymath deleted the feat/bindings-3-pixi-ui branch May 28, 2026 13:17
@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