7. May 2026

6. May 2026

5. May 2026

30. April 2026

29. April 2026

Combine Layers

Mans • Fix export crash when source layer contains components The CombineLayers filter's _prepareBShapes copied each shape from addLayer with s.copy() — when a shape was a GSComponent, this appended the component reference to the target layer. The OTF/Type1 writer doesn't implement addComponent:transformation:, so any such leftover component crashed the export with GSNotImplemented. Decompose the source layer first via copyDecomposedLayer(), which preserves the master/parent context (a plain layer.copy() + decomposeComponents() orphans the layer and yields zero paths). This fixes export of fonts that use a "shadow"-style master where composite glyphs (Aacute, aring, …) reference base letters via components. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

28. April 2026

27. April 2026

25. April 2026

Random Rotate

mekkablue • objc rewrite (no Python install necessary) commit 59b0e2671b0eb51793a58a20bde84b9048f3de4b Author: mekkablue <rainer@schriftlabor.at> Date: Mon Mar 30 15:01:11 2026 +0200 Rotate from center commit bb225d3f1bf3ee6cd7ea29d041b2a33123b14224 Author: mekkablue <rainer@schriftlabor.at> Date: Mon Mar 30 10:35:59 2026 +0200 gitignore for Xcode/objc commit aedba85cd981adeea1883eb52ef7db88c74ac42e Author: mekkablue <rainer@schriftlabor.at> Date: Mon Mar 30 09:28:37 2026 +0200 First working objc version commit d04238f68ee4cc1387bda32d937a0afacf592184 Author: Claude <noreply@anthropic.com> Date: Mon Mar 30 06:25:06 2026 +0000 Restructure: move Python plugin to python/, add ObjC Xcode project in objc/ - Moves RandomRotate.glyphsFilter → python/RandomRotate.glyphsFilter to preserve the existing Python plugin. - Adds objc/RandomRotate.xcodeproj (Xcode 16 bundle target) that builds RandomRotate.glyphsFilter directly into the repo root (CONFIGURATION_BUILD_DIR = $(SRCROOT)/..), mirroring the layout used by Risorizer, CutAndShake and PixelSlanter. - ObjC source files: RandomRotate.h/.m implementing GSFilterPlugin with ARC, -undefined dynamic_lookup linker flag, and FRAMEWORK_SEARCH_PATHS pointing at /Applications/Glyphs 3.app/Contents/Frameworks. - IBdialog.xib carries over the same "Max Angle" dialog from the Python version. - Post-build shell phase auto-installs the bundle into ~/Library/Application Support/Glyphs 3/Plugins after each build. https://claude.ai/code/session_01LyxSKe9GTbBDNBkFZCWGNX

24. April 2026

Cut and Shake

Claude • Remove becomeFirstResponder to eliminate focus-ring size illusion The macOS focus ring draws a blue glow 3-4 pt outside the first responder's frame, making it appear larger than the unfocused fields. Combined with "Number of Cuts" text nearly filling its 100 pt label column (leaving only the standard 8 pt gap before the field), the focused field looked visually larger even though all three frames are identical. Removing the call lets all three fields render with equal visual weight on open. https://claude.ai/code/session_01MURxLMimAN2ueWJe4mAWAh

Cut and Shake

