Skip to content

PHO-83/#153 T12 · D: Modifier.lumosPointer and the LumosOrb plumbing — hover, touch, scroll pass-through, the pointer on LumosCanvasFrame; LumosInputPreview and the desktop recording - #179

Merged
wow-miley merged 1 commit into
mainfrom
miley/pho-83-t12-d-modifierlumospointer-and-the-lumosorb-plumbing-hover
Oct 17, 2026
Merged

wow-miley merged 1 commit into
mainfrom
miley/pho-83-t12-d-modifierlumospointer-and-the-lumosorb-plumbing-hover

Conversation

@wow-miley

Copy link
Copy Markdown
Contributor

Closes #153 (PHO-83). Builds on #175 (PHO-82, T12 · C).

What

  • Modifier.lumosPointer(tiltDegrees = 0f, onInput) in :phosphor-lumos-compose, for a consumer drawing LumosCanvas directly. A Modifier.Node over SuspendingPointerInputModifierNode, so it is common to all six targets (onPointerEvent is skiko-only). It reads PointerEventPass.Final and never consumes.
    • Mouse and stylus: Enter/Move set the pointer, Exit sends NONE; a button press keeps the hover and pressed follows the button.
    • Touch: Press/Move set the pointer with pressed = true, Release sends NONE.
    • A change someone else consumed (a parent's scroll past touch slop) sends NONE, then the handler waits for every pointer to lift.
    • The handler's finally sends NONE. A new onInput on recomposition updates the node without restarting the handler.
    • Mapping: x = 2·px/w − 1, y = 1 − 2·py/h, then y = sy·cos t + √(max(0, 1 − x² − sy²))·sin t for a tilt.
  • LumosCanvasFrame.pointer: Vector2? (@Transient, canvas px, Y down) for a material's light. PixelLattice.project(frame, pointer = frame.input?.pointer) carries it; PixelLattice.canvasPointer is the forward mapping, re-tilted and placed in the viewport, so the light lands on the voxel under the pointer.
  • OrbStepper.setInput hands the pointer to the source and lays the latest one over every frame projected after it, live, still or recorded. NONE clears a stale pointer even on a live frame built before it left. A stepper never handed input leaves the frame's own pointer alone, so :phosphor-lumos-surface is unchanged. LumosDriver.setInput and a once-allocated onInput wrap it.
  • LumosOrb carries the modifier on its Box with config.tiltDegrees, and a DisposableEffect(driver) tells the source NONE when the orb leaves composition or its source is replaced. No frame is published for a pointer move alone, so a paused or reduced-motion orb draws nothing extra.
  • LumosInputPreview: three interactive THINKING orbs — alone, pointed at the centre, pointed upper right — each settled under its pointer.
  • README: the Lumos section gains the pointer paragraph and a compiled PointedCanvas snippet, held to the quick start's rule by ReadmeLumosQuickStartTest.

Tests

./gradlew ktlintFormat :phosphor-lumos:jvmTest :phosphor-lumos-compose:jvmTest --offline is green locally; goldens unchanged.

  • PixelLatticePointerTest (lumos commonTest): the frame's pointer in px, override and clear, tilt matches the front voxel and keeps the rim on the rim, past-the-rim on the equatorial plane, viewport, aspect.
  • OrbStepperTest: setInput goes to the source and projects nothing by itself; the latest pointer lights live, still and recorded frames; NONE clears a stale live pointer; a stepper never handed input leaves the frame's own.
  • LumosPointerMappingTest (compose commonTest): centre, corner, past the node, 30° tilt, and round trips through PixelLattice.canvasPointer tilted and untilted.
  • LumosDriverTest: onInput reaches the source and lights the next frame in px.
  • LumosOrbPointerTest (jvmTest, through SteppedScene.sendPointerEvent / sendTouch): hover at the centre (0, 0) and top-left (−1, 1), Exit → NONE; a mouse button follows pressed without ending the hover; touch press/release; an orb inside Column(Modifier.verticalScroll(state)) lets a touch drag scroll the column and reports NONE once the scroll takes over; removal reports NONE; a 30° tilt maps the front centre to y = sin 30°.
  • LumosInputPreviewTest: the strip to build/lumos-previews/lumos-input-strip.png, and the desktop recording — a scripted pointer sweep driven through LumosOrb with real pointer events on desktop Skia, 90 frames at 30 fps — to build/lumos-previews/lumos-input-repel.gif, written through a small javax.imageio GifWriter (test-only).

Calls to review

Not done here

  • Posting the strip and GIF on PHO-64: that publishes to the public repo, left to Miley. Both are in this workspace's .context/.
  • The iOS simulator check (T12 · E, PHO-84), drawing with the light (T11), a Compose bump.

🤖 Generated with Claude Code

…— hover, touch, scroll pass-through, the pointer on LumosCanvasFrame; LumosInputPreview and the desktop recording

- `Modifier.lumosPointer(tiltDegrees, onInput)` in :phosphor-lumos-compose: a
  Modifier.Node over SuspendingPointerInputModifierNode that reads the Final
  pass and never consumes. Mouse and stylus report on Enter/Move, NONE on Exit,
  pressed follows the button; touch reports Press/Move pressed and NONE on
  Release. A consumed change reports NONE and waits for every pointer to lift.
  The handler's finally reports NONE. A new lambda never restarts it.
- The mapping inverts PixelLattice: x = 2px/w − 1, y = 1 − 2py/h, then
  un-tilted onto the front of the unit sphere.
- `LumosCanvasFrame.pointer` (@transient, canvas px). `PixelLattice.project`
  takes an optional pointer, defaulting to the frame's input, and
  `canvasPointer` is the forward mapping, re-tilted and placed in the viewport.
- `OrbStepper.setInput` hands the pointer to the source and lays the latest
  one over every frame projected after it, live, still or recorded; NONE
  clears a stale live pointer. `LumosDriver.setInput` / `onInput` wrap it.
- `LumosOrb` carries the modifier on its Box and tells the source NONE when
  the driver is disposed (orb gone or source replaced).
- `LumosInputPreview`: three interactive THINKING orbs — alone, centre, upper
  right. `LumosInputPreviewTest` writes the strip and a 3 s, 30 fps GIF of a
  scripted pointer sweep driven through LumosOrb with real pointer events.
- `SteppedScene` gains `sendPointerEvent` and `sendTouch`.
- README: the pointer section with a compiled `PointedCanvas` snippet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@wow-miley
wow-miley merged commit 7c221f1 into main Oct 17, 2026
4 checks passed
@wow-miley
wow-miley deleted the miley/pho-83-t12-d-modifierlumospointer-and-the-lumosorb-plumbing-hover branch October 17, 2026 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant