Skip to content

Editable text, stroke-level opacity, layered saves, and the App Framework window - #7

Merged
AllTerrainDeveloper merged 2 commits into
mainfrom
fix/editable-text-stroke-opacity-layered-saves
Sep 3, 2026
Merged

AllTerrainDeveloper merged 2 commits into
mainfrom
fix/editable-text-stroke-opacity-layered-saves

Conversation

@AllTerrainDeveloper

Copy link
Copy Markdown
Owner

Summary

Fixes three user-reported bugs and ports the window to OpenStation's App Framework.

  • Text can be edited after it is placed. A text layer kind keeps the words and style. Click text with the Text tool, double-click it with Transform, or press the T beside it in the Layers panel; the caret reopens over the glyphs. Emptying the text removes the layer. Changing colour, font or weight from the options bar restyles the caret live instead of committing it.
  • Brush and eraser opacity applies to the whole stroke. Dabs overlap at a fifth of the brush width, so per-dab opacity compounded a 20% eraser to 99% within a second. Dabs now go into a stroke buffer at full strength and the buffer is laid over a snapshot of the layer once at the stroke opacity (src/engine/renderer/stroke-buffer.ts).
  • Saved copies open again with their layers. Raster layers travel with the save as PNGs (uploads/allterrain-photo-editor/layers/<id>/), served back by GET lienzo/v1/media/<id>/layers/<layer>; text layers are redrawn from their words. Only a layer over the upload limit still flattens, and the banner says so. Layer files are removed with the attachment and on uninstall.
  • Layer opacity slider in the Layers panel for the active layer.
  • App Framework. The window is declared in apps/photo-editor/photo-editor.os.php; lienzo-app.js is the client view that hands the mounted root to the main bundle. Shells without the framework keep the direct registration.

Version bumped to 1.1.0 with changelog entries; README save section updated.

Test plan

  • npm run typecheck, npm test (457 vitest), npm run test:php (129 PHPUnit), phpcs clean
  • On the QA site: create text, double-click to retype, Bold and colour while typing keep the caret
  • Gradient layer + eraser at 20%: eyedropper shows one stroke lifts black from 10 to 31, two strokes compound to ~36%
  • Save with text + painted layer, open the saved copy: source pointer, recipe, layer PNG streamed at 200, all layers editable
  • Opacity slider fades the active layer and shows a percentage badge on the row

🤖 Generated with Claude Code

https://claude.ai/code/session_01RMcGRhTqbzL6BDQ1L5wbBZ

AllTerrainDeveloper and others added 2 commits September 3, 2026 19:55
…work window

Three bugs a user found, and the framework port that came with fixing them.

Text can be edited after it is placed. A text layer keeps the words and style
it was typed with, so clicking it with the Text tool, double-clicking it with
Transform, or pressing the T beside it in the Layers panel reopens the caret
over the glyphs. The layer hides while the caret is open, the first line stays
anchored when the words change, and the retyped layer arrives under a new id
so undo can still show the old rendering. Changing colour, font or weight from
the options bar restyles the caret live instead of committing it.

Brush and eraser opacity applies to the whole stroke. Dabs used to carry the
opacity themselves and overlap at a fifth of the brush width, so a 20% eraser
compounded to 99% within a second. Dabs now land at full strength in a stroke
buffer and the buffer is laid over a snapshot of the layer once, at the stroke
opacity, flushed once per pointer event. Undo captures reads from the snapshot
so it records the pixels as they were before the brush touched them.

Saved copies open again with their layers. Each raster layer travels with the
save as a PNG of its own, stored under uploads/allterrain-photo-editor/layers
and streamed back through a new REST route; text layers are redrawn from their
words. lienzo_recipe_is_reproducible() is told which layers were stored, so
only a layer over the upload limit still flattens the copy, and the banner
says so. Layer files go with the attachment and on uninstall.

Layers gain an Opacity slider for the active layer in the Layers panel.

The window is now declared to OpenStation's App Framework from
apps/photo-editor/photo-editor.os.php with a small client view bundle that
hands the mounted root to the main bundle; a shell without the framework still
gets the direct registration.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RMcGRhTqbzL6BDQ1L5wbBZ
The Retouching and Fill headings were the shell's <os-section>, a Preferences
page section with a full-size title and a boxed body, dropped between the
controls with nothing inside -- so each drew a large heading over a blank box.
They are the panel's own small uppercase subheadings now, and hold their
controls, so the gap is the section's own.

The changelog credits the WP103 channel for the feedback behind this release.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RMcGRhTqbzL6BDQ1L5wbBZ
@AllTerrainDeveloper
AllTerrainDeveloper merged commit d22bec8 into main Sep 3, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant