feat(textbox): add rotation support for textbox rendering - #862
Draft
zachelnet wants to merge 6 commits into
Draft
feat(textbox): add rotation support for textbox rendering#862zachelnet wants to merge 6 commits into
zachelnet wants to merge 6 commits into
Conversation
zachelnet
requested review from
Map1en,
fffonion,
karrot0,
liksunrice and
mayocream
as code owners
July 12, 2026 12:40
|
Thanks for your first PR to Koharu. Please review our contribution guide before review: In the PR description, include:
If AI helped produce the patch, a human still needs to review and understand it before submission. |
zachelnet
force-pushed
the
feat/textbox-rotation
branch
from
July 12, 2026 12:45
089300e to
4f3a747
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Adds end-to-end rotation support for textboxes so the editor UI, canvas overlays, and Rust render pipeline can all represent and render rotated text consistently.
Changes:
- Adds a rotation control to the render controls panel (with localized label strings).
- Updates canvas text block overlays to rotate the selection box, keep resize behavior intuitive under rotation, and rotate resize cursors.
- Applies rotation during final sprite composition in the Rust renderer via a custom rotate+resample path.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| ui/public/locales/zh-TW/translation.json | Adds render.rotationLabel localization. |
| ui/public/locales/zh-CN/translation.json | Adds render.rotationLabel localization. |
| ui/public/locales/tr-TR/translation.json | Adds render.rotationLabel localization. |
| ui/public/locales/ru-RU/translation.json | Adds render.rotationLabel localization. |
| ui/public/locales/pt-BR/translation.json | Adds render.rotationLabel localization. |
| ui/public/locales/ko-KR/translation.json | Adds render.rotationLabel localization. |
| ui/public/locales/ja-JP/translation.json | Adds render.rotationLabel localization. |
| ui/public/locales/es-ES/translation.json | Adds render.rotationLabel localization. |
| ui/public/locales/en-US/translation.json | Adds render.rotationLabel localization. |
| ui/components/panels/RenderControlsPanel.tsx | Introduces rotation UI and writes transform.rotationDeg updates to the selected text node. |
| ui/components/Panels.tsx | Adjusts tab panel sizing/scroll behavior (likely to accommodate additional controls). |
| ui/components/canvas/TextBlockLayer.tsx | Rotates selection overlay/sprites, updates resize math for rotated boxes, and rotates resize cursors. |
| crates/koharu-app/src/renderer.rs | Rotates text sprites during composition using a custom rotate+bilinear resample implementation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
zachelnet
force-pushed
the
feat/textbox-rotation
branch
from
July 12, 2026 13:00
4f3a747 to
ed2ba7e
Compare
zachelnet
force-pushed
the
feat/textbox-rotation
branch
from
July 12, 2026 13:09
ed2ba7e to
d01b760
Compare
zachelnet
force-pushed
the
feat/textbox-rotation
branch
from
July 12, 2026 13:28
d01b760 to
6119ea2
Compare
zachelnet
force-pushed
the
feat/textbox-rotation
branch
from
July 12, 2026 13:42
6119ea2 to
6145919
Compare
zachelnet
force-pushed
the
feat/textbox-rotation
branch
from
July 15, 2026 21:46
6145919 to
da92bd6
Compare
zachelnet
force-pushed
the
feat/textbox-rotation
branch
from
July 15, 2026 22:52
7dc3e92 to
d726ab7
Compare
zachelnet
marked this pull request as ready for review
July 15, 2026 22:54
zachelnet
force-pushed
the
feat/textbox-rotation
branch
from
July 16, 2026 05:54
b62714a to
de4dc6d
Compare
Add rotation controls and rendering for text blocks across the full stack — Rust renderer, React canvas overlay, and settings panel. Renderer (koharu-app): - overlay_sprite_with_rotation: CSS top-left rotation model with bilinear resampling; 90/180/270° integer fast paths - sample_bilinear_rgba: premultiplied-alpha interpolation with float precision to avoid edge halos - sprite_collides_with_bubble_mask: rotation-aware collision check using rotated sprite matching render overlay - centred_sprite_transform: keeps rotated text visually centered UI (TextBlockLayer): - Rotated resize with local-coordinate projection - Rotated resize cursors via ROTATE_CURSOR_MAP (45° steps) - BlockSprite overlay matches renderer (center rotation origin) UI (RenderControlsPanel): - Range slider + number input + ± buttons - Draft-state pattern for smooth keyboard/slider interaction - Batch rotation across multi-selected nodes via ops.batch - Escape clears draft; commits on pointerUp/blur/keyUp Panels: max-h-60 constraint on layout tab. i18n: rotationLabel added to all 9 locales. Tests: 5 Rust rotation tests + 1 UI rotation test. Co-authored-by: DeepSeek V4 <deepseek@v4.ai>
zachelnet
force-pushed
the
feat/textbox-rotation
branch
from
July 16, 2026 06:59
de4dc6d to
2d0a7f4
Compare
- updateSelectedRotation now sets lockLayoutBox:true so manual rotation survives subsequent layout passes (matches drag/resize). - rotate_sprite_expand_top_left: use rem_euclid(4) for quadrant selection to avoid panic when normalized is near 360° (e.g. 359.9996° rounds to 360, hitting unreachable!()). Co-authored-by: DeepSeek V4 <deepseek@v4.ai>
The center-based BlockSprite positioning (transformOrigin: center / translate(-50%, -50%)) caused the sprite overlay to drift relative to the text block when zooming. The translate(-50%, -50%) depends on the element's rendered dimensions which can briefly change during re-render. Revert to the original top-left model with rotate() as an addition. The renderer still centers rotated sprites correctly; the UI overlay is a preview where minor rotation offset is acceptable. Co-authored-by: DeepSeek V4 <deepseek@v4.ai>
zachelnet
marked this pull request as draft
July 16, 2026 19:52
Co-authored-by: DeepSeek V4 <deepseek@v4.ai>
When a user manually rotates a text block via the UI, the rotation is stored in Transform.rotation_deg, not TextData.rotation_deg. The PSD export previously only read TextData.rotation_deg, falling back to the AI-predicted angle, which meant user rotations were silently lost on PSD export. Now falls back to Transform.rotation_deg when TextData.rotation_deg is None. Co-authored-by: DeepSeek V4 <deepseek@v4.ai>
- Remove excessive doc comments (normalize_rotation, ROTATE_CURSOR_MAP, sample_bilinear_rgba, etc.) — code is self-documenting. - Rename rotate_point_top_left → rotate_point (rotates around origin, not specifically a corner). - Fix dead clamp(0.0, 255.0) in sample_bilinear_rgba (alpha already in 0..1 range after /255.0 normalization). - Improve 180° overlay test from weak any(alpha != 0) to precise pixel position assertion. Co-authored-by: DeepSeek V4 <deepseek@v4.ai>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds rotation support for textboxes in the rendering pipeline.
What changed
rotationhandling in textbox data/model.User-visible behavior
Validation
Demo
Bildschirmaufzeichnung.vom.2026-07-12.14-37-07.mp4
AI Disclosure
AI-assisted (DeepSeek V4).
The final patch was reviewed and validated by the contributor before submission.