mekkablue • Improved wording, fixed custom parameter commit b836a6bbd47580a7089293cf64f7607b4f11235d Author: mekkablue <rainer@schriftlabor.at> Date: Fri Apr 24 09:10:10 2026 +0200 Improved wording, fixed custom parameter commit de4db2772ebca935c19aea8d924054b8eda59ed4 Author: Claude <noreply@anthropic.com> Date: Fri Apr 24 05:57:29 2026 +0000 Fix export crash: layerForKey: → layerForId: (unrecognized selector) The forward-declared method was named layerForKey: but the actual GlyphsCore runtime method on GSGlyph is layerForId:. Calling the non-existent selector threw NSInvalidArgumentException during export, which Glyphs reported as "error with plugin Cut and Shake". Interactive use was unaffected because processFont:withArguments: (the only caller) is only invoked at export time. https://claude.ai/code/session_01MURxLMimAN2ueWJe4mAWAh commit 905ec8b0c35c523357fab7103f8fa2165542084b Author: Claude <noreply@anthropic.com> Date: Fri Apr 24 05:52:18 2026 +0000 Fix unequal field widths by pinning all field leading edges to superview Labels with HHP=251 overrode the inter-sibling trailing-alignment constraints (c04/c05), causing MoveLabel/RotateLabel to use their shorter intrinsic widths and their fields to start further left than CutsField. Decouple fields from labels by pinning all three leading edges directly to RootView at x=128 (20 left-margin + 100 label-column + 8 gap), guaranteeing identical field positions and widths regardless of label content size. https://claude.ai/code/session_01MURxLMimAN2ueWJe4mAWAh commit 251624f518b5ec3814d434d7f18c2b488cc69628 Author: Claude <noreply@anthropic.com> Date: Thu Apr 23 20:25:49 2026 +0000 Redesign filter dialog: longer labels, shorter fields, label tooltips - Labels renamed: "Cuts" → "Number of Cuts", "Move" → "Max Move", "Rotate" → "Max Rotation" for clarity. - Label column widened to 100 pt (was 44 pt) to accommodate the longest label; c19 constraint updated accordingly. - Input fields narrowed to 62 pt (was 151 pt) — comfortably fits 4–5 figures at macOS system font while the dialog shrinks to 210 pt (was 239 pt). - All six labels and fields now carry matching tooltips so hovering anywhere on a row shows the parameter description. - Added missing placeholderString="" to RotateField for consistency with CutsField and MoveField. https://claude.ai/code/session_01MURxLMimAN2ueWJe4mAWAh commit 986a1bbe0d57698ed3eb90beadf73e318670988e Author: Claude <noreply@anthropic.com> Date: Thu Apr 23 20:16:43 2026 +0000 Fix build error: declare layerForKey: via category so compiler accepts it GSGlyph.h does not expose layerForKey: in the installed SDK headers, but the method exists at runtime. Added a local @interface category (same pattern already used for GlyphsToolOther cutPathsInLayer:) so the compiler accepts the call in processFont:withArguments:. https://claude.ai/code/session_01MURxLMimAN2ueWJe4mAWAh commit 82c1712d7ab40430b612d36e8e5e414825433ac4 Author: Claude <noreply@anthropic.com> Date: Thu Apr 23 17:19:38 2026 +0000 Fix three ObjC filter issues: angled cuts, custom parameter layer iteration, equal field widths - randomCutLayer: now gives each cut endpoint an independently-random Y (or X) coordinate, producing diagonal cuts that match the Python version instead of always-orthogonal horizontal/vertical cuts. - processFont:withArguments: switches from `glyph.layers` fast enumeration to the SDK-template pattern (fontMasterAtIndex: + layerForKey:), which reliably reaches master layers during export and avoids issues with Glyphs' custom ordered-dictionary collection. - IBdialog.xib gains an explicit width=44 constraint on CutsLabel, pinning the label column to a fixed size so all three input fields resolve to the same width under Auto Layout on every macOS version. https://claude.ai/code/session_01MURxLMimAN2ueWJe4mAWAh

Cut and Shake

Claude • Fix export crash: layerForKey: → layerForId: (unrecognized selector) The forward-declared method was named layerForKey: but the actual GlyphsCore runtime method on GSGlyph is layerForId:. Calling the non-existent selector threw NSInvalidArgumentException during export, which Glyphs reported as "error with plugin Cut and Shake". Interactive use was unaffected because processFont:withArguments: (the only caller) is only invoked at export time. https://claude.ai/code/session_01MURxLMimAN2ueWJe4mAWAh

Cut and Shake

Claude • Fix unequal field widths by pinning all field leading edges to superview Labels with HHP=251 overrode the inter-sibling trailing-alignment constraints (c04/c05), causing MoveLabel/RotateLabel to use their shorter intrinsic widths and their fields to start further left than CutsField. Decouple fields from labels by pinning all three leading edges directly to RootView at x=128 (20 left-margin + 100 label-column + 8 gap), guaranteeing identical field positions and widths regardless of label content size. https://claude.ai/code/session_01MURxLMimAN2ueWJe4mAWAh

23. April 2026

Cut and Shake

Claude • Redesign filter dialog: longer labels, shorter fields, label tooltips - Labels renamed: "Cuts" → "Number of Cuts", "Move" → "Max Move", "Rotate" → "Max Rotation" for clarity. - Label column widened to 100 pt (was 44 pt) to accommodate the longest label; c19 constraint updated accordingly. - Input fields narrowed to 62 pt (was 151 pt) — comfortably fits 4–5 figures at macOS system font while the dialog shrinks to 210 pt (was 239 pt). - All six labels and fields now carry matching tooltips so hovering anywhere on a row shows the parameter description. - Added missing placeholderString="" to RotateField for consistency with CutsField and MoveField. https://claude.ai/code/session_01MURxLMimAN2ueWJe4mAWAh

Cut and Shake

Claude • Fix build error: declare layerForKey: via category so compiler accepts it GSGlyph.h does not expose layerForKey: in the installed SDK headers, but the method exists at runtime. Added a local @interface category (same pattern already used for GlyphsToolOther cutPathsInLayer:) so the compiler accepts the call in processFont:withArguments:. https://claude.ai/code/session_01MURxLMimAN2ueWJe4mAWAh

Cut and Shake

Claude • Fix three ObjC filter issues: angled cuts, custom parameter layer iteration, equal field widths - randomCutLayer: now gives each cut endpoint an independently-random Y (or X) coordinate, producing diagonal cuts that match the Python version instead of always-orthogonal horizontal/vertical cuts. - processFont:withArguments: switches from `glyph.layers` fast enumeration to the SDK-template pattern (fontMasterAtIndex: + layerForKey:), which reliably reaches master layers during export and avoids issues with Glyphs' custom ordered-dictionary collection. - IBdialog.xib gains an explicit width=44 constraint on CutsLabel, pinning the label column to a fixed size so all three input fields resolve to the same width under Auto Layout on every macOS version. https://claude.ai/code/session_01MURxLMimAN2ueWJe4mAWAh

22. April 2026

21. April 2026

19. April 2026

18. April 2026

16. April 2026

14. April 2026

Subtractor

mekkablue • Merge branch 'claude/add-masked-components-checkbox-1vXJQ'

Subtractor

Claude • Remove stale subtract components before placing a new masked component When the mask option is active in Edit view, any components on the layer whose glyph name equals or starts with the subtract-shapes prefix are stripped before the new component is added. This prevents duplicate subtract components from accumulating across repeated filter runs. The tooltip on the 'Add as Masked Components' checkbox now documents this behaviour. https://claude.ai/code/session_0111BBtHhcwvQuhN1hEWCeWS

Subtractor

mekkablue • Version 1.0.2: "Added non-destructive mask option for Edit view."

Subtractor

Claude • Apply centering/rotation/offset transforms to masked components When 'Add as Masked Components' is active, the same Center Bounding Boxes, Random Rotate, and Random Offset settings now apply to the placed GSComponent via a computed affine transform matrix. The matrix is derived by composing the three operations—centering translation, rotation around the (possibly shifted) bbox pivot, and random offset—into a single (m11,m12,m21,m22,tX,tY) tuple that produces an algebraically identical result to what subtractFromLayer applies to paths. A new buildComponentTransform() helper encapsulates the derivation. https://claude.ai/code/session_0111BBtHhcwvQuhN1hEWCeWS