You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Forge has no way to accept typed text. A chat box, a name-entry prompt, a debug console, a seed field, or a search box are all currently impossible.
Raised by @stormmuller while reviewing #580, following the observation that a "text input" is really three concerns and only one of them is UI-shaped. Split out of the UI design for the same reason as text rendering (#584) and clipping (#583).
The three concerns
Concern
Home
Notes
Text entry — keystrokes, caret, selection, IME, clipboard, soft keyboard
/src/input
Where all the genuinely hard browser complexity lives. Reusable by anything needing typed input, not specific to one widget.
Text display — drawing the string, caret, and selection highlight
Text selection by drag and by keyboard, word-jump modifiers, platform-specific caret conventions
Screen-reader accessibility
Browsers already solve every one of these correctly. This is the one place where DOM interop is the right engineering call rather than a shortcut, and it's the standard approach in browser game engines (PixiJS, Phaser).
Suggested approach
A small primitive in /src/input — roughly "give me a hidden DOM input synced to this screen rect, and tell me its value, caret, and selection":
Creates an off-screen or transparent <input> / <textarea>, positioned to follow a screen rect so mobile keyboards and IME candidate windows appear in the right place. Positioning needs worldToScreenSpace, already present in src/rendering/transforms/.
Exposes value, caret index, selection range, and composition state as plain data for a system to read.
Handles focus/blur, and cleans up the DOM node on teardown.
Emits change/submit/cancel as InputActions where it makes sense, consistent with docs(ui): add design document for the Forge UI system #580's DL-14 — so text entry can also be driven programmatically for tests and scripted tutorials.
Then a thin TextInputEcsComponent in /src/ui binds that primitive to a focusable rect, and renders value + caret + selection via #584.
Design questions worth settling early
Multiline.<input> vs <textarea> changes wrapping, Enter semantics, and caret navigation. Deciding up front avoids a rewrite.
design/ui-system.md DL-10 holds the decision record that led here and now defers to this issue.
One consequence worth noting: moving the DOM bridge out means the UI module's "no DOM-backed widgets" non-goal becomes a real invariant rather than one with an exception carved out of it. The UI module stays DOM-free, and the unavoidable browser interop sits in /src/input alongside the other input-source complexity.
Summary
Forge has no way to accept typed text. A chat box, a name-entry prompt, a debug console, a seed field, or a search box are all currently impossible.
Raised by @stormmuller while reviewing #580, following the observation that a "text input" is really three concerns and only one of them is UI-shaped. Split out of the UI design for the same reason as text rendering (#584) and clipping (#583).
The three concerns
/src/input/src/ui(#580)This issue covers the first, and the thin UI component that consumes it.
Why a hidden DOM
<input>rather than hand-rolled key handlingHand-rolling from
KeyboardInputSourcemeans reimplementing:Browsers already solve every one of these correctly. This is the one place where DOM interop is the right engineering call rather than a shortcut, and it's the standard approach in browser game engines (PixiJS, Phaser).
Suggested approach
A small primitive in
/src/input— roughly "give me a hidden DOM input synced to this screen rect, and tell me its value, caret, and selection":<input>/<textarea>, positioned to follow a screen rect so mobile keyboards and IME candidate windows appear in the right place. Positioning needsworldToScreenSpace, already present insrc/rendering/transforms/.InputActions where it makes sense, consistent with docs(ui): add design document for the Forge UI system #580's DL-14 — so text entry can also be driven programmatically for tests and scripted tutorials.Then a thin
TextInputEcsComponentin/src/uibinds that primitive to a focusable rect, and renders value + caret + selection via #584.Design questions worth settling early
<input>vs<textarea>changes wrapping, Enter semantics, and caret navigation. Deciding up front avoids a rewrite.TextMeshEcsComponentshould expose glyph advances/positions rather than only quads. Worth raising on feat(text): text rendering — MSDF font atlases, shaping, and a TextEcsComponent #584 before that API is fixed, since retrofitting it later is more disruptive than including it.Dependencies
Relationship to #580
design/ui-system.mdDL-10 holds the decision record that led here and now defers to this issue.One consequence worth noting: moving the DOM bridge out means the UI module's "no DOM-backed widgets" non-goal becomes a real invariant rather than one with an exception carved out of it. The UI module stays DOM-free, and the unavoidable browser interop sits in
/src/inputalongside the other input-source complexity.