diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/00-design-tokens.html b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/00-design-tokens.html new file mode 100644 index 0000000..0d1176b --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/00-design-tokens.html @@ -0,0 +1,92 @@ + + + +Apple Settings - Design Tokens + +

Apple Settings · iOS

Figma SAJX6z3s8bHctuZyvOSN8i, 393pt mode. A two-tone chip is a token the dark frames redefine, light half on the left. The type ramp is labelled with its own shorthand; every row of it is a named style in the file. The caption under a chip is its light value; evidence for all 37 tokens, both themes, is on the next 2 boards.

Colour

--as-bg#F2F2F7
--as-card#FFFFFF
--as-black#000000
--as-white#FFFFFF
--as-sep#C7C7CC
--as-trackrgba(118,118,128,.1216)
--as-blurrgba(255,255,255,.698)
--as-ink#000000
--as-grey#8E8E93
--as-grey2#AFB0B4
--as-blue#007BFE
--as-green#31C859

Radius

phone
card
logo
pill

Type

Sign in to your iPhone400 13px/16px
Sign in to your iPhone400 17px/22px
Sign in to your iPhone590 17px/22px
Settings700 34px/41px

Metrics

--as-w: 393px
--as-h: 852px
--as-sb: 54px
--as-nav: 44px
--as-margin: 16px
--as-gutter: 20px
--as-logo: 29px
--as-rowgap: 35px
--as-toggle-w: 51px
--as-toggle-h: 31px
--as-knob: 27px
--as-home: 34px
--as-home-w: 140px
--as-island-w: 126px
--as-island-h: 37px
--as-hair: 0.33px
+ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/00b-evidence.html b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/00b-evidence.html new file mode 100644 index 0000000..ce1a498 --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/00b-evidence.html @@ -0,0 +1,92 @@ + + + +Apple Settings - Evidence 1/2 + +

Evidence 1/2

Token, then its light value and its dark override, then where the value came from. A token with no evidence is a guess.

--as-font -apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display","Helvetica Neue",Helvetica,Arial,sans-serif

every type style in the file is Font(family: "SF Pro"); this is the platform stack that resolves to it on macOS and iOS

--as-bg #F2F2F7 / #000000

Figma variable grouped-bg/primary-base: the ground a grouped list sits on

--as-card #FFFFFF / #1C1C1E

Figma variable bg/primary-elevated: every list card

--as-black #000000

Figma variable system/black: the Dynamic Island, one value in both themes (which is why the island is invisible on the dark boards)

--as-white #FFFFFF

Figma variable system/white: the toggle knob, light in both themes

--as-sep #C7C7CC / #464649

Figma variable system/grey3: row dividers and the nav rule

--as-track rgba(118,118,128,.1216) / rgba(118,118,128,.2392)

Figma variable fill/tertiary #7676801F / #7676803D: the off toggle track. Over the card it renders #EEEEEF / #313136, which is what ref-02 and ref-d02 sample at 2x

--as-blur rgba(255,255,255,.698) / rgba(40,40,42,.941)

Figma variable ui/background-blur #FFFFFFB2 / #28282AF0, behind Material Blur (BACKGROUND_BLUR radius 50). Over the page ground it renders #FBFBFC / #262627, which is what the Developer nav band samples at 2x

--as-ink #000000 / #FFFFFF

Figma variable label/primary: row labels, the large title, the clock, the home indicator

--as-grey #8E8E93

Figma variable system/grey: section headers and section help text, one value in both themes (confirmed on ref-d02)

--as-grey2 #AFB0B4 / #636366

Figma variable system/grey2: the sign-in avatar glyph

--as-blue #007BFE / #0385FF

Figma variable ui/accent: the sign-in link, the action rows, the checkmark

--as-green #31C859 / #2DD257

Figma variable system/green: the on toggle track

--as-r-phone 52px

the repo's frame convention, not a value in the file: its screens are square-cornered 393 x 852 artboards

--as-r-card 10px

Figma corner radius on every list card

--as-r-logo 6px

Figma corner radius on the 29pt app icon in a list row

--as-r-pill 100px

Figma corner radius on the Dynamic Island, the home indicator, the toggle and its knob

--as-t-r13 400 13px/16px var(--as-font)

Figma type style Regular/13pt; Uppercase/13pt is the same style with text-transform on top

--as-t-r17 400 17px/22px var(--as-font)

Figma type style Regular/17pt: every row label

--as-t-b17 590 17px/22px var(--as-font)

Figma type style SemiBold/17pt: the nav title and the status-bar clock

--as-t-b34 700 34px/41px var(--as-font)

Figma type style Bold/34pt: the large Settings title

+ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/00c-evidence.html b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/00c-evidence.html new file mode 100644 index 0000000..80fcf35 --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/00c-evidence.html @@ -0,0 +1,92 @@ + + + +Apple Settings - Evidence 2/2 + +

Evidence 2/2

Token, then its light value and its dark override, then where the value came from. A token with no evidence is a guess.

--as-w 393px

Figma variable screen/width in the 393 mode

--as-h 852px

Figma variable screen/height in the 393 mode

--as-sb 54px

node box of the Status Bar frame

--as-nav 44px

node box of Title and Actions, which is also the list row height and the tap target

--as-margin 16px

Figma variable listing/margin: the inset of every card from the frame

--as-gutter 20px

node box padding on Content inside a row, a section header and a card

--as-logo 29px

node box of the app icon in a list row

--as-rowgap 35px

gap on the Sections flex column: the space between two cards

--as-toggle-w 51px

node box of the Toggle component

--as-toggle-h 31px

node box of the Toggle component

--as-knob 27px

node box of the Knob: the 31pt toggle with its 2pt padding

--as-home 34px

node box of the Home Bar frame

--as-home-w 140px

Figma variable homebar/width in the 393 mode (it is 154 in the 430 mode)

--as-island-w 126px

node box of the Dynamic Island

--as-island-h 37px

node box of the Dynamic Island

--as-hair 0.33px

stroke weight on every divider and on the nav rule

+ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/01-settings.html b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/01-settings.html new file mode 100644 index 0000000..6f2611e --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/01-settings.html @@ -0,0 +1,144 @@ + + + +Apple Settings - Settings + +
1:47
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Settings
+
Sign in to your iPhoneSet up iCloud, the App Store, and more.
+ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/02-developer.html b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/02-developer.html new file mode 100644 index 0000000..50a30f6 --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/02-developer.html @@ -0,0 +1,130 @@ + + + +Apple Settings - Developer + +
Paired devices
Text
Removing trusted computers will delete all of the records of computers that you have paired with previously.
UI automation
Enable UI Automation
State restoration testing
Fast App Termination
Terminate instead of suspending apps when backgrounded to force apps to be relaunched when they are foregrounded.
Waltter testing
Additional Logging
Allow HTTP Services
Disable Rate Limiting
NFC Pass Key Optional
Media services testing
AirPlay Suggestions
+
Text
News testing
Reset Local Data on Next Launch
+ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/03-display-zoom.html b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/03-display-zoom.html new file mode 100644 index 0000000..5f15177 --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/03-display-zoom.html @@ -0,0 +1,128 @@ + + + +Apple Settings - Display Zoom + +
Larger Text
Default
+
+ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/PRD.md b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/PRD.md new file mode 100644 index 0000000..6ffcadd --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/PRD.md @@ -0,0 +1,40 @@ +# Apple Settings (iOS) + +> For anyone who needs to change how their iPhone behaves, Settings is the one list that holds every toggle and sub-page the OS exposes, from developer options to how large the display renders — so getting to the right control fast is the entire job. + +## Problem +Someone wants to change one specific thing about their phone — flip on a developer flag, make text bigger — and has to find it inside a long, nested list whose shape they don't fully know. + +## Users +- Primary: someone scanning the top-level list for a section. +- Secondary: a developer digging into Developer options. +- Secondary: someone adjusting Display Zoom for readability. + +## Value +Every setting reachable from one root list, organized into sections, with a search-free path down into a specific sub-page like Developer or Display Zoom. + +## Scope +**In:** the top-level Settings list, the Developer sub-page, the Display Zoom sub-page, each in light and dark. + +**Out:** the search bar's results, every other sub-page visible as a row but not opened (Wi-Fi, Notifications, and the rest), and applying a Display Zoom change — no before/after preview is shown. + +## Success +Someone scanning the root list finds the section they want without opening the wrong one first; Developer's toggles are legible enough to flip the right one; Display Zoom's choice reads clearly without the (unmocked) live preview. + +## Screens +| Screen | Purpose | States | +|---|---|---| +| Settings | Root, scrolling list of every settings section | loaded, scrolled to top (not mocked: search active, scrolled further) | +| Developer | Sub-page of developer-facing toggles and options | loaded, six sections (not mocked: a toggle mid-change) | +| Display Zoom | Sub-page for choosing display zoom level | loaded, options shown (not mocked: live before/after preview, selection confirmed) | + +Settings (root) → tap a row → pushes to a sub-page. Developer is one such push; Display Zoom is reached from Developer, per this board's own Back label. Back returns to the page above. + +## Open questions +- Whether Display Zoom sits under Developer, or the source file placed it there for convenience rather than matching iOS's real information architecture. +- What search from the root list does. + +## Riskiest assumptions +1. People can find Developer without knowing beforehand that it exists (it isn't visible by default on a real device). Cheapest test: card-sort — ask someone to find "developer options" starting from the root list alone. +2. Display Zoom's choice is understandable without the live preview the real page provides. Cheapest test: show the static board and ask what each option will do to their screen. +3. The root list's section grouping matches how people mentally sort settings. Cheapest test: give people the section names and ask them to group them their own way, compare to the shown order. diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/README.md b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/README.md new file mode 100644 index 0000000..aaf4d73 --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/README.md @@ -0,0 +1,182 @@ +# Apple Settings, iOS + +Three screens of the iOS Settings app, each in both appearances, rebuilt from +the Figma community file [Apple Settings · iOS][file], plus the token board +and the two evidence boards behind them. 9 boards, and 6 more that park the +file's own PNG export under each replica. + +The file ships every screen twice, at 430pt and at 393pt, light and dark. This +repo's frame is 393 × 852, so the 393 pair is what was measured. All six frames +live under [`2006:4741`][root], the file's "📱 Screens" board. + +| Board | Figma node, light | Figma node, dark | +| --- | --- | --- | +| `01-settings` | [`2006:4774`][n1] | [`2006:4775`][d1] | +| `02-developer` | [`2006:4813`][n2] | [`2006:4814`][d2] | +| `03-display-zoom` | [`2006:4825`][n3] | [`2006:4826`][d3] | + +## How close it lands + +Mean absolute delta against the file's own 2× PNG export, whole frame, phone +crop, in levels of 255: + +| Screen | light | dark | +| --- | --- | --- | +| Settings | 0.39 | 0.49 | +| Developer | 0.71 | 0.74 | +| Display Zoom | 0.15 | 0.28 | + +What is left is antialiasing, not geometry. + +## One generator, both appearances + +`gen.py` emits all 15 boards. Each screen is one builder called twice: +`fn()` is the light frame, `fn(dark=True)` adds `.dark` to the phone, which +redefines the nine variables the file redefines and nothing else. + +`TOKENS_SPEC` is the single source for the `:root` block, the `.dark` block, +the token board and the evidence boards, so a value cannot drift from the +evidence behind it. Values came from the file's published variables read with +`get_variable_defs` on a light frame and on a dark one, from its named type +styles, and from node boxes. The PNG exports were used to confirm them, to +read the strings a layer named "Text" does not give you, and to settle the two +values that are a translucent fill over a ground. + +## What the file said, and what the renders corrected + +**Two rows literally say "Text".** `Paired devices` and `Media services +testing` each hold an Action Row that was left on the component's unfilled +default, so the community file renders the word "Text" in accent blue where a +real Settings screen names an action. The clone rule is to transcribe the +reference, so the boards say "Text" too. This is the source's defect, not the +replica's. + +**"Waltter testing" is the file's typo**, transcribed as-is. It is the Wallet +section. + +**Both pushed screens hide their Back button.** `get_design_context` describes +a Back control on Developer (`chevron.left` + "Settings") and on Display Zoom +(`chevron.left` + "Developer"), plus a "Set" right action on Display Zoom. +Those are the component's layers; the instances switch them off. The file's own +SVG export of either frame contains neither, and neither does its PNG. Nothing +draws them, so nothing here does. That also disposed of the run's one open +value: the "Set" label is the file's only `label/tertiary` fill, which is not +a published variable and so had no dark counterpart to go and find. + +**The Settings list overflows its own frame, on purpose.** The Top frame is +976 tall inside an 852 frame: a scrolling list parked at the top. Siri & Search +is cut mid-row and Photos and Game Center never appear. All three are emitted +and the frame clips them, which is what the export shows. The same is true of +Developer's last section, `News testing`, which starts at y 879. + +**Chrome sets a glyph half a point low, but only from 17pt up.** Row labels, +the nav title, the sign-in link, the 34pt title and the status-bar clock all +want their measured Figma `top` minus 0.5. Put every one of them back on its +measured coordinate and the six boards go 1.39 / 1.82 / 0.41 / 1.40 / 1.72 / +0.54 instead of the table above, so the half point is worth more than +everything else on this screen put together. The 13pt strings do not want it: +shifting the section headers, the section help and the sign-in subtitle the +same way cost Developer 0.6 of a level back. Rects are never shifted. +`apple-calendar` found the same half point at 17pt. + +The clock was the one string here that did not get it. Its Figma top is 18.5, +this folder shipped it at 18.5, and it rendered half a point low in all six +boards; `apple-wallet` measured it and caught the miss. Every number in the +table above is with the corrected clock, which is worth 0.02 to 0.03 a board. +`apple-calendar` had the same miss and is fixed too. + +**Only one of the two nav bars has a material.** Developer's Page Title paints +`ui/background-blur` and a 0.33pt rule at its bottom edge; Display Zoom's +paints neither, so the grouped page ground runs straight up behind the clock. +Both are 98 tall. The material is a flat composite in the export — `#FBFBFC` +light, `#262627` dark — because the content below starts at y 120 and nothing +scrolls under it in these frames. + +**The Dynamic Island is `system/black` in both themes**, one variable, so on +the dark Settings and Display Zoom boards it is invisible against a black page. +It reappears on dark Developer, where the nav material lifts the ground to +`#262627` around it. That is the file's behaviour, not a bug in the replica. + +**Dark reuses the same app-icon art.** The dark Home frame returns 15 raw +images against 14 rows; all 14 are byte-identical to the light frame's, and +the fifteenth is a pink-stripe Figma placeholder on a hidden layer. So one +`assets/images/` set serves both boards. + +**There is no `letter-spacing` anywhere, on purpose.** The type styles carry +tracking (+0.40 at 34pt, −0.43 at 17, −0.08 at 13) but SF Pro applies it +through its optical size axis and Figma's own export shows none of it added. +Same finding as `apple-photos/README.md` and `apple-calendar/README.md`. + +## Details worth not re-deriving + +- **A divider starts where its row's content starts.** 64 from the card edge + on a row with a 29pt app icon (20 gutter + 29 icon + 15 gap), 20 on a row + without one. Both are in the export. +- **A section header sits 35 below the card above it**, the gap on the + Sections column, and 22 above its own card. Help text does not use that + gap: it hangs 6 under its card and the next header comes 20 under the help. + Both numbers are in `section()`, which is why the six Developer sections + are placed at absolute tops rather than stacked. +- **Section help wraps to exactly three lines** in both help blocks, at 13pt + in the 321pt content width. That is the wrap the export shows, and it falls + out of the measured width rather than being forced. +- **Accessory glyphs are placed at their own ink box, not centred.** + `chevron.right` and `checkmark` have different optical centres and Figma + sets each from its text box, so `gen.py` writes both measured rects. +- **The toggle knob carries two shadows**, `0 3px 8px rgba(0,0,0,.15)` and + `0 3px 1px rgba(0,0,0,.06)`, straight off the Figma effect list. +- **This file and `apple-calendar` draw the same Status Bar component.** The + three glyph ink rects agree to three decimal places, so `SB_ICONS` and + `cellular.svg` / `wifi.svg` / `battery.svg` were reused verbatim rather + than re-lifted. +- **Two tokens are alpha over a ground, and stay that way.** + `--as-track` (`fill/tertiary`) renders `#EEEEEF` / `#313136` over the + card and `--as-blur` (`ui/background-blur`) renders `#FBFBFC` / `#262627` + over the page. Both composites were sampled off the 2× exports to confirm + the alpha; the block keeps the alpha, not the composite. +- **`system/grey` is one value in both themes.** `#8E8E93` for section + headers and help text, confirmed on `ref-d02`. + +## Assets + +`assets/` holds what Figma exported, so the boards rebuild offline. + +- `icons/` — 6 SF Symbols, each one's `viewBox` **is** its ink box. Lifted + with `apple-calendar/iconkit.py`, which explains why a whole-node export is + the only one that outlines them. +- `images/` — the 14 app icons, the file's own art, downscaled to 87 px (3× + of the 29pt slot they render in) so a board carries 111 KB of base64 rather + than ten times that. +- `refs/` — the 6 PNG exports at 2×, 786 × 1704. **Gitignored**, along with + the `ref-*.html` boards built from them: they are whole Apple screens, not + component art. + +The artwork is Apple's, reproduced from the community file for design +reference. It is not licensed for redistribution as product artwork. + +## Regenerating + +```bash +python3 canvases/apple-settings/gen.py +``` + +Rebuilds every board and `layout.json` from `assets/`, byte-identical. The +boards are output: edit `gen.py`, never the HTML. Without `assets/refs/` it +skips the 6 reference boards and builds the other 9. + +Verify with: + +```bash +python3 tools/refkit.py tokens canvases/apple-settings +python3 tools/refkit.py shoot canvases/apple-settings/*.html \ + -o shots --scale 2 --check-overflow +``` + +[file]: https://www.figma.com/design/SAJX6z3s8bHctuZyvOSN8i/Apple-Settings-%C2%B7-iOS--Community- +[root]: https://www.figma.com/design/SAJX6z3s8bHctuZyvOSN8i/Apple-Settings-%C2%B7-iOS--Community-?node-id=2006-4741 +[n1]: https://www.figma.com/design/SAJX6z3s8bHctuZyvOSN8i/Apple-Settings-%C2%B7-iOS--Community-?node-id=2006-4774 +[d1]: https://www.figma.com/design/SAJX6z3s8bHctuZyvOSN8i/Apple-Settings-%C2%B7-iOS--Community-?node-id=2006-4775 +[n2]: https://www.figma.com/design/SAJX6z3s8bHctuZyvOSN8i/Apple-Settings-%C2%B7-iOS--Community-?node-id=2006-4813 +[d2]: https://www.figma.com/design/SAJX6z3s8bHctuZyvOSN8i/Apple-Settings-%C2%B7-iOS--Community-?node-id=2006-4814 +[n3]: https://www.figma.com/design/SAJX6z3s8bHctuZyvOSN8i/Apple-Settings-%C2%B7-iOS--Community-?node-id=2006-4825 +[d3]: https://www.figma.com/design/SAJX6z3s8bHctuZyvOSN8i/Apple-Settings-%C2%B7-iOS--Community-?node-id=2006-4826 diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/battery.svg b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/battery.svg new file mode 100644 index 0000000..7ab7b9c --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/battery.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/cellular.svg b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/cellular.svg new file mode 100644 index 0000000..0e4b839 --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/cellular.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/checkmark.svg b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/checkmark.svg new file mode 100644 index 0000000..37facac --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/checkmark.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/chevron-right.svg b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/chevron-right.svg new file mode 100644 index 0000000..efe4bda --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/chevron-right.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/person-crop-circle-fill.svg b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/person-crop-circle-fill.svg new file mode 100644 index 0000000..8127124 --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/person-crop-circle-fill.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/wifi.svg b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/wifi.svg new file mode 100644 index 0000000..ad20035 --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/icons/wifi.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/accessibility.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/accessibility.png new file mode 100644 index 0000000..018bbcc Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/accessibility.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/game-center.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/game-center.png new file mode 100644 index 0000000..7c186de Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/game-center.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/general.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/general.png new file mode 100644 index 0000000..2192c6d Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/general.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/health.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/health.png new file mode 100644 index 0000000..69913ac Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/health.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/maps.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/maps.png new file mode 100644 index 0000000..9c52f99 Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/maps.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/news.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/news.png new file mode 100644 index 0000000..2abf39d Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/news.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/passwords.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/passwords.png new file mode 100644 index 0000000..113badb Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/passwords.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/photos.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/photos.png new file mode 100644 index 0000000..93ea84e Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/photos.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/privacy.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/privacy.png new file mode 100644 index 0000000..1e4fc05 Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/privacy.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/safari.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/safari.png new file mode 100644 index 0000000..787c853 Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/safari.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/screen-time.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/screen-time.png new file mode 100644 index 0000000..1397089 Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/screen-time.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/shortcuts.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/shortcuts.png new file mode 100644 index 0000000..3393a59 Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/shortcuts.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/siri.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/siri.png new file mode 100644 index 0000000..43c7762 Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/siri.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/translate.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/translate.png new file mode 100644 index 0000000..a05ce32 Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/assets/images/translate.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/d01-settings.html b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/d01-settings.html new file mode 100644 index 0000000..36a2b22 --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/d01-settings.html @@ -0,0 +1,144 @@ + + + +Apple Settings - Settings (dark) + +
1:47
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Settings
+
Sign in to your iPhoneSet up iCloud, the App Store, and more.
+ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/d02-developer.html b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/d02-developer.html new file mode 100644 index 0000000..9d3b44c --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/d02-developer.html @@ -0,0 +1,130 @@ + + + +Apple Settings - Developer (dark) + +
Paired devices
Text
Removing trusted computers will delete all of the records of computers that you have paired with previously.
UI automation
Enable UI Automation
State restoration testing
Fast App Termination
Terminate instead of suspending apps when backgrounded to force apps to be relaunched when they are foregrounded.
Waltter testing
Additional Logging
Allow HTTP Services
Disable Rate Limiting
NFC Pass Key Optional
Media services testing
AirPlay Suggestions
+
Text
News testing
Reset Local Data on Next Launch
+ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/d03-display-zoom.html b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/d03-display-zoom.html new file mode 100644 index 0000000..3d22f2d --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/d03-display-zoom.html @@ -0,0 +1,128 @@ + + + +Apple Settings - Display Zoom (dark) + +
Larger Text
Default
+
+ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/gen.py b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/gen.py new file mode 100644 index 0000000..d19f43a --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/gen.py @@ -0,0 +1,573 @@ +"""Emit canvases/apple-settings/ from the Figma measurements. + +Source: the Figma community file "Apple Settings . iOS", SAJX6z3s8bHctuZyvOSN8i, +393pt mode (the file also ships a 430pt column; this repo's frame is 393). Node +ids per board are in README.md. + +Every number here came out of the file, not out of a screenshot: the published +variables for the palette and the metrics, the file's own type styles for the +ramp, and node boxes for the geometry. The PNG renders under assets/refs/ were +only used to confirm them and to settle the two composites the variables give +as alpha over an unnamed ground (the nav material and the toggle track). + +No letter-spacing anywhere, on purpose. The type styles carry tracking (-0.43 +at 17pt, -0.08 at 13pt and so on) but SF Pro already applies it through its +optical size axis, so Figma's own PNG export shows none of it on top. Same +finding as apple-photos/README.md and apple-calendar/gen.py record. + +Light and dark are one board each from one builder: .dark on the phone swaps +the nine variables the file redefines for its dark screens and nothing else. + +Artboards are output. Edit this file, never the HTML. + + python3 canvases/apple-settings/gen.py +""" +import base64 +import json +import os + +OUT = os.path.dirname(os.path.abspath(__file__)) +ASSETS = os.path.join(OUT, "assets") + + +def icon(name, style="", cls=""): + """Inline one glyph lifted by iconkit.py. Its viewBox IS its ink box, so a + left/top/width/height off the Figma frame places it exactly.""" + svg = open(os.path.join(ASSETS, "icons", name + ".svg"), encoding="utf-8").read() + return svg.replace(".png as a data: URI. The iframe is sandboxed, so a + board that wants a bitmap has to carry it. These are the file's own app + icons, downscaled to 87px (3x of the 29pt slot they render in).""" + with open(os.path.join(ASSETS, "images", name + ".png"), "rb") as f: + return "data:image/png;base64," + base64.b64encode(f.read()).decode() + + +# ---------------------------------------------------------------- tokens + +# (group, name, light, dark, evidence). One row per token, and the :root +# block, the .dark block, the token board and the evidence boards are all +# generated from it, so a value cannot drift from the evidence behind it. +# +# "Figma variable X" means the file's own published variable, read with +# get_variable_defs on a light frame and on a dark one; that is the primary +# source here, not a screenshot. Where a variable is an alpha fill the row +# keeps the alpha and says what it composites over, and the sample that +# confirms the composite. +TOKENS_SPEC = [ + ("", "font", + '-apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display",' + '"Helvetica Neue",Helvetica,Arial,sans-serif', "", + 'every type style in the file is Font(family: "SF Pro"); this is the ' + 'platform stack that resolves to it on macOS and iOS'), + + ("Surface", "bg", "#F2F2F7", "#000000", + "Figma variable grouped-bg/primary-base: the ground a grouped list sits on"), + ("Surface", "card", "#FFFFFF", "#1C1C1E", + "Figma variable bg/primary-elevated: every list card"), + ("Surface", "black", "#000000", "", + "Figma variable system/black: the Dynamic Island, one value in both themes " + "(which is why the island is invisible on the dark boards)"), + ("Surface", "white", "#FFFFFF", "", + "Figma variable system/white: the toggle knob, light in both themes"), + ("Surface", "sep", "#C7C7CC", "#464649", + "Figma variable system/grey3: row dividers and the nav rule"), + ("Surface", "track", "rgba(118,118,128,.1216)", "rgba(118,118,128,.2392)", + "Figma variable fill/tertiary #7676801F / #7676803D: the off toggle track. " + "Over the card it renders #EEEEEF / #313136, which is what ref-02 and " + "ref-d02 sample at 2x"), + ("Surface", "blur", "rgba(255,255,255,.698)", "rgba(40,40,42,.941)", + "Figma variable ui/background-blur #FFFFFFB2 / #28282AF0, behind Material " + "Blur (BACKGROUND_BLUR radius 50). Over the page ground it renders #FBFBFC " + "/ #262627, which is what the Developer nav band samples at 2x"), + + ("Ink", "ink", "#000000", "#FFFFFF", + "Figma variable label/primary: row labels, the large title, the clock, the " + "home indicator"), + ("Ink", "grey", "#8E8E93", "", + "Figma variable system/grey: section headers and section help text, one " + "value in both themes (confirmed on ref-d02)"), + ("Ink", "grey2", "#AFB0B4", "#636366", + "Figma variable system/grey2: the sign-in avatar glyph"), + ("Ink", "blue", "#007BFE", "#0385FF", + "Figma variable ui/accent: the sign-in link, the action rows, the checkmark"), + ("Ink", "green", "#31C859", "#2DD257", + "Figma variable system/green: the on toggle track"), + + ("Radius", "r-phone", "52px", "", + "the repo's frame convention, not a value in the file: its screens are " + "square-cornered 393 x 852 artboards"), + ("Radius", "r-card", "10px", "", + "Figma corner radius on every list card"), + ("Radius", "r-logo", "6px", "", + "Figma corner radius on the 29pt app icon in a list row"), + ("Radius", "r-pill", "100px", "", + "Figma corner radius on the Dynamic Island, the home indicator, the toggle " + "and its knob"), + + ("Type", "t-r13", "400 13px/16px var(--as-font)", "", + "Figma type style Regular/13pt; Uppercase/13pt is the same style with " + "text-transform on top"), + ("Type", "t-r17", "400 17px/22px var(--as-font)", "", + "Figma type style Regular/17pt: every row label"), + ("Type", "t-b17", "590 17px/22px var(--as-font)", "", + "Figma type style SemiBold/17pt: the nav title and the status-bar clock"), + ("Type", "t-b34", "700 34px/41px var(--as-font)", "", + "Figma type style Bold/34pt: the large Settings title"), + + ("Metrics", "w", "393px", "", "Figma variable screen/width in the 393 mode"), + ("Metrics", "h", "852px", "", "Figma variable screen/height in the 393 mode"), + ("Metrics", "sb", "54px", "", "node box of the Status Bar frame"), + ("Metrics", "nav", "44px", "", + "node box of Title and Actions, which is also the list row height and the " + "tap target"), + ("Metrics", "margin", "16px", "", + "Figma variable listing/margin: the inset of every card from the frame"), + ("Metrics", "gutter", "20px", "", + "node box padding on Content inside a row, a section header and a card"), + ("Metrics", "logo", "29px", "", "node box of the app icon in a list row"), + ("Metrics", "rowgap", "35px", "", + "gap on the Sections flex column: the space between two cards"), + ("Metrics", "toggle-w", "51px", "", "node box of the Toggle component"), + ("Metrics", "toggle-h", "31px", "", "node box of the Toggle component"), + ("Metrics", "knob", "27px", "", + "node box of the Knob: the 31pt toggle with its 2pt padding"), + ("Metrics", "home", "34px", "", "node box of the Home Bar frame"), + ("Metrics", "home-w", "140px", "", + "Figma variable homebar/width in the 393 mode (it is 154 in the 430 mode)"), + ("Metrics", "island-w", "126px", "", "node box of the Dynamic Island"), + ("Metrics", "island-h", "37px", "", "node box of the Dynamic Island"), + ("Metrics", "hair", "0.33px", "", + "stroke weight on every divider and on the nav rule"), +] + + +def _root(): + """One :root block, byte-identical in every board, and no `}` inside it: + tools/refkit.py reads it with a non-greedy regex.""" + out, seen = [":root{"], None + for group, name, value, _dark, _ev in TOKENS_SPEC: + if group and group != seen: + out.append("") + out.append(" /* %s */" % group) + seen = group + out.append(" --as-%s:%s;" % (name, value)) + return "\n".join(out) + "\n}" + + +def _dark(): + """Only what the file redefines. system/grey, system/black and system/white + are one variable in both themes, so they are not here.""" + return ".dark{\n%s\n}" % "\n".join( + " --as-%s:%s;" % (n, d) for _g, n, _v, d, _e in TOKENS_SPEC if d) + + +TOKENS = _root() +DARK = _dark() + +BASE = """*{box-sizing:border-box;margin:0;padding:0} +body{font-family:var(--as-font);-webkit-font-smoothing:antialiased;display:flex;justify-content:center;padding:24px}""" + +# translateZ(0) composites the frame itself. Safari on iPhone clips composited children (blur, +# backdrop-filter) of a non-composited ancestor with a plain rectangle, so the screen painted +# square past the bezel's corners; a composited frame clips them with its own rounded mask. +PHONE = """.phone{width:var(--as-w);height:var(--as-h);position:relative;flex:none;overflow:hidden;border-radius:var(--as-r-phone);background:var(--as-bg);color:var(--as-ink);transform:translateZ(0);outline:1px solid rgba(0,0,0,.10);box-shadow:0 0 0 11px #1D191A,0 0 0 12.5px #3A3735,0 24px 60px rgba(29,25,26,.28)} +.sb{position:absolute;left:0;right:0;top:0;height:var(--as-sb);z-index:8} +.sb .t{position:absolute;left:10px;top:18px;width:123.5px;height:22px;text-align:center;font:var(--as-t-b17)} +.sb .island{position:absolute;left:133.5px;top:11px;width:var(--as-island-w);height:var(--as-island-h);border-radius:var(--as-r-pill);background:var(--as-black)} +.sb svg{position:absolute;display:block} +.home{position:absolute;left:50%;bottom:8px;z-index:7;transform:translateX(-50%);width:var(--as-home-w);height:5px;border-radius:var(--as-r-pill);background:var(--as-ink)}""" + +# 393-mode Status Bar: px-10, two flex-1 sides around the 126px island, each +# side items-center with pt-18 pb-13. Each entry is the glyph's own ink rect in +# the 393 x 852 frame. This file and apple-calendar draw the same Status Bar +# component, down to three decimals, so these are its measurements verbatim. +SB_ICONS = [("cellular", 282.598, 22.109, 19.474, 12.531), + ("wifi", 309.076, 22.986, 16.621, 11.996), + ("battery", 332.946, 22.993, 26.824, 12.120)] + + +def statusbar(time="1:47"): + return ('
%s
%s
' + % (time, "".join(at(*i) for i in SB_ICONS))) + + +def home(): + return '
' + + +def phone(body, dark=False): + return '
%s
' % (" dark" if dark else "", body) + + +def page(title, css, body): + return """ + + +%s + +%s + +""" % (title, TOKENS, DARK, BASE, css, body) + + +# ------------------------------------------------- shared: the grouped list + +# Chrome sets a glyph half a point lower than Figma does inside the same line +# box, so every text top from 17pt up -- row labels, the nav title, the +# sign-in link, the 34pt page title, the status-bar clock -- is written as its +# measured Figma coordinate minus 0.5. The 13pt strings are not: the section +# headers, the section help and the sign-in subtitle land on their measured +# coordinate, and shifting them costs the Developer board 0.6 of a level. +# Rects are never shifted. Same finding as apple-calendar/README.md records. + + +# Every screen in this file is the same grouped list: cards inset 16 from the +# frame, 44pt rows inside them, a 0.33pt divider between rows that starts +# where the row's own content starts. A row with a 29pt app icon indents its +# label and its divider to 64 (20 gutter + 29 icon + 15 gap); a row without +# one indents both to 20. +LIST = PHONE + "\n" + """.card{position:absolute;left:var(--as-margin);width:361px;border-radius:var(--as-r-card);background:var(--as-card)} +.row{position:absolute;left:0;right:0;height:var(--as-nav)} +.row .lb{position:absolute;left:var(--as-gutter);top:10.5px;font:var(--as-t-r17);white-space:nowrap} +.row .lb.ac{color:var(--as-blue)} +.row .lg{position:absolute;left:var(--as-gutter);top:7.5px;width:var(--as-logo);height:var(--as-logo);border-radius:var(--as-r-logo);object-fit:cover;display:block} +.row .dv{position:absolute;left:var(--as-gutter);right:0;bottom:0;height:var(--as-hair);background:var(--as-sep)} +.row.logo .lb,.row.logo .dv{left:64px} +.row svg{position:absolute;display:block;color:var(--as-sep)} +.row svg.ck{color:var(--as-blue)} +.tg{position:absolute;right:var(--as-gutter);top:6.5px;width:var(--as-toggle-w);height:var(--as-toggle-h);border-radius:var(--as-r-pill);background:var(--as-track)} +.tg.on{background:var(--as-green)} +.tg i{position:absolute;left:2px;top:2px;width:var(--as-knob);height:var(--as-knob);border-radius:var(--as-r-pill);background:var(--as-white);box-shadow:0 3px 8px rgba(0,0,0,.15),0 3px 1px rgba(0,0,0,.06)} +.tg.on i{left:22px}""" + +# Both accessory glyphs sit at their own measured ink box inside the row, not +# centred by CSS: chevron.right and checkmark have different optical centres +# and Figma places each by its text box. +CHEVRON = at("chevron-right", 332.841, 15.426, 7.157, 12.277) +CHECK = at("checkmark", 321.925, 14.910, 14.950, 14.559, "ck") + + +def row(i, label, logo=None, accent=False, chevron=False, toggle=None, + check=False, divider=False): + p = ['' % img(logo) if logo else "", + '
%s
' % (" ac" if accent else "", label), + CHEVRON if chevron else "", + CHECK if check else "", + "" if toggle is None else '
' + % (" on" if toggle else ""), + '
' if divider else ""] + return '
%s
' % ( + " logo" if logo else "", i * 44, "".join(p)) + + +def rows(items): + """Every row but the last carries the divider; that is the component's + own hasDivider default and what the exports show.""" + return "".join(row(i, divider=i < len(items) - 1, **it) + for i, it in enumerate(items)) + + +def card(top, height, items): + return '
%s
' % ( + top, height, rows(items)) + + +# ------------------------------------------------- 01 Settings home + +# Node 2006:4774 (light) / 2006:4775 (dark). The Top frame is 976 tall inside +# an 852 frame: this is a scrolling list parked at the top, so Siri & Search +# is cut mid-row and Photos and Game Center are off-screen. Both are emitted, +# because the frame clips them rather than the file omitting them. +HOME_CSS = LIST + """ +.title{position:absolute;left:var(--as-margin);top:100.5px;font:var(--as-t-b34)} +.si{position:absolute;left:96px;top:16.5px} +.si b{display:block;font:var(--as-t-r17);font-weight:400;color:var(--as-blue);margin-bottom:-2px} +.si span{display:block;position:relative;top:0.5px;font:var(--as-t-r13)} +.card>svg.av{position:absolute;display:block;color:var(--as-grey2)}""" + +HOME_CARDS = [ + (255, 44, [{"label": "Screen Time", "logo": "screen-time", "chevron": True}]), + (334, 132, [{"label": "General", "logo": "general", "chevron": True}, + {"label": "Accessibility", "logo": "accessibility", "chevron": True}, + {"label": "Privacy & Security", "logo": "privacy", + "chevron": True}]), + (501, 44, [{"label": "Passwords", "logo": "passwords", "chevron": True}]), + (580, 396, [{"label": "Safari", "logo": "safari", "chevron": True}, + {"label": "News", "logo": "news", "chevron": True}, + {"label": "Translate", "logo": "translate", "chevron": True}, + {"label": "Maps", "logo": "maps", "chevron": True}, + {"label": "Shortcuts", "logo": "shortcuts", "chevron": True}, + {"label": "Health", "logo": "health", "chevron": True}, + {"label": "Siri & Search", "logo": "siri", "chevron": True}, + {"label": "Photos", "logo": "photos", "chevron": True}, + {"label": "Game Center", "logo": "game-center", "chevron": True}])] + + +def settings_home(dark=False): + signin = ('
%s' + '
Sign in to your iPhone' + 'Set up iCloud, the App Store, and more.
' + % at("person-crop-circle-fill", 20.419, 5.475, 59.366, 59.336, "av")) + return page("Apple Settings - Settings" + (" (dark)" if dark else ""), HOME_CSS, + phone(statusbar() + '
Settings
' + signin + + "".join(card(*c) for c in HOME_CARDS) + home(), dark)) + + +# ------------------------------------------------- shared: pushed screen nav + +# Page Title on a pushed screen is 98 tall: the 54pt status bar over a 44pt +# Title and Actions row. Both instances in this file hide their Back button +# and their right actions, so the title is all that is left in that row. +NAV = """.nav{position:absolute;left:0;top:0;width:var(--as-w);height:98px;z-index:6} +.nav .mat{position:absolute;inset:0;background:var(--as-blur);backdrop-filter:blur(25px);-webkit-backdrop-filter:blur(25px)} +.nav .rule{position:absolute;left:0;right:0;bottom:0;height:var(--as-hair);background:var(--as-sep)} +.nav .tt{position:absolute;left:0;right:0;top:64.5px;text-align:center;font:var(--as-t-b17)}""" + + +def nav(title, material=True): + return ('' + % ('
' if material else "", + statusbar(), title, + '
' if material else "")) + + +# ------------------------------------------------- 02 Developer + +# Node 2006:4813 (light) / 2006:4814 (dark). Sections start at y 120 and each +# one is a 22pt header, a card, then an optional 54pt help block; the gap +# after a section is 20 when it has help and 35 when it does not. +DEV_CSS = LIST + NAV + """ +.sl{position:absolute;left:36px;height:16px;font:var(--as-t-r13);text-transform:uppercase;color:var(--as-grey)} +.sh{position:absolute;left:36px;width:321px;font:var(--as-t-r13);color:var(--as-grey)}""" + +# (top, header, card height, rows, help). "Text" is verbatim: two Action Rows +# in this community file were left on the component's unfilled default. The +# clone rule is to transcribe the reference, so the defect is reproduced and +# recorded in README.md rather than quietly corrected. +DEV_SECTIONS = [ + (120, "Paired devices", 44, [{"label": "Text", "accent": True}], + "Removing trusted computers will delete all of the records of computers " + "that you have paired with previously."), + (260, "UI automation", 44, + [{"label": "Enable UI Automation", "toggle": True}], None), + (361, "State restoration testing", 44, + [{"label": "Fast App Termination", "toggle": False}], + "Terminate instead of suspending apps when backgrounded to force apps to " + "be relaunched when they are foregrounded."), + (501, "Waltter testing", 176, + [{"label": "Additional Logging", "toggle": False}, + {"label": "Allow HTTP Services", "toggle": False}, + {"label": "Disable Rate Limiting", "toggle": False}, + {"label": "NFC Pass Key Optional", "toggle": False}], None), + (734, "Media services testing", 88, + [{"label": "AirPlay Suggestions", "chevron": True}, + {"label": "Text", "accent": True}], None), + (879, "News testing", 44, + [{"label": "Reset Local Data on Next Launch"}], None)] + + +def section(top, header, height, items, help_=None): + out = ['
%s
' % (top, header), + card(top + 22, height, items)] + if help_: + out.append('
%s
' + % (top + 22 + height + 6, help_)) + return "".join(out) + + +def developer(dark=False): + return page("Apple Settings - Developer" + (" (dark)" if dark else ""), DEV_CSS, + phone(nav("Developer") + "".join(section(*s) for s in DEV_SECTIONS) + + home(), dark)) + + +# ------------------------------------------------- 03 Display Zoom + +# Node 2006:4825 (light) / 2006:4826 (dark). This nav bar has neither the +# material nor the rule -- the page ground runs straight up under the clock -- +# and Sections is pt-35, so the one card starts at 98 + 35 = 133. +def display_zoom(dark=False): + return page("Apple Settings - Display Zoom" + (" (dark)" if dark else ""), + LIST + NAV, + phone(nav("Display Zoom", material=False) + + card(133, 88, [{"label": "Larger Text"}, + {"label": "Default", "check": True}]) + + home(), dark)) + + +# ------------------------------------------------- foundations boards + +# The two boards that carry Phase 1 and Phase 2: the token block rendered as +# itself, and the evidence behind every row of it. Both are built from +# TOKENS_SPEC, so neither can fall out of step with the :root the screens +# inline. Every swatch shows light over dark, because this board ships both. +SHEET = """body{padding:0;background:var(--as-card);color:var(--as-ink)} +.sh8{width:478px;height:980px;padding:22px 24px;overflow:hidden} +h1{font:590 20px/25px var(--as-font)} +header p{font:var(--as-t-r13);color:var(--as-grey);margin:2px 0 12px} +h2{font:590 10px/12px var(--as-font);text-transform:uppercase;color:var(--as-grey);margin:13px 0 6px} +.gr{display:grid;grid-template-columns:repeat(5,1fr);gap:7px} +.sw .ch{height:24px;border-radius:5px;border:0.5px solid var(--as-sep);display:flex;overflow:hidden} +.sw .ch span{flex:1} +.sw b{display:block;margin-top:3px;font:590 8.5px/11px ui-monospace,Menlo,monospace} +.sw i{display:block;font:400 8px/11px ui-monospace,Menlo,monospace;color:var(--as-grey);font-style:normal;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} +.rd{display:flex;gap:10px} +.rd div{text-align:center} +.rd .b{width:46px;height:26px;background:var(--as-bg);border:0.5px solid var(--as-sep)} +.rd em{display:block;margin-top:3px;font:400 8.5px/11px var(--as-font);color:var(--as-grey);font-style:normal} +.ty .tr{display:flex;align-items:baseline;justify-content:space-between;gap:8px;padding-bottom:2px;border-bottom:0.5px solid var(--as-sep)} +.ty .tr span{white-space:nowrap;overflow:hidden} +.ty .tr em{font:400 8px/11px ui-monospace,Menlo,monospace;color:var(--as-grey);font-style:normal;white-space:nowrap;flex:none} +.mt{columns:3;column-gap:14px;font:400 9px/13.5px ui-monospace,Menlo,monospace;color:var(--as-grey)} +.ev div{padding:3px 0;border-bottom:0.5px solid var(--as-sep)} +.ev b{font:590 8.5px/12px ui-monospace,Menlo,monospace;color:var(--as-blue)} +.ev i{font:400 8.5px/12px ui-monospace,Menlo,monospace;color:var(--as-grey);font-style:normal} +.ev p{font:400 8px/11px var(--as-font);color:var(--as-grey)}""" + + +def _of(group): + return [t for t in TOKENS_SPEC if t[0] == group] + + +def token_board(): + """Colour, radius, type and metrics, drawn with the tokens themselves. A + two-tone chip is a token the dark frames redefine; a flat one is a token + that is one value in both themes.""" + sw = "".join( + '
' + '%s
--as-%s%s
' + % (v, '' % d if d else "", n, v) + for g in ("Surface", "Ink") for _, n, v, d, _ in _of(g)) + rd = "".join('
%s
' + % (v, n[2:]) for _, n, v, _, _ in _of("Radius")) + ty = "".join('
%s' + '%s
' + % (n, "Settings" if int(v.split()[1].split("px")[0]) >= 34 + else "Sign in to your iPhone", v.split(" var")[0]) + for _, n, v, _, _ in _of("Type")) + mt = "
".join("--as-%s: %s" % (n, v) for _, n, v, _, _ in _of("Metrics")) + return page("Apple Settings - Design Tokens", SHEET, + '

Apple Settings · iOS

' + '

Figma SAJX6z3s8bHctuZyvOSN8i, 393pt mode. A two-tone chip is a ' + 'token the dark frames redefine, light half on the left. The type ' + 'ramp is labelled with its own shorthand; every row of it is a named ' + 'style in the file. The caption under a chip is its light value; ' + 'evidence for all %d tokens, both themes, is on the next %d ' + 'boards.

' + '

Colour

%s
' + '

Radius

%s
' + '

Type

%s
' + '

Metrics

%s
' + % (len(TOKENS_SPEC), len(list(evidence_boards())), sw, rd, ty, mt)) + + +EV_ROWS = 21 # what fits the 478 x 980 box; past this the table splits + + +def evidence_boards(): + """The evidence table, over as many boards as it needs. It is the + deliverable of Phase 1: split the board, never trim the rows.""" + pages = [TOKENS_SPEC[i:i + EV_ROWS] for i in range(0, len(TOKENS_SPEC), EV_ROWS)] + for i, chunk in enumerate(pages): + rows_ = "".join( + '
--as-%s %s%s

%s

' + % (n, v, " / " + d if d else "", e) for _g, n, v, d, e in chunk) + of = " %d/%d" % (i + 1, len(pages)) + yield ("00%s-evidence" % "bcdefgh"[i], + page("Apple Settings - Evidence" + of, SHEET, + '

Evidence%s

' + '

Token, then its light value and its dark override, then ' + 'where the value came from. A token with no evidence is a ' + 'guess.

%s
' % (of, rows_))) + + +# ------------------------------------------------- Phase 5: the references + +# assets/refs/ref-.png is the file's own PNG export of that frame at 2x, +# 786 x 1704, unretouched. They are gitignored (they are someone else's +# artwork), so a fresh clone regenerates the 9 boards above and skips these. +REF_CSS = """.rb{width:430px;height:932px;background:#151311;border-radius:20px;padding:14px 20px 12px;color:#fff;position:relative;overflow:hidden} +.rb h1{font:590 15px/20px var(--as-font)} +.rb p{font:400 9.5px/13px ui-monospace,Menlo,monospace;color:rgba(255,255,255,.5);margin-top:2px} +.rb .shot{margin-top:9px;display:flex;justify-content:center} +.rb img{width:393px;height:852px;display:block;border-radius:6px}""" + + +def ref_boards(): + for name, label, _fn in SCREENS: + for pre, theme in (("", "light"), ("d", "dark")): + path = os.path.join(ASSETS, "refs", "ref-%s%s.png" % (pre, name)) + if not os.path.exists(path): + continue + with open(path, "rb") as f: + uri = "data:image/png;base64," + base64.b64encode(f.read()).decode() + yield ("ref-%s%s" % (pre, name), + page("Apple Settings - reference: %s (%s)" % (label, theme), + REF_CSS, + '

%s — %s reference

' + '

Figma PNG export · 786×1704 @2x · ' + 'exact frame, not a near match

' + '
%s
' + % (label, theme, label, uri))) + + +# (file stem, caption on the canvas, builder). Both themes come from one +# builder: fn() is the light frame, fn(dark=True) the dark one. +SCREENS = [("01-settings", "Settings", settings_home), + ("02-developer", "Developer", developer), + ("03-display-zoom", "Display Zoom", display_zoom)] + + +def layout(refs): + """Four rows at one pitch from x = 0, so item N of every row lands + column-for-column under item N of the row above: each dark screen sits + under its light one, and each Figma export under the replica of it.""" + rows_ = [{"title": "Foundations", + "files": [{"file": "00-design-tokens", "label": "Design tokens"}] + + [{"file": n, "label": "Evidence"} + for n, _ in evidence_boards()]}, + {"title": "Screens: light", "numbered": True, + "files": [{"file": n, "label": l} for n, l, _ in SCREENS]}, + {"title": "Screens: dark", "numbered": True, + "files": [{"file": "d" + n, "label": l} for n, l, _ in SCREENS]}] + for pre, title in (("", "Source of truth: Figma export, light"), + ("d", "Source of truth: Figma export, dark")): + files = [{"file": "ref-%s%s" % (pre, n), "label": l} + for n, l, _ in SCREENS if "ref-%s%s" % (pre, n) in refs] + if files: + rows_.append({"title": title, "numbered": True, "files": files}) + return {"name": "(example) Apple Settings", "rows": rows_} + + +def main(): + files = {"00-design-tokens.html": token_board()} + files.update((n + ".html", h) for n, h in evidence_boards()) + for name, _label, fn in SCREENS: + files[name + ".html"] = fn() + files["d" + name + ".html"] = fn(dark=True) + refs = dict(ref_boards()) + files.update((n + ".html", h) for n, h in refs.items()) + for name, html in sorted(files.items()): + open(os.path.join(OUT, name), "w", encoding="utf-8").write(html) + print("%-32s %6d KB" % (name, len(html.encode()) // 1024)) + with open(os.path.join(OUT, "layout.json"), "w", encoding="utf-8") as f: + json.dump(layout(refs), f, indent=2) + f.write("\n") + print("%-32s %6d rows" % ("layout.json", len(layout(refs)["rows"]))) + + +if __name__ == "__main__": + main() diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/icon.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/icon.png new file mode 100644 index 0000000..97f875f Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/icon.png differ diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/layout.json b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/layout.json new file mode 100644 index 0000000..2e467d1 --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/canvases/apple-settings/layout.json @@ -0,0 +1,94 @@ +{ + "name": "(example) Apple Settings", + "rows": [ + { + "title": "Foundations", + "files": [ + { + "file": "00-design-tokens", + "label": "Design tokens" + }, + { + "file": "00b-evidence", + "label": "Evidence" + }, + { + "file": "00c-evidence", + "label": "Evidence" + } + ] + }, + { + "title": "Screens: light", + "numbered": true, + "files": [ + { + "file": "01-settings", + "label": "Settings" + }, + { + "file": "02-developer", + "label": "Developer" + }, + { + "file": "03-display-zoom", + "label": "Display Zoom" + } + ] + }, + { + "title": "Screens: dark", + "numbered": true, + "files": [ + { + "file": "d01-settings", + "label": "Settings" + }, + { + "file": "d02-developer", + "label": "Developer" + }, + { + "file": "d03-display-zoom", + "label": "Display Zoom" + } + ] + }, + { + "title": "Source of truth: Figma export, light", + "numbered": true, + "files": [ + { + "file": "ref-01-settings", + "label": "Settings" + }, + { + "file": "ref-02-developer", + "label": "Developer" + }, + { + "file": "ref-03-display-zoom", + "label": "Display Zoom" + } + ] + }, + { + "title": "Source of truth: Figma export, dark", + "numbered": true, + "files": [ + { + "file": "ref-d01-settings", + "label": "Settings" + }, + { + "file": "ref-d02-developer", + "label": "Developer" + }, + { + "file": "ref-d03-display-zoom", + "label": "Display Zoom" + } + ] + } + ] +} diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/project.json b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/project.json new file mode 100644 index 0000000..b99f619 --- /dev/null +++ b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/project.json @@ -0,0 +1,6 @@ +{ + "format": 1, + "name": "Apple Settings", + "author": "Jing-yilin", + "id": "19146dc5-50a2-43a4-9fd7-9e21f7d74845" +} diff --git a/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/thumbnail.png b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/thumbnail.png new file mode 100644 index 0000000..90d1085 Binary files /dev/null and b/projects/19146dc5-50a2-43a4-9fd7-9e21f7d74845/thumbnail.png differ