Skip to content

Add per-character text outline/stroke for text clips#190

Open
indie-rok wants to merge 4 commits into
palmier-io:mainfrom
indie-rok:feat/text-outline
Open

Add per-character text outline/stroke for text clips#190
indie-rok wants to merge 4 commits into
palmier-io:mainfrom
indie-rok:feat/text-outline

Conversation

@indie-rok

@indie-rok indie-rok commented Jun 26, 2026

Copy link
Copy Markdown

Summary

Adds a per-character text outline (stroke) to text clips — the classic TikTok/YouTube Shorts caption style with colored borders around each letter.

Changes

Model (TextStyle.swift, TextLayout.swift)

  • New TextStyle.Outline struct: enabled, color (RGBA, default black), width (canvas points, default 3)
  • Backward-compatible: tolerant decoder fills defaults for existing .palmier files
  • TextLayout.naturalSize accounts for outline width in bounding-box padding
  • Stroke rendered via NSAttributedString.Key.strokeColor + .strokeWidth (negative = fill + stroke)

Rendering (TextLayerController.swift)

  • When outline is enabled, text is pre-rendered into a CGImage via NSAttributedString.draw(in:)CGContext.makeImage()
  • Bypasses CATextLayer's native text rendering so AVVideoCompositionCoreAnimationTool composites stroke correctly during export

Inspector UI (TextTab.swift)

  • Outline toggle + color picker in Typography section
  • Outline Width scrubber (0.5–20 pt), visible when outline is enabled

MCP / Agent Tools

  • add_texts: outlineColor (hex), outlineWidth (canvas points) — setting either auto-enables outline
  • set_clip_properties: same params (text clips only)
  • add_captions: same params — captions can have outline too
  • outlineWidth parsed via dict.double() to handle MCP JSON integer/float coercion

Testing

  • swift build passes with zero new warnings
  • Verified outline renders in preview and exports correctly to MP4

Note

Low Risk
Localized text styling and rendering changes with tolerant project decode; export path adds a CGContext rasterization branch only when outline is enabled.

Overview
Adds per-character text outline/stroke on text clips (caption-style colored letter borders), wired through the model, preview/export, inspector, and agent tools.

TextStyle gains an Outline (enabled, color, width in canvas points) with backward-compatible decode. Stroke uses NSAttributedString stroke attributes; TextLayout.naturalSize pads the bbox when outline is on. TextLayerController rasterizes outlined text to a CGImage when enabled so export compositing matches preview (instead of relying on CATextLayer alone).

Inspector (TextTab) adds outline toggle/color and a width scrubber (0.5–20 pt) that refits the clip box.

Agent/MCP: outlineColor and outlineWidth on add_texts, set_clip_properties (text-only), and add_captions; either param enables outline. set_clip_properties treats outlineWidth-only updates as valid and refits on width changes.

Reviewed by Cursor Bugbot for commit b8d298a. Bugbot is set up for automated code reviews on this repo. Configure here.

indie-rok and others added 4 commits June 26, 2026 09:02
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b8d298a. Configure here.

debounceKey: "outlineColor",
setEnabled: { $0.outline.enabled = $1 },
setColor: { $0.outline.color = $1 }
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outline enable skips bbox refit

Medium Severity

Turning on outline (inspector toggle or set_clip_properties with only outlineColor) does not run fitTextClipToContent, unlike outline width changes. The clip box stays sized for fill-only text while outline mode rasterizes into that fixed CATextLayer bounds, so the stroke can be clipped in preview and export.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b8d298a. Configure here.

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