NOASSERTIONupdated 1mo ago
Let be the absolute plugin directory two levels above this SKILL.md. Resolve that path before running commands or opening shared references. When these instructions say swiftui-ctx, invoke /scripts/swiftui-ctx; do not assume the command is on PATH.
What can you do with Audit Swiftui Drawing Canvas?
name: audit-swiftui-drawing-canvas description: Audit macOS SwiftUI drawing canvas for correctness, current APIs, and production conventions. Use for that domain or as part of a full audit.
Bundled resource root
Let <swiftui-plugin-root> be the absolute plugin directory two levels above this SKILL.md. Resolve that path before running commands or opening shared references. When these instructions say swiftui-ctx, invoke <swiftui-plugin-root>/scripts/swiftui-ctx; do not assume the command is on PATH.
Audit SwiftUI Drawing & Canvas
AUDIT-ONLY Β· macOS-only Β· SwiftUI-only. Run this on a finished or in-progress macOS SwiftUI
project to detect β and where certain, fix β every way custom drawing goes wrong: dozens of stacked
Image/Shape views where one Canvas belongs, a hand-rolled Timer driving a redraw that
TimelineView does for free, GeometryReader abused as a layout container, absolute hard-coded frames
where containerRelativeFrame/MeshGradient fit, broken Path math, expensive static vector art with
no .drawingGroup(), an ungated MeshGradient below the macOS 15 floor, and a Canvas invisible to
VoiceOver. Findings are written to disk in the toolkit's unified schema; certain mechanical defects are
fixed under the fix-safety protocol. This is never a from-scratch drawing generator.
These APIs are mostly long-stable (macOS 12/10.15), so the failure mode is misuse, not
hallucination β the wrong tool, the wrong layer, an ungated MeshGradient. Judge architecture, not
just names.
Boundary / seam note (stay in lane)
- The
Layoutprotocol itself belongs toaudit-swiftui-layout-and-tables. This skill flagsGeometryReader-as-layout (a drawing-geometry smell) and routes the custom-Layoutdecision there with across_ref; it does not auditLayoutconformance mechanics.GeometryReaderthat feeds drawing geometry (aCanvas/Pathsize) stays here. - Swift
Chartand chart-shaped data viz belong toaudit-swiftui-chartsβ except a hand-rolled, non-Chartdrawing of data, which stays here. If audited code reaches forChart, note it in one line and defer. - Cost measurement / profiling belongs to
audit-swiftui-view-performance. This skill owns the.drawingGroup()usage decision (should it be there at all); the render-cost number is theirs β emit across_refon the shared site. - The
Canvas/drawing accessibility descriptor is a keep-both seam withaudit-swiftui-accessibility(intentional double-detection per both plans): file the finding here AND cross-link; do not collapse. withAnimationtiming of a drawing belongs toaudit-swiftui-animation-motion(TimelineView-as- clock is theirs at the seam) β flag the missingTimelineViewhere, route motion-curve choices there.
The three drawing-architecture rules
- One
Canvasbeats a pile of views. Many siblingImage/Shape/Pathviews drawing one scene each become their own layout node + render pass;Canvas { ctx, size in β¦ }draws them all in one immediate-mode pass. Use a view per interactive/identity element; useCanvasfor bulk static art. - Time drives redraw through
TimelineView, never aTimer+@State. ATimermutating@Stateto re-render is a manual render loop SwiftUI already owns;TimelineView(.animation) { context in β¦ }(or.periodic/.explicit) hands you acontext.dateand redraws on the schedule, vsync-aligned. - Geometry feeds drawing; it does not arrange views.
GeometryReaderto read a size intoCanvasmath is correct;GeometryReaderwrapping children to position them is a layout job β theLayoutprotocol /containerRelativeFrame(route to layout-and-tables). Absolute hard-coded frames don't survive resize on a free Mac window.
The Canvas test: is the element interactive or independently identified (its own gesture, its own
a11y node, its own animation)? β keep it a view. Is it bulk static or procedurally-drawn paint? β
Canvas. Full reasoning + the redraw-source map: references/canvas-and-redraw.md.
Defect index (draw-01 β¦ draw-12)
id Β· tell Β· severity Β· fix Β· open reference. Severities: hard-fail (build break / ungated below
floor), warning (compiles but non-native / wrong tool), advisory (judgment / perf). auto =
mechanical single-answer fix; flag = show the β
, dev applies.
| id | One-line tell | Sev | Fix | Reference |
|---|---|---|---|---|
| draw-01 | many sibling Image/Shape/Path views drawing one static scene where one Canvas fits |
advisory | flag | canvas-and-redraw.md |
| draw-02 | Timer/Timer.publish/Date() + @State driving a periodic redraw instead of TimelineView |
warning | flag | canvas-and-redraw.md |
| draw-03 | GeometryReader wrapping children to arrange them (layout, not drawing geometry) |
warning | flag | geometry-and-frames.md |
| draw-04 | absolute hard-coded .frame(width:height:) / .position(x:y:) for a resizable drawing surface |
advisory | flag | geometry-and-frames.md |
| draw-05 | MeshGradient ungated under a deployment target < macOS 15 |
warning | flag | geometry-and-frames.md |
| draw-06 | MeshGradient(width:height:β¦) where points/colors count β width*height (mesh-arity) |
warning | flag | geometry-and-frames.md |
| draw-07 | Path math smell β unbalanced move(to:)/addLine, no closeSubpath(), magic-number control points |
advisory | flag | path-and-shapes.md |
| draw-08 | hand-rolled Path/Shape for a primitive that Circle/Ellipse/RoundedRectangle/Capsule already is |
advisory | flag | path-and-shapes.md |
| draw-09 | expensive static vector art (large Path/many shapes, no animation) with no .drawingGroup() |
advisory | flag | canvas-and-redraw.md |
| draw-10 | .drawingGroup() on a tiny/animated/text subtree (misapplied β flattens, breaks text/blends) |
advisory | flag | canvas-and-redraw.md |
| draw-11 | Canvas/hand-drawn data viz with no .accessibilityLabel/accessibilityChartDescriptor (a11y) |
advisory | flag | path-and-shapes.md |
| draw-12 | #available(iOS 15, *) gating MeshGradient in a macOS target (wrong arm) |
hard-fail | auto | geometry-and-frames.md |
Two claims are UNVERIFIED β carry as advisory with the flag, never assert as fact (each flagged in
its reference + becomes source: verify against Xcode 26 SDK): whether .drawingGroup() on a
text-bearing subtree drops the text rasterization fidelity (draw-10); whether a MeshGradient arity
mismatch is a compile error vs a runtime no-op on macOS 15+ (draw-06 β flag, don't assert a crash).
The real API, at a glance
Real (exist on macOS): Canvas(opaque:colorMode:rendersAsynchronously:renderer:) (12.0+),
GraphicsContext, TimelineView + .animation/.periodic/.explicit schedules (12.0+), Path +
move(to:)/addLine(to:)/addCurve/addArc/closeSubpath() (10.15+), Circle/Ellipse/Rectangle/
RoundedRectangle/Capsule shapes (10.15+), Gradient/LinearGradient/RadialGradient/AngularGradient
(10.15+), MeshGradient(width:height:points:colors:) (15.0+), .drawingGroup() (10.15+),
containerRelativeFrame(_:alignment:) (14.0+). All long-stable except MeshGradient (the one gating
concern). MeshGradient is macOS 15.0+ β never flag it as invented; flag it only when ungated below a
<15 floor.
Hallucinated (do not invent): there is no Canvas2D, no .canvasRenderer, no MeshGradientView,
no DrawingContext (the type is GraphicsContext). When unsure a symbol exists, VERIFY (a swiftui-ctx lookup exit-3 + Sosumi index-absence = hallucinated). Signatures, floors, and the full βββ
rewrites:
the routed references/*.md. Floor values are the reconciled truth in
<swiftui-plugin-root>/references/_shared/floors-master.md and the canonical invented-name list in
<swiftui-plugin-root>/references/_shared/hallucination-blacklist.md β read, never restate them.
The 8-step audit workflow (execute verbatim)
- ORIENT.
tree/findthe SwiftUI sources. Read the deployment target (project.pbxprojMACOSX_DEPLOYMENT_TARGET, orPackage.swiftplatforms:). It is load-bearing: draw-05/draw-12 fire only when the floor is below macOS 15 (theMeshGradientfloor). Record it. - LOCATE. Run the shared hybrid lint runner:
bash <swiftui-plugin-root>/scripts/swiftui-lint.sh --skill audit-swiftui-drawing-canvas --dir <sources> --json /tmp/draw.json --sarif /tmp/draw.sarif. It runs this skill's tier-1 grep tells (lint/grep-tells.tsv) + tier-2 structural ast-grep rules (lint/ast-grep/*.ymlβ theMeshGradient-not-gated,GeometryReader-arranges-children, andTimer-redraw-loop rules grep can't express), plus a per-file parse probe, and emits unified JSON + SARIF. Read itsparse_warningsβ a flagged file did not fully parse, so a structural miss can't masquerade as clean; READ those by hand. The runner only LOCATES β never treat a hit as a finding. Engine + rule-file format + degradation:<swiftui-plugin-root>/references/_shared/lint-architecture.md. - READ. Open every located file in full β never pattern-match-and-patch blind. View-vs-
Canvaschoice, the redraw source, gate scope, and whether aGeometryReaderarranges or measures are all invisible to grep. Build a per-file inventory: each drawing surface + its redraw source (static / time / state) + the Canvas test verdict + its gate (ifMeshGradient). - DETECT. Apply the index. Assign each candidate a confidence; report a finding only at 100%
certainty (e.g. an ungated
MeshGradientunder a <15 floor, aniOSgate arm, aTimer+@Stateredraw loop aTimelineViewreplaces). - VERIFY. For anything β€ ~70% confidence (a symbol you're unsure exists, a floor you can't place, an
arity or behavior claim), run both evidence sources. (a) Practice β
bash <swiftui-plugin-root>/scripts/swiftui-ctx lookup <api> --json(andswiftui-ctx deprecated <api>for a currency rule): read itsconsensus(the canonical shape β e.g.Canvasis{ }at 90%,TimelineViewis(_)at 99%,MeshGradientis(width, height, points, colors)at 70%),deprecated+replacement,recommendedpermalink,introduced_macos, andco_occurs_with; alookupexit 3 (not-found, with a did-you-meansuggestion) corroborates a hallucination finding. (b) Spec β confirm via Sosumi:curl -sSL https://sosumi.ai/<apple-path>usingreferences/source-directory.mdfor the path and<swiftui-plugin-root>/references/_shared/sosumi-reference.mdfor the protocol (neverWebFetchdeveloper.apple.com). Cross-checkintroduced_macosagainstfloors-master.mdand the Sosumidoc:floor (MeshGradient= macOS 15.0). The CLI contract is<swiftui-plugin-root>/references/_shared/swiftui-ctx-reference.md. Promote with the citation or discard. Carry the two UNVERIFIED items asadvisorywithsource: verify against Xcode 26 SDK. Deeper corpus evidence (custom-style): before flagging draw-07/draw-08 (a hand-rolledPath/Shape) or routing a customLayout(draw-03), prove the real idiom βbash <swiftui-plugin-root>/scripts/swiftui-ctx conformances Shape --json(313 repos conform; e.g.LineShapeatRepo-Radar/AnalyticsCharts.swift#L223) andconformances Layout(198 repos) give a permalinked custom conformer for## Source;bash <swiftui-plugin-root>/scripts/swiftui-ctx examples Canvas --shape "( )" --jsongives a realCanvascall site for the draw-01 consolidation β . - REPORT. Write each confirmed finding (output contract below). One finding per file, zero-padded,
ordered. Write the run's
_index.md. - FIX. Apply corrections under the fix-safety protocol
(
<swiftui-plugin-root>/references/_shared/fix-safety-protocol.md): clean-tree gate, findings-first, onlyfix_mode: auto(draw-12 wrong-arm), one conventional commit per finding citing itsrule_id, never weaken a check. The β "Correct" is not a hand-written snippet β it is the swiftui-ctx consensus shape put in## Correct, backed by a real macOS example fetched withbash <swiftui-plugin-root>/scripts/swiftui-ctx file <recommended.id> --smartwhose GitHub permalink (plus the Sosumidoc:) goes in## Sourceas the canonical example. Leaveflag-onlyfindingsopenwith that β in## Correct. - DOUBLE-CHECK. Re-grep each fixed file to confirm the tell no longer matches; record the evidence
in
## Fix applied?. Re-confirm every citation still resolves and still says its floor. If a fix introduced a new tell (e.g. aMeshGradientyou added now needs a macOS-15 gate), loop that file back to DETECT.
Confidence gating (load-bearing)
Report a finding only at 100% certainty. Anything β€ ~70% goes to VERIFY (step 5) before it can
become a finding β never emit a speculative finding. Auto-fix only the mechanical set (draw-12 wrong-arm
gate); everything else is fix_mode: flag-only (architecture and judgment calls need a human).
Output contract
Inherits the toolkit's unified contract (full schema + body sections + frontmatter keys:
<swiftui-plugin-root>/references/_shared/finding-schema.md β do not restate it). Specialized for this
domain:
- Findings:
swiftui-audits/drawing-canvas/<context>/NN-slug.md(one finding per file, zero-padded, ordered). Per-run index:swiftui-audits/drawing-canvas/_index.md. domain: drawing-canvas. Frontmatter is the canonical schema;fix_modeisautofor draw-12, elseflag-only.availabilityreads fromfloors-master.md(MeshGradient= macOS 15.0+).sourceis an Apple URL + access date (fetched via Sosumi) orverify against Xcode 26 SDK. Emitcross_refon the seam findings (draw-03 βlayout-and-tables; draw-09/draw-10 βview-performance; draw-11 βaccessibility).
Starter <context> folders (file here whenβ¦):
<context> |
File a finding here when⦠|
|---|---|
canvas-consolidation/ |
a pile of Image/Shape/Path views should collapse to one Canvas (draw-01) |
redraw-source/ |
a Timer+@State redraw loop should be a TimelineView (draw-02) |
geometry-as-layout/ |
GeometryReader arranges children instead of feeding drawing geometry (draw-03) β cross_ref layout-and-tables |
absolute-frames/ |
hard-coded .frame/.position for a resizable drawing surface (draw-04) |
availability-gating/ |
MeshGradient ungated under a <15 floor, or gated on the iOS arm (draw-05, draw-12) |
mesh-gradient/ |
a MeshGradient points/colors arity mismatch (draw-06) |
path-math/ |
unbalanced/closed Path math, or a hand-rolled primitive a built-in shape covers (draw-07, draw-08) |
drawing-group/ |
expensive static art missing .drawingGroup(), or .drawingGroup() misapplied (draw-09, draw-10) β cross_ref view-performance |
accessibility/ |
a Canvas/hand-drawn data viz with no a11y descriptor (draw-11) β cross_ref accessibility (keep-both) |
New-folder rule: if a finding does not fit any existing context folder, create a new one under
swiftui-audits/drawing-canvas/ with a lowercase-hyphen slug naming the sub-category, and note it in the
run's _index.md. Prefer an existing folder when the fit is reasonable; consistency across runs is a
hard requirement. Two runs over the same code produce structurally identical trees.
Go-beyond artifact (optional):
swiftui-audits/drawing-canvas/_redraw-map.mdclassifying every drawing surface asstatic/time-driven/state-drivenwith a view-vs-Canvasverdict β seereferences/canvas-and-redraw.md.
Reference routing
| File | Open when |
|---|---|
references/canvas-and-redraw.md |
view-vs-Canvas choice, the TimerβTimelineView redraw fix, the .drawingGroup() usage/misuse decision, the redraw map (draw-01/02/09/10) |
references/geometry-and-frames.md |
GeometryReader-as-layout, absolute frames vs containerRelativeFrame, MeshGradient gating + the wrong-arm trap + mesh arity (draw-03/04/05/06/12) |
references/path-and-shapes.md |
Path math correctness, hand-rolled-vs-built-in shapes, drawing accessibility (draw-07/08/11) |
references/source-directory.md |
step VERIFY β the Apple/WWDC/practitioner source map fetched via Sosumi |
lint/grep-tells.tsv + lint/ast-grep/*.yml |
step LOCATE β this skill's declarative lint rule set fed to the shared runner (tier-1 grep tells + tier-2 structural ast-grep); edit here to tune detection |
Shared toolkit references (point in, never restate):
| Shared file | For |
|---|---|
<swiftui-plugin-root>/references/_shared/floors-master.md |
every floor/availability value (the reconciled truth β MeshGradient = macOS 15.0) |
<swiftui-plugin-root>/references/_shared/hallucination-blacklist.md |
the canonical invented-name list |
<swiftui-plugin-root>/references/_shared/macos-arm-gating.md |
the macOS-arm gating rule + wrong-arm failure (draw-12) |
<swiftui-plugin-root>/references/_shared/finding-schema.md |
the unified finding schema + frontmatter keys |
<swiftui-plugin-root>/references/_shared/fix-safety-protocol.md |
the 8-point fix-safety protocol (step 7) |
<swiftui-plugin-root>/references/_shared/sosumi-reference.md |
the Apple-doc spec fetch protocol (step 5 VERIFY) |
<swiftui-plugin-root>/references/_shared/swiftui-ctx-reference.md |
the practice-corpus CLI contract β lookup/deprecated/file --smart for the consensus shape + permalinked example (steps 5 VERIFY Β· 7 FIX) |
<swiftui-plugin-root>/references/_shared/cross-ref-graph.md |
seam ownership + cross_ref targets (layout-and-tables, view-performance, accessibility, animation-motion, charts) |
Detection accelerator
bash <swiftui-plugin-root>/scripts/swiftui-lint.sh --skill audit-swiftui-drawing-canvas --dir <files-or-dir> [--json out.json] [--sarif out.sarif] β the toolkit's one shared hybrid lint engine, fed this
skill's declarative rules: tier-1 grep tells (lint/grep-tells.tsv,
draw-01/02/04/05/06/07/08/09/10/11/12) + tier-2 ast-grep structural rules (lint/ast-grep/*.yml β
draw-05 MeshGradient-not-gated, draw-03 GeometryReader-arranges-children, draw-02 Timer-redraw-loop)
that grep cannot express. It runs a per-file parse probe (surfaces "did not fully parse" so a
structural miss can't look clean), emits unified JSON + SARIF, emits warnings/advisories only
(no hard-fail tells β nothing blocks the gate), and degrades to grep-only with a notice if ast-grep is unreachable
(npx --package @ast-grep/cli ast-grep; faster: brew install ast-grep). It only LOCATES β always READ
each hit in full before reporting (step 3). The legacy scripts/draw-lint.sh is a thin pointer to this
runner. Engine + rule-file format + JSON/SARIF shape + safety rails:
<swiftui-plugin-root>/references/_shared/lint-architecture.md.
Install
Add Audit Swiftui Drawing Canvas to your client. Pick the one you use.
npx skills add yigitkonur/plugin-swiftuiInstalls every skill in the repository, then prompts for which to keep.
/plugin marketplace add yigitkonur/plugin-swiftuiAdds the repository as a plugin marketplace; install individual plugins with `/plugin install`.
git clone https://github.com/yigitkonur/plugin-swiftui
cp -r plugins/swiftui/skills/audit-swiftui-drawing-canvas ~/.claude/skills/A skill is a plain directory. Copy it into `.claude/skills/` in a project or in your home directory.
Score
68 / 100
Good