From c932814166ad170dbab268b2dad2509f2439b5b2 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 3 Aug 2026 17:00:52 +0000 Subject: [PATCH] Brand mark: scallop ribbon shape, app icon in light / dark / tinted (#11) --- Marks.xcodeproj/project.pbxproj | 4 + .../AppIcon.appiconset/AppIcon-Dark.png | Bin 0 -> 14937 bytes .../AppIcon.appiconset/AppIcon-Tinted.png | Bin 0 -> 14158 bytes .../AppIcon.appiconset/AppIcon.png | Bin 9198 -> 13857 bytes .../AppIcon.appiconset/Contents.json | 24 + Marks/Views/Library/MarksMark.swift | 166 +++++++ docs/logo-c1-variants.html | 322 +++++++++++++ docs/logo-variants.html | 447 ++++++++++++++++++ scripts/appicon/appicon.html | 72 +++ scripts/appicon/generate.sh | 38 ++ 10 files changed, 1073 insertions(+) create mode 100644 Marks/Assets.xcassets/AppIcon.appiconset/AppIcon-Dark.png create mode 100644 Marks/Assets.xcassets/AppIcon.appiconset/AppIcon-Tinted.png create mode 100644 Marks/Views/Library/MarksMark.swift create mode 100644 docs/logo-c1-variants.html create mode 100644 docs/logo-variants.html create mode 100644 scripts/appicon/appicon.html create mode 100755 scripts/appicon/generate.sh diff --git a/Marks.xcodeproj/project.pbxproj b/Marks.xcodeproj/project.pbxproj index 9974c22..40ca20f 100644 --- a/Marks.xcodeproj/project.pbxproj +++ b/Marks.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 1F1CB72BBCFFB33B6533D5C9 /* LibraryListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E093C878E702891C64D21FD5 /* LibraryListRow.swift */; }; 212F713DCC289C48087B79AE /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB7728D15C17219ABFF3EFFE /* Log.swift */; }; 22C814FD55D29B88D227C987 /* SpotlightBookmarkSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41DDBB04346F3BF06DE233D2 /* SpotlightBookmarkSearch.swift */; }; + 2F80DFB7298B733965FE04F5 /* MarksMark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EC8E834AB663A823D77BCB1 /* MarksMark.swift */; }; 337E8272EEB3B10FD0868F76 /* IngestedSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DC9BBF1006495D75DE4A232 /* IngestedSource.swift */; }; 3528AF5CB690BBCCF337581B /* Bookmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CA428181B35885F7D9F4D55 /* Bookmark.swift */; }; 4153FBF538C1D3F4BC96E4C5 /* LibraryKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5C9BFD9C0DD3876CC32B3A /* LibraryKit.swift */; }; @@ -138,6 +139,7 @@ 23F172EC9977CD5C51B228B9 /* MarksWidget.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = MarksWidget.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 240DBB87940F8D255A812EB2 /* BookmarkActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkActions.swift; sourceTree = ""; }; 2526E22D8EC5453358F0FCF9 /* SpotlightRetrievalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpotlightRetrievalTests.swift; sourceTree = ""; }; + 3EC8E834AB663A823D77BCB1 /* MarksMark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarksMark.swift; sourceTree = ""; }; 41DDBB04346F3BF06DE233D2 /* SpotlightBookmarkSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpotlightBookmarkSearch.swift; sourceTree = ""; }; 47CB3AAED5B64809B06A9650 /* RecentPodcastsWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentPodcastsWidget.swift; sourceTree = ""; }; 49685B8F3FEC72E8CF75843E /* AnalyticsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsService.swift; sourceTree = ""; }; @@ -257,6 +259,7 @@ 1BF2B010DADCCFBC282D37F0 /* LibraryGridView.swift */, AA5C9BFD9C0DD3876CC32B3A /* LibraryKit.swift */, E093C878E702891C64D21FD5 /* LibraryListRow.swift */, + 3EC8E834AB663A823D77BCB1 /* MarksMark.swift */, ); path = Library; sourceTree = ""; @@ -600,6 +603,7 @@ 41F00F4E7FFC1C0ACF71E398 /* MarksApp.swift in Sources */, E10B0B4EC9580342830EC0D2 /* MarksAppIntents.swift in Sources */, 8BD3FA025C082654D55374A2 /* MarksAuth.swift in Sources */, + 2F80DFB7298B733965FE04F5 /* MarksMark.swift in Sources */, 14E1B3CE58D36BFF1A2199C1 /* OnboardingView.swift in Sources */, 773C174263D08416248D0675 /* PodcastGenerationManager.swift in Sources */, 0479C0AA16E3AFDBD4414AD0 /* PodcastIndex.swift in Sources */, diff --git a/Marks/Assets.xcassets/AppIcon.appiconset/AppIcon-Dark.png b/Marks/Assets.xcassets/AppIcon.appiconset/AppIcon-Dark.png new file mode 100644 index 0000000000000000000000000000000000000000..c964e63410b77709825b8abd252456e94e4399e4 GIT binary patch literal 14937 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 Yx|D(ueL9Z6C`k4*)^=8fC%y0dA7dElT>t<8 literal 0 HcmV?d00001 diff --git a/Marks/Assets.xcassets/AppIcon.appiconset/AppIcon-Tinted.png b/Marks/Assets.xcassets/AppIcon.appiconset/AppIcon-Tinted.png new file mode 100644 index 0000000000000000000000000000000000000000..d86980f21da0f2d911520d093ba891c9723b8ddf GIT binary patch literal 14158 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�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

$HH9XT-ua8$WUTsf= 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 diff --git a/Marks/Assets.xcassets/AppIcon.appiconset/Contents.json b/Marks/Assets.xcassets/AppIcon.appiconset/Contents.json index cefcc87..e02c1e5 100644 --- a/Marks/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Marks/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -5,6 +5,30 @@ "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "AppIcon-Dark.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "filename" : "AppIcon-Tinted.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" } ], "info" : { diff --git a/Marks/Views/Library/MarksMark.swift b/Marks/Views/Library/MarksMark.swift new file mode 100644 index 0000000..310d0a2 --- /dev/null +++ b/Marks/Views/Library/MarksMark.swift @@ -0,0 +1,166 @@ +import SwiftUI + +// MARK: - The mark +// +// One path, four tails. +// +// The brand mark is a single closed shape rather than a stack of separate +// ribbons, and that is the whole design decision. A logo gets tested in two +// places that have nothing to do with how it looks on a slide: at 16pt in a +// Spotlight result, and in iOS 26's tinted and monochrome icon modes, where the +// palette is thrown away and only the silhouette survives. Every arrangement of +// N separate ribbons collapses into a blob under both tests, because the shapes +// were only ever told apart by colour. A scalloped baseline is told apart by +// its outline, so it reads the same tinted, monochrome, and 16pt tall. +// +// Geometry is defined in a canonical 88 x 98 box and fitted to whatever rect it +// is handed, so the proportions can't drift with the container. + +struct ScallopMark: Shape { + /// Downward points along the baseline. Four is the drawn default: three + /// reads as a plain banner, and five starts to look like bunting. + var tails: Int = 4 + + /// How far the notches cut up from the baseline, as a fraction of height. + /// Shallower than this and the tails read as damage rather than intent. + var notchDepth: CGFloat = 16.0 / 98.0 + + /// Top-corner radius, as a fraction of width. + var capRadius: CGFloat = 10.0 / 88.0 + + /// Canonical proportions of the drawn mark. Everything else derives from + /// this, including the app icon artwork — see scripts/appicon. + static let aspectRatio: CGFloat = 88.0 / 98.0 + + func path(in rect: CGRect) -> Path { + // Fit the canonical box into `rect` without distorting it, so callers + // can hand this any frame and still get the drawn proportions. + let height = min(rect.height, rect.width / Self.aspectRatio) + let width = height * Self.aspectRatio + let minX = rect.midX - width / 2 + let minY = rect.midY - height / 2 + let maxX = minX + width + let maxY = minY + height + + let radius = min(capRadius * width, min(width, height) / 2) + let depth = notchDepth * height + let points = max(2, tails) + let step = width / CGFloat(points - 1) + + var path = Path() + path.move(to: CGPoint(x: minX + radius, y: minY)) + // Top edge, right cap, then straight down the right side. + path.addArc( + tangent1End: CGPoint(x: maxX, y: minY), + tangent2End: CGPoint(x: maxX, y: minY + radius), + radius: radius + ) + path.addLine(to: CGPoint(x: maxX, y: maxY)) + // The tails, cut right to left so the winding stays consistent with + // the caps above. + for i in 1.. MarksMark { + MarksMark(bands: [color]) + } + + var body: some View { + ScallopMark(tails: tails) + .fill(bandFill) + .aspectRatio(ScallopMark.aspectRatio, contentMode: .fit) + } + + /// Hard-stopped, not blended: the bands are three inks laid side by side, + /// not a gradient. Doubling the stop at each boundary is what kills the + /// ramp SwiftUI would otherwise interpolate. + private var bandFill: LinearGradient { + let stops = bands.enumerated().flatMap { index, color in + [ + Gradient.Stop(color: color, location: Double(index) / Double(bands.count)), + Gradient.Stop(color: color, location: Double(index + 1) / Double(bands.count)), + ] + } + return LinearGradient(stops: stops, startPoint: .leading, endPoint: .trailing) + } +} + +// MARK: - Previews + +#Preview("Size ladder") { + VStack(spacing: 28) { + HStack(alignment: .bottom, spacing: 22) { + ForEach([128, 64, 40, 24, 16], id: \.self) { size in + MarksMark().frame(height: CGFloat(size)) + } + } + // The test the shape was chosen to pass: no colour, same mark. + HStack(alignment: .bottom, spacing: 22) { + ForEach([128, 64, 40, 24, 16], id: \.self) { size in + MarksMark.monochrome().frame(height: CGFloat(size)) + } + } + HStack(spacing: 22) { + ForEach(3..<6) { tails in + MarksMark(tails: tails).frame(height: 72) + } + } + } + .padding(40) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Paper.sheet) +} + +#Preview("Lockup") { + HStack(spacing: 18) { + MarksMark().frame(height: 64) + VStack(alignment: .leading, spacing: 6) { + Text("Marks").font(.system(size: 46, design: .serif)) + Text("EVERYTHING YOU SAVED") + .font(PaperType.micro) + .tracking(3) + .foregroundStyle(Paper.tertiary) + } + } + .foregroundStyle(Paper.ink) + .padding(40) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Paper.sheet) +} diff --git a/docs/logo-c1-variants.html b/docs/logo-c1-variants.html new file mode 100644 index 0000000..277588c --- /dev/null +++ b/docs/logo-c1-variants.html @@ -0,0 +1,322 @@ + + + + +Marks — C1 development + + + + +

+

C1 — three ribbons, developed

+

C1 had the most robust silhouette of the seven and the least ownership: three bookmark ribbons is a shape any read-later app could reach for. Ownability is the thing to attack, so each variant below adds one specific idea — a rhythm, a structure, a colour rule — and the caption says whether it actually buys anything.

+
+ + + +
+ 01 +

Ten developments

+

Shown in the app's own palette (navy / vermilion / yellow from Paper.swatchPairs) rather than the reference cyan-violet, since that was the conclusion of the last sheet. The ownable? line is the honest verdict, not a summary.

+
+
+ +
+ 02 +

Palette

+

The three-swatch column is the interesting one. The app already hashes bookmarks into a twelve-swatch palette — a mark built from three of those swatches is describing the app's actual data model, which is ownership no competitor can copy without copying the system underneath it.

+
+
+ +
+ 03 +

Size ladder

+

128 / 64 / 40 / 24 / 16 px. C1's whole argument is that it survives this; the developments have to survive it too or they've bought ownership with legibility.

+
+
+ +
+ 04 +

App icon

+

Squircle at 118 and 58 px, mark at ~62% of the tile.

+
+
+
+ +
+ 05 +

Lockups

+
+
+ +
+ 06 +

Pattern

+

The test C1 is most likely to win: a repeating field is where a simple silhouette beats a clever one.

+
+
+ + + + + diff --git a/docs/logo-variants.html b/docs/logo-variants.html new file mode 100644 index 0000000..897627d --- /dev/null +++ b/docs/logo-variants.html @@ -0,0 +1,447 @@ + + + + +Marks — logo variants + + + + +
+

Marks — logo variants

+

Five geometries derived from the reference (letter + box files + bookmark ribbon), each drawn once and re-coloured through the app's existing Paper palette. Geometry lives in <symbol>; colour is injected with CSS custom properties, so any cell in the matrix is a real, buildable combination.

+
+ + + + + +
+ 01 +

Seven geometries

+

Shown in the reference palette (cyan #22C7F0 / violet #8B4DEE) with multiply overlap, so they're directly comparable to the original.

+
+ +
+
+

A1 · Binder-B

+

Faithful reconstruction. Ribbon stem carries the notch; three bars go wide / narrow / wide to make the B. Closest to the source.

+
+ +
+
+

A2 · Ribbon-B

+

Every terminal becomes a swallowtail. More internally consistent, but the bowls stop reading as bowls — the B gets weaker.

+
+ +
+
+

B1 · Slab-M, tailed

+

Retargeted to the app's actual name. A real M — counters are wedges, apex at the cap line — with a swallowtail on each of the three feet.

+
+ +
+
+

B2 · Slab-M, flat

+

Same letter, tails removed. Sturdier and more type-like, but only the rounded cap is left carrying the bookmark idea — probably too little.

+
+ +
+
+

B3 · Ribbon knockout

+

Single ribbon, letter knocked out. One colour, one shape — the only variant that's trivially correct in iOS 26 tinted and mono icon modes.

+
+ +
+
+

C1 · Three ribbons

+

Drops the letterform entirely. Stepped heights do the work. Most robust silhouette, least ownable — many apps could use this.

+
+ +
+
+

C2 · Monoline

+

Binder-B as strokes. Sits in the same register as the app's serif/paper styling instead of fighting it. Fails below ~28px.

+
+ +
+
+ + +
+ 02 +

Palette matrix

+

Each geometry through the reference palette and five pairs drawn from Paper.swatchPairs in LibraryKit.swift. The Dark column uses the palette's own dark-mode counterparts, not dimmed light values.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReferenceNavy + Verm.Ink + Verm.Yellow + Verm.Blue + ForestInk onlyDark
A1 Binder-B
A2 Ribbon-B
B1 Slab-M deep
B2 Slab-M shallow
B3 Knockout
C1 Three ribbons
C2 Monoline
+
+ + +
+ 03 +

Size ladder

+

128 / 64 / 40 / 24 / 16 px. 40px is the Settings-row and tab-bar size; 16px is the favicon / Spotlight-result size. Anything that turns to mush at 24 is a wordmark, not a mark.

+ +
+
A1 Binder-B
+
128
+
64
+
40
+
24
+
16
+
+ +
+
B1 Slab-M deep
+
128
+
64
+
40
+
24
+
16
+
+ +
+
B3 Knockout
+
128
+
64
+
40
+
24
+
16
+
+ +
+
C1 Three ribbons
+
128
+
64
+
40
+
24
+
16
+
+ +
+
C2 Monoline
+
128
+
64
+
40
+
24
+
16
+
+
+ + +
+ 04 +

App icon

+

iOS squircle at 120pt and 60pt. The mark is set at ~62% of the tile — Apple's grid wants generous margins, and every one of these was drawn edge-to-edge in its own box.

+
+
A1 · navy
+
B1 · yellow
+
B3 · ink
+
C1 · blue
+
A1 · dark
+
A1 · reference
+
+
+
60pt
+
60pt
+
60pt
+
60pt
+
60pt
+
60pt
+
+
+ + +
+ 05 +

Lockups

+

Wordmark set in the app's own voice — serif for the name, mono letterspaced for the descriptor — rather than the reference's geometric sans, which belongs to a different product.

+ +
+ +
Marks
Everything you saved
+
+ +
+ +
Marks
Everything you saved
+
+ +
+ +
Marks
Everything you saved
+
+ +
+ +
Marks
Everything you saved
+
+
+ + +
+ 06 +

Pattern test

+

The reference proves itself by tiling. Same test here — if the mark only works alone, it isn't a system.

+
+
+ + + + + diff --git a/scripts/appicon/appicon.html b/scripts/appicon/appicon.html new file mode 100644 index 0000000..aedd51e --- /dev/null +++ b/scripts/appicon/appicon.html @@ -0,0 +1,72 @@ + + + + + +Marks app icon + + + +
+ + + diff --git a/scripts/appicon/generate.sh b/scripts/appicon/generate.sh new file mode 100755 index 0000000..81906e2 --- /dev/null +++ b/scripts/appicon/generate.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Renders the three app-icon variants from appicon.html into the asset catalog. +# +# scripts/appicon/generate.sh +# +# Chrome is the rasteriser because it is the only thing on a stock Mac that +# renders SVG the same way the browser preview sheets in docs/ do. The PNGs it +# writes are build output — edit appicon.html, not them. +set -euo pipefail + +HERE="$(cd "$(dirname "$0")" && pwd)" +OUT="$HERE/../../Marks/Assets.xcassets/AppIcon.appiconset" +CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" + +[ -x "$CHROME" ] || { echo "Google Chrome not found at $CHROME" >&2; exit 1; } +command -v magick >/dev/null || { echo "ImageMagick (magick) not found" >&2; exit 1; } + +render() { + local variant=$1 name=$2 + "$CHROME" --headless=new --disable-gpu --hide-scrollbars \ + --default-background-color=00000000 \ + --screenshot="$OUT/$name" --window-size=1024,1024 \ + --virtual-time-budget=2000 \ + "file://$HERE/appicon.html?v=$variant" >/dev/null 2>&1 + echo " $name" +} + +echo "rendering app icon ->" +render light AppIcon.png +render dark AppIcon-Dark.png +render tinted AppIcon-Tinted.png + +# The light icon is the one shipped as the home-screen artwork, and iOS rejects +# an alpha channel there. The dark and tinted variants are composited by the +# system over a background it supplies, so they must keep theirs. +magick "$OUT/AppIcon.png" -background '#F8F5EF' -alpha remove -alpha off "$OUT/AppIcon.png" + +echo "done"