Skip to content

Release 1.8.0: complete artwork, per-side VoiceOver, Swift 6, CI and snapshot tests - #6

Merged
melihcolpan merged 7 commits into
mainfrom
release/1.8.0
Oct 8, 2026
Merged

melihcolpan merged 7 commits into
mainfrom
release/1.8.0

Conversation

@melihcolpan

Copy link
Copy Markdown
Owner

Summary

Every muscle is now drawn in at least one view, the package builds cleanly in the Swift 6 language mode, VoiceOver exposes paired muscles per side, and the repository gets CI with snapshot tests.

Artwork

  • New regions: .rearDeltoid, .upperTrapezius and .lowerTrapezius are drawn on both back views, and .upperTrapezius on the front views. They follow the parent muscle's own outline, replacing the small circular placeholders that were removed earlier. Like the other non-visible sub-groups, they are drawn with .showSubGroups().
  • Female back ankles: the female back view had a single heel shape tagged as feet, so .ankles painted nothing there. Its upper part is now the always-visible ankles sub-group.
  • Female back head: not drawn, because the hair covers it completely; isDrawable reports this.
  • Existing apps: unhighlighted bodies and heatmaps render the same as in 1.7.1. On the female back the ankle edges differ by at most 2/255 per channel.

VoiceOver

  • Per-side elements: muscles drawn on both sides now get one accessibility element per side ("Biceps, Left" / "Biceps, Right"), read left then right. Before, a single element spanned both arms, so the middle of the chest announced "Biceps".
  • Actions: the activate and long-press actions report the element's side, matching what a touch on the same spot returns.
  • Translations: a new string was added in all 11 languages.

Performance

  • Parsing: each SVG path is now parsed once at unit scale and scaled per view size. The first draw at a new size drops from ~6.0 ms to ~2.9 ms for a front + back pair (release build).
  • Preloading: creating a BodyView starts parsing all four bodies in the background, and the new BodyView.preloadArtwork() lets apps start this at launch.
  • Cache: PathCache is now protected by OSAllocatedUnfairLock and is checked Sendable; it no longer uses @unchecked Sendable.

Swift 6

  • Manifest: a new Package@swift-6.0.swift uses the Swift 6 language mode. Package.swift stays on Swift 5.9 for older Xcode versions, and the podspec lists both versions.
  • Clean build: the library and the tests build without warnings in Swift 6 mode.

Repository

  • CI: GitHub Actions runs the tests, an iOS Simulator build of the library and of the demo app, and pod lib lint.
  • Snapshot tests: they compare all four bodies with reference images. Reintroducing the female back view box bug fixed in 1.6.4 makes them fail with 26 % of the pixels different.
  • Screenshots: Tools/ScreenshotGenerator renders the README screenshots from code. All body screenshots were regenerated, and two were added: back regions and the stepped heatmap.
  • Demo: the outdated Examples/ copy was removed, and the demo app's Sub-Groups tab now shows the back regions.
  • README: updated for all of the above.

Every Muscle case is now drawn in at least one view.

- upperTrapezius / lowerTrapezius: on the back views, the parts of the
  trapezius above and below the rhomboid band, clipped to the trapezius
  outline. On the front views the visible trapezius is the upper part, so
  upperTrapezius uses that shape.
- rearDeltoid: the deltoid as seen from behind, on both back views.
- These three were removed earlier because they were small circular
  placeholders; the new shapes follow the parent muscle's own outline.
  Like the other non-visible sub-groups they are only drawn with
  .showSubGroups().
- Female back ankles: the female back view had a single heel shape tagged
  as feet, so .ankles painted nothing there. Its upper part is now the
  always-visible ankles sub-group, slightly inset so the unhighlighted
  body looks the same as before.
- The female back view still has no head path: the hair covers it
  completely, so there is nothing visible to draw. isDrawable reports that.

Unhighlighted bodies and heatmaps on trapezius, deltoids, feet and upper
back render pixel-identical to 1.7.1 on three views; on the female back
the ankle edges differ by at most 2/255 per channel.
Path cache
- Parse every SVG path string once at unit scale and scale it per view size
  with an affine transform, instead of parsing again for every size. The
  first draw at a new size (rotation, split view, zoom) drops from ~6.0 ms
  to ~2.9 ms for a front + back pair in a release build; steady-state
  redraws are unchanged at ~2.2 ms.
- Parsed paths are kept for the life of the app (the artwork is a fixed set
  of strings); per-size copies are still cleared past 4096 entries.
- Protect the cache with OSAllocatedUnfairLock so PathCache is checked
  Sendable instead of @unchecked Sendable.

Preloading
- Creating a BodyView now starts parsing all four bodies in the background
  once per app run, and BodyView.preloadArtwork() lets apps start it at
  launch. After SwiftUI's own first-render setup, the first body draws in
  ~6.7 ms instead of ~8.1 ms.

Swift 6
- Add Package@swift-6.0.swift with the Swift 6 language mode, so projects
  on a Swift 6 toolchain build the package with full concurrency checking;
  Package.swift keeps Swift 5.9 for older Xcode versions. The podspec now
  lists both Swift versions.
- AnimatedBodyCanvas.animatableData is nonisolated, which Swift 6 requires
  for the Animatable conformance of a main-actor view.
- Test classes that create views run on the main actor.

The library and tests build without warnings in Swift 6 mode, all tests
pass with both manifests, and renders match 1.7.1 to within 1/255 per
channel.
Paired muscles were exposed as a single accessibility element whose frame
was the union of both sides, so the biceps element spanned the whole chest
and the midline between the arms announced "Biceps".

- Muscles drawn on both sides now get one element per side, labelled
  "Biceps, Left" / "Biceps, Right" and read left then right. Muscles drawn
  once (for example a single common path) keep one element.
- The activate and long-press actions report the element's side, matching
  what a touch on the same spot returns, instead of always .both.
- New "accessibility.muscleWithSide" string in all 11 languages, using the
  list separator of each script (、 in Japanese, , in Chinese, ، in Arabic)
  and keeping the muscle name and side as separate words so no language
  needs grammatical agreement.
- BodyRenderer gains boundingRect(for:muscleSide:in:) for per-side frames.
- Add Tools/ScreenshotGenerator, a small macOS tool that renders the README
  body screenshots with the library itself:
    swift run --package-path Tools/ScreenshotGenerator ScreenshotGenerator Screenshots
  Each screenshot is defined next to the code it illustrates, so they can
  be refreshed whenever the artwork or rendering changes.
- Regenerate the eleven body screenshots with it and add two new ones:
  back_regions (upper/lower trapezius, rhomboids, rear deltoid, rotator
  cuff) and heatmap_stepped (.workoutStepped now that the scale's own
  interpolation is honoured). The two app screenshots of the gradient and
  stepped heatmap demo are unchanged.
- Demo app: the Sub-Groups tab gains a "Back Regions" section with both
  back bodies and a legend, and shows which views the tapped muscle is
  drawn on.
- Remove Examples/MuscleMapDemo, an outdated copy of the demo without an
  Xcode project that was last updated for 1.4.0. Example/ is the
  maintained demo.
- README: document the new back regions, BodyView.preloadArtwork(), the
  per-side VoiceOver elements, Swift 6 support, and how to run the tests
  and regenerate the screenshots.
- GitHub Actions runs on every push to main and every pull request:
  swift test on macOS, an iOS Simulator build of the library and of the
  demo app, and pod lib lint.
- SnapshotTests render all four bodies, unhighlighted and with a heatmap,
  plus the back regions, and compare them with reference images in
  Tests/MuscleMapTests/__Snapshots__. A pixel counts as different above a
  per-channel tolerance and a snapshot fails above 0.2 % different pixels,
  so anti-aliasing differences between machines pass while artwork or
  layout regressions fail. Reintroducing the female back view box bug
  fixed in 1.6.4 makes 26 % of the pixels differ.
- Record new references after an intended change with
  MUSCLEMAP_RECORD_SNAPSHOTS=1 swift test --filter SnapshotTests. On CI,
  failing renders are uploaded as a build artifact.
- Bump the podspec and the SPM / CocoaPods install snippets to 1.8.0.
The first CI run failed the heatmap and back-region snapshots by 1-5 % of
pixels while the unhighlighted bodies matched exactly. The shapes were
identical; the system colors were not: SwiftUI's .red, .orange and .yellow
resolve to different values on macOS 15 (CI) and macOS 26 (where the
references were recorded), e.g. #FF5128 vs #FF5340.

Snapshots now highlight with fixed sRGB colors and a custom heatmap scale,
so they test geometry and layout independently of the OS color palette.
References re-recorded.
@melihcolpan
melihcolpan merged commit 624701d into main Oct 8, 2026
4 checks passed
@melihcolpan
melihcolpan deleted the release/1.8.0 branch October 8, 2026 01:40
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