claudecode-omc 5.6.6 → 5.6.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.local/skills/THIRD_PARTY_LICENSES/AvdLee-SwiftUI-Agent-Skill.LICENSE +21 -0
- package/.local/skills/THIRD_PARTY_LICENSES/Dimillian-Skills.LICENSE +21 -0
- package/.local/skills/THIRD_PARTY_LICENSES/README.md +36 -0
- package/.local/skills/THIRD_PARTY_LICENSES/twostraws-swiftui-agent-skill.LICENSE +21 -0
- package/.local/skills/h5-to-swiftui/SKILL.md +201 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/README.md +176 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/h5-twin/index.html +52 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/h5-twin/style.css +133 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin/Package.swift +26 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin/Sources/CalibrationScreen/CalibrationScreen.swift +142 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin-divergent/Package.swift +32 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin-divergent/Sources/CalibrationScreenDivergent/CalibrationScreenDivergent.swift +122 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/tokens.json +42 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/index.html +14 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/package.json +20 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/public/api/articles/001.json +96 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/public/api/articles/index.json +89 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/App.jsx +22 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/App.module.css +11 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/ArticleCard.jsx +53 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/ArticleCard.module.css +139 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/NavBar.jsx +37 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/NavBar.module.css +72 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TagCloud.jsx +30 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TagCloud.module.css +50 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TrendChart.jsx +159 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TrendChart.module.css +21 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/main.jsx +12 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/ArticleScreen.jsx +182 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/ArticleScreen.module.css +294 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/FeedScreen.jsx +147 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/FeedScreen.module.css +161 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/styles/global.css +50 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/styles/tokens.css +103 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/vite.config.js +6 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/data/tasks.js +67 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/index.html +26 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/router.js +73 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/detail.js +164 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/home.js +53 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/list.js +87 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/styles/app.css +342 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/styles/tokens.css +68 -0
- package/.local/skills/h5-to-swiftui/references/css-to-swiftui-map.md +205 -0
- package/.local/skills/h5-to-swiftui/references/design-token-extraction.md +209 -0
- package/.local/skills/h5-to-swiftui/references/high-risk-triage.md +209 -0
- package/.local/skills/h5-to-swiftui/references/render-equivalence-calibration.md +193 -0
- package/.local/skills/h5-to-swiftui/references/stack-detection.md +160 -0
- package/.local/skills/h5-to-swiftui/references/visual-diff-loop-protocol.md +365 -0
- package/.local/skills/h5-to-swiftui/scripts/_calib-consts.mjs +150 -0
- package/.local/skills/h5-to-swiftui/scripts/_imglib.mjs +547 -0
- package/.local/skills/h5-to-swiftui/scripts/_provenance.mjs +123 -0
- package/.local/skills/h5-to-swiftui/scripts/calibrate-render.mjs +625 -0
- package/.local/skills/h5-to-swiftui/scripts/capture-reference.mjs +386 -0
- package/.local/skills/h5-to-swiftui/scripts/detect-stack.mjs +305 -0
- package/.local/skills/h5-to-swiftui/scripts/evaluate-convergence.mjs +1093 -0
- package/.local/skills/h5-to-swiftui/scripts/extract-tokens.mjs +600 -0
- package/.local/skills/h5-to-swiftui/scripts/mark-overlay.mjs +379 -0
- package/.local/skills/h5-to-swiftui/scripts/pixel-diff.mjs +530 -0
- package/.local/skills/h5-to-swiftui/scripts/sim-screenshot.sh +544 -0
- package/.local/skills/ios-debugger-agent/SKILL.md +51 -0
- package/.local/skills/ios-debugger-agent/agents/openai.yaml +4 -0
- package/.local/skills/swift-concurrency-expert/SKILL.md +105 -0
- package/.local/skills/swift-concurrency-expert/agents/openai.yaml +4 -0
- package/.local/skills/swift-concurrency-expert/references/approachable-concurrency.md +63 -0
- package/.local/skills/swift-concurrency-expert/references/swift-6-2-concurrency.md +272 -0
- package/.local/skills/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md +33 -0
- package/.local/skills/swiftui-expert-skill/SKILL.md +162 -0
- package/.local/skills/swiftui-expert-skill/references/accessibility-patterns.md +215 -0
- package/.local/skills/swiftui-expert-skill/references/animation-advanced.md +403 -0
- package/.local/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
- package/.local/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
- package/.local/skills/swiftui-expert-skill/references/charts-accessibility.md +135 -0
- package/.local/skills/swiftui-expert-skill/references/charts.md +602 -0
- package/.local/skills/swiftui-expert-skill/references/focus-patterns.md +299 -0
- package/.local/skills/swiftui-expert-skill/references/image-optimization.md +203 -0
- package/.local/skills/swiftui-expert-skill/references/latest-apis.md +488 -0
- package/.local/skills/swiftui-expert-skill/references/layout-best-practices.md +266 -0
- package/.local/skills/swiftui-expert-skill/references/liquid-glass.md +423 -0
- package/.local/skills/swiftui-expert-skill/references/list-patterns.md +446 -0
- package/.local/skills/swiftui-expert-skill/references/macos-scenes.md +318 -0
- package/.local/skills/swiftui-expert-skill/references/macos-views.md +357 -0
- package/.local/skills/swiftui-expert-skill/references/macos-window-styling.md +303 -0
- package/.local/skills/swiftui-expert-skill/references/performance-patterns.md +403 -0
- package/.local/skills/swiftui-expert-skill/references/scroll-patterns.md +293 -0
- package/.local/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
- package/.local/skills/swiftui-expert-skill/references/state-management.md +388 -0
- package/.local/skills/swiftui-expert-skill/references/text-patterns.md +32 -0
- package/.local/skills/swiftui-expert-skill/references/trace-analysis.md +295 -0
- package/.local/skills/swiftui-expert-skill/references/trace-recording.md +134 -0
- package/.local/skills/swiftui-expert-skill/references/view-structure.md +780 -0
- package/.local/skills/swiftui-expert-skill/scripts/__pycache__/analyze_trace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/__pycache__/record_trace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/analyze_trace.py +301 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__init__.py +1 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/__init__.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/causes.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/correlate.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/events.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hangs.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hitches.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/summary.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/swiftui.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/time_profiler.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xctrace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xml_utils.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/causes.py +187 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/correlate.py +179 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/events.py +291 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hangs.py +108 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hitches.py +145 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/summary.py +243 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/swiftui.py +195 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/time_profiler.py +135 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xctrace.py +117 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xml_utils.py +224 -0
- package/.local/skills/swiftui-expert-skill/scripts/record_trace.py +252 -0
- package/.local/skills/swiftui-liquid-glass/SKILL.md +90 -0
- package/.local/skills/swiftui-liquid-glass/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-liquid-glass/references/liquid-glass.md +280 -0
- package/.local/skills/swiftui-performance-audit/SKILL.md +106 -0
- package/.local/skills/swiftui-performance-audit/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-performance-audit/references/code-smells.md +150 -0
- package/.local/skills/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
- package/.local/skills/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
- package/.local/skills/swiftui-performance-audit/references/profiling-intake.md +44 -0
- package/.local/skills/swiftui-performance-audit/references/report-template.md +47 -0
- package/.local/skills/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
- package/.local/skills/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
- package/.local/skills/swiftui-pro/SKILL.md +108 -0
- package/.local/skills/swiftui-pro/agents/openai.yaml +10 -0
- package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
- package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
- package/.local/skills/swiftui-pro/references/accessibility.md +13 -0
- package/.local/skills/swiftui-pro/references/api.md +39 -0
- package/.local/skills/swiftui-pro/references/data.md +43 -0
- package/.local/skills/swiftui-pro/references/design.md +32 -0
- package/.local/skills/swiftui-pro/references/hygiene.md +9 -0
- package/.local/skills/swiftui-pro/references/navigation.md +14 -0
- package/.local/skills/swiftui-pro/references/performance.md +46 -0
- package/.local/skills/swiftui-pro/references/swift.md +56 -0
- package/.local/skills/swiftui-pro/references/views.md +36 -0
- package/.local/skills/swiftui-ui-patterns/SKILL.md +95 -0
- package/.local/skills/swiftui-ui-patterns/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
- package/.local/skills/swiftui-ui-patterns/references/async-state.md +96 -0
- package/.local/skills/swiftui-ui-patterns/references/components-index.md +50 -0
- package/.local/skills/swiftui-ui-patterns/references/controls.md +57 -0
- package/.local/skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
- package/.local/skills/swiftui-ui-patterns/references/focus.md +90 -0
- package/.local/skills/swiftui-ui-patterns/references/form.md +97 -0
- package/.local/skills/swiftui-ui-patterns/references/grids.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/haptics.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
- package/.local/skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
- package/.local/skills/swiftui-ui-patterns/references/list.md +86 -0
- package/.local/skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
- package/.local/skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
- package/.local/skills/swiftui-ui-patterns/references/media.md +73 -0
- package/.local/skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
- package/.local/skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
- package/.local/skills/swiftui-ui-patterns/references/overlay.md +45 -0
- package/.local/skills/swiftui-ui-patterns/references/performance.md +62 -0
- package/.local/skills/swiftui-ui-patterns/references/previews.md +48 -0
- package/.local/skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
- package/.local/skills/swiftui-ui-patterns/references/scrollview.md +87 -0
- package/.local/skills/swiftui-ui-patterns/references/searchable.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/sheets.md +155 -0
- package/.local/skills/swiftui-ui-patterns/references/split-views.md +72 -0
- package/.local/skills/swiftui-ui-patterns/references/tabview.md +114 -0
- package/.local/skills/swiftui-ui-patterns/references/theming.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/title-menus.md +93 -0
- package/.local/skills/swiftui-ui-patterns/references/top-bar.md +49 -0
- package/.local/skills/swiftui-view-refactor/SKILL.md +202 -0
- package/.local/skills/swiftui-view-refactor/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-view-refactor/references/mv-patterns.md +161 -0
- package/bundled/manifest.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Antoine van der Lee
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thomas Ricouard
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Third-Party Skill Attribution
|
|
2
|
+
|
|
3
|
+
The following iOS / Swift / SwiftUI skills were vendored from external
|
|
4
|
+
open-source repositories. Each is distributed under the **MIT License**.
|
|
5
|
+
The full upstream license text is preserved in this directory and must remain
|
|
6
|
+
shipped with `claudecode-omc` per the MIT terms.
|
|
7
|
+
|
|
8
|
+
| Vendored skill (`.local/skills/<dir>`) | Source repository | Source commit | License file |
|
|
9
|
+
|---|---|---|---|
|
|
10
|
+
| `ios-debugger-agent` | [Dimillian/Skills](https://github.com/Dimillian/Skills) | `05ba982` | [Dimillian-Skills.LICENSE](./Dimillian-Skills.LICENSE) |
|
|
11
|
+
| `swift-concurrency-expert` | [Dimillian/Skills](https://github.com/Dimillian/Skills) | `05ba982` | [Dimillian-Skills.LICENSE](./Dimillian-Skills.LICENSE) |
|
|
12
|
+
| `swiftui-liquid-glass` | [Dimillian/Skills](https://github.com/Dimillian/Skills) | `05ba982` | [Dimillian-Skills.LICENSE](./Dimillian-Skills.LICENSE) |
|
|
13
|
+
| `swiftui-performance-audit` | [Dimillian/Skills](https://github.com/Dimillian/Skills) | `05ba982` | [Dimillian-Skills.LICENSE](./Dimillian-Skills.LICENSE) |
|
|
14
|
+
| `swiftui-ui-patterns` | [Dimillian/Skills](https://github.com/Dimillian/Skills) | `05ba982` | [Dimillian-Skills.LICENSE](./Dimillian-Skills.LICENSE) |
|
|
15
|
+
| `swiftui-view-refactor` | [Dimillian/Skills](https://github.com/Dimillian/Skills) | `05ba982` | [Dimillian-Skills.LICENSE](./Dimillian-Skills.LICENSE) |
|
|
16
|
+
| `swiftui-pro` | [twostraws/swiftui-agent-skill](https://github.com/twostraws/swiftui-agent-skill) | `be297ff` | [twostraws-swiftui-agent-skill.LICENSE](./twostraws-swiftui-agent-skill.LICENSE) |
|
|
17
|
+
| `swiftui-expert-skill` | [AvdLee/SwiftUI-Agent-Skill](https://github.com/AvdLee/SwiftUI-Agent-Skill) | `a4d7692` | [AvdLee-SwiftUI-Agent-Skill.LICENSE](./AvdLee-SwiftUI-Agent-Skill.LICENSE) |
|
|
18
|
+
|
|
19
|
+
## Copyright holders
|
|
20
|
+
|
|
21
|
+
- **Dimillian/Skills** — Copyright (c) 2026 Thomas Ricouard — MIT
|
|
22
|
+
- **twostraws/swiftui-agent-skill** — Copyright (c) 2026 Paul Hudson — MIT
|
|
23
|
+
- **AvdLee/SwiftUI-Agent-Skill** — Copyright (c) 2026 Antoine van der Lee — MIT
|
|
24
|
+
|
|
25
|
+
## Vendoring notes
|
|
26
|
+
|
|
27
|
+
- Only the iOS/SwiftUI-relevant subset of `Dimillian/Skills` was vendored;
|
|
28
|
+
non-iOS skills (React, GitHub, review/refactor swarms, etc.) were excluded.
|
|
29
|
+
- From `twostraws/swiftui-agent-skill`, the marketplace-packaging artifacts
|
|
30
|
+
(`.claude-plugin/`) and the divergent nested `skills/swiftui-pro/` duplicate
|
|
31
|
+
were excluded; only the canonical top-level skill + `references/` were taken.
|
|
32
|
+
- From `AvdLee/SwiftUI-Agent-Skill`, only `swiftui-expert-skill/` was vendored;
|
|
33
|
+
the `update-swiftui-apis` helper was excluded because it requires the
|
|
34
|
+
external Sosumi MCP server.
|
|
35
|
+
- Upstream skill content was vendored verbatim (no edits to SKILL.md bodies);
|
|
36
|
+
only placement under `.local/skills/` differs from upstream layout.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Paul Hudson.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: h5-to-swiftui
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: >-
|
|
5
|
+
Convert an H5 / web app's source into a native SwiftUI iOS app by native
|
|
6
|
+
rewrite (NOT a WebView shell, NOT a transpiler). Use when the user wants to
|
|
7
|
+
port, re-implement, or migrate a web/H5 frontend to native SwiftUI with
|
|
8
|
+
high visual fidelity, asks to "turn this web app into a real iOS app", or
|
|
9
|
+
wants a measured render-diff convergence loop against a browser baseline.
|
|
10
|
+
Auto-detects the web stack (v1: vanilla + React; other stacks are detected
|
|
11
|
+
then gated, not guessed), extracts design tokens, calibrates a
|
|
12
|
+
cross-renderer fidelity floor, rewrites per component, and drives a bounded
|
|
13
|
+
render→diff→correct loop that reports a quantified visual residual plus an
|
|
14
|
+
independent judge verdict. It does NOT promise literal pixel-identity:
|
|
15
|
+
cross-renderer differences impose a measured floor it reports honestly.
|
|
16
|
+
Triages canvas/WebGL/complex-animation/3rd-party-SDK/backend surfaces
|
|
17
|
+
instead of silently emitting wrong code.
|
|
18
|
+
argument-hint: "<path-to-h5-source> [--ios-floor 17] [--device 'iPhone 15 Pro'] [--max-iter 3]"
|
|
19
|
+
disable-model-invocation: false
|
|
20
|
+
user-invocable: true
|
|
21
|
+
allowed-tools:
|
|
22
|
+
- Read
|
|
23
|
+
- Grep
|
|
24
|
+
- Glob
|
|
25
|
+
- Bash
|
|
26
|
+
- Write
|
|
27
|
+
- Edit
|
|
28
|
+
- Agent
|
|
29
|
+
model: sonnet
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
# H5 → Native SwiftUI (perceptually-convergent, residual-quantified)
|
|
33
|
+
|
|
34
|
+
Convert a web/H5 app to a **native SwiftUI** iOS app by reading the source and
|
|
35
|
+
**re-implementing** UI + logic in idiomatic SwiftUI. This is a native rewrite,
|
|
36
|
+
**not** a WebView wrapper and **not** a mechanical transpiler — those cannot
|
|
37
|
+
reach native fidelity (see `references/stack-detection.md` for why).
|
|
38
|
+
|
|
39
|
+
## Honest promise (read this first)
|
|
40
|
+
|
|
41
|
+
Literal pixel-identity is **physically unreachable** for any text-bearing
|
|
42
|
+
screen: H5 renders in WebKit/Skia, SwiftUI in CoreText/Core Animation;
|
|
43
|
+
per-glyph subpixel/hinting and sRGB-vs-Display-P3 differences impose a
|
|
44
|
+
**non-zero residual** even when the SwiftUI is perfectly correct. This skill
|
|
45
|
+
therefore does **not** claim "pixel-perfect". It:
|
|
46
|
+
|
|
47
|
+
1. **measures** the achievable cross-renderer floor for the current toolchain
|
|
48
|
+
(Stage 2.5 calibration),
|
|
49
|
+
2. drives a render→diff→correct loop that **strictly reduces** visual delta
|
|
50
|
+
toward that measured floor,
|
|
51
|
+
3. stops with a **quantified residual**, an **independent adversarial judge**
|
|
52
|
+
verdict, and a tiered outcome: `converged` / `close` / `needs-human`,
|
|
53
|
+
4. **triages** anything it cannot safely convert — never silently emits
|
|
54
|
+
plausible-wrong code.
|
|
55
|
+
|
|
56
|
+
Never describe output as "pixel-accurate/perfect" in any report.
|
|
57
|
+
|
|
58
|
+
## When to use / not use
|
|
59
|
+
|
|
60
|
+
Use for: porting a web/H5 frontend to native SwiftUI; "make this a real iOS
|
|
61
|
+
app (not a webview)"; measured visual migration. Not for: building a webview
|
|
62
|
+
wrapper (decline — out of scope); generic SwiftUI feature work (use normal
|
|
63
|
+
dev flow); design-mock→code with no source app (different problem).
|
|
64
|
+
|
|
65
|
+
## Inputs
|
|
66
|
+
|
|
67
|
+
- `<path-to-h5-source>` (required)
|
|
68
|
+
- `--ios-floor` (default `17`; changes API availability + risk tiers)
|
|
69
|
+
- `--device` (default `iPhone 15 Pro`; sets logical viewport + safe-area)
|
|
70
|
+
- `--max-iter` (default `3`; Stage 5 per-component iteration cap)
|
|
71
|
+
- `--thresholds` (optional override; default = **calibrated**, not asserted)
|
|
72
|
+
|
|
73
|
+
## Environment reality (hard gate)
|
|
74
|
+
|
|
75
|
+
Stage 5 needs macOS + Xcode + iOS Simulator. If absent OR the generated
|
|
76
|
+
project fails to build, the affected component is `needs-human`/`blocked`
|
|
77
|
+
and is **never counted converged**. The skill must not fabricate
|
|
78
|
+
convergence. Stages 0–4 + triage still run and produce value.
|
|
79
|
+
|
|
80
|
+
## Pipeline (Stage 0–7) — product contracts
|
|
81
|
+
|
|
82
|
+
All stage products go under the *target project*'s `.h5-to-swiftui/` work
|
|
83
|
+
dir (inspectable, resumable). Every convergence artifact header pins
|
|
84
|
+
`sim_runtime`, `browser_version`, `model_id`, `temperature:0` — re-runs must
|
|
85
|
+
reproduce the same **verdict** (not the same pixels).
|
|
86
|
+
|
|
87
|
+
| Stage | Does | Key output |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| 0 Intake + detect + **v1 gate** | `scripts/detect-stack.mjs`; framework ∉ {vanilla,React} ⇒ write report & **STOP** (no guess) | `stack-report.json` |
|
|
90
|
+
| 1 Static analysis + facts + risk | inventory; `scripts/extract-tokens.mjs` (static∪runtime DTCG); risk triage pass *before* any generation; token-miss ⇒ `token-gaps.json` (never inline) | `pages/components/state-model/api/tokens/token-gaps/risk-triage.json` |
|
|
91
|
+
| 2 Reference capture | `scripts/capture-reference.mjs` (Playwright, iOS viewport, animations frozen, webfont/async settle, masks, browser pinned) | `reference/**`, `reference/manifest.json` |
|
|
92
|
+
| 2.5 **Render-equivalence calibration** | `scripts/calibrate-render.mjs` on bundled known-correct pair → normalization + **measured floor**; unmeasurable ⇒ `blocked.json` | `calibration.json` → see `references/render-equivalence-calibration.md` |
|
|
93
|
+
| 3 Scaffold | Xcode skeleton; `DesignTokens` (DTCG→Color/Font/spacing/radius + `.colorset` dark); router→`NavigationStack`; state skeleton | compiling skeleton |
|
|
94
|
+
| 4 Per-component rewrite | LLM rewrites each component using **only** token vocab + `references/css-to-swiftui-map.md`; **each component MUST emit a snapshot host** (isolated render entry); idiomatic-lint rejects `.position/.offset`-pinned layouts; Tier-3 ⇒ non-compiling `fatalError` stub | per-component `.swift` + host |
|
|
95
|
+
| 5 **Convergence loop** ★ | per component: host-render→normalize(calibration)→cascade diff (`pixel-diff.mjs`)→feedback payload→structured patch→recompile→re-measure; cap `--max-iter`. **The verdict is emitted ONLY by `scripts/evaluate-convergence.mjs`** — it mechanically enforces every anti-gaming guard and exits non-zero on any violation; the LLM never hand-writes `convergence/<component>.json` | `convergence/<component>.json` (written by `evaluate-convergence.mjs`) → see `references/visual-diff-loop-protocol.md` |
|
|
96
|
+
| 6 Behavioral parity | port `URLSession` async / Keychain tokens / ATS-flag `http://` / state / models; equivalence checks | `parity-report.json` |
|
|
97
|
+
| 7 Assemble + honest report | build; aggregate; summary leads with `needs-human` if it dominates | Xcode project + `conversion-report.json` + `convergence-summary.json` |
|
|
98
|
+
|
|
99
|
+
## Hard rules (non-negotiable)
|
|
100
|
+
|
|
101
|
+
- **No silent failure.** Tier-3 surfaces (WebGL/WebGPU, RAF physics, WebRTC,
|
|
102
|
+
payments/secrets, analytics/ATT) ⇒ non-compiling `fatalError` stub +
|
|
103
|
+
machine-readable entry in `conversion-report.json`. See
|
|
104
|
+
`references/high-risk-triage.md`.
|
|
105
|
+
- **Anti-gaming (Stage 5) — ENFORCED IN CODE by
|
|
106
|
+
`scripts/evaluate-convergence.mjs`** (the sole thing that may emit the
|
|
107
|
+
verdict; it exits non-zero on any violation so a pipeline cannot ignore a
|
|
108
|
+
failed gate): the calibration gate is **recomputed from `calib.floor`** and
|
|
109
|
+
a hand-loosened gate is rejected (`gate-floor-mismatch`, exit 1 — this binds
|
|
110
|
+
the *gate to the floor*, not the floor's value); the **identity of the
|
|
111
|
+
bundled twin source files** (excluding build output/dotfiles) is bound via
|
|
112
|
+
`calibration_source` source-tree hashes recomputed from
|
|
113
|
+
`assets/calibration/{h5-twin,swiftui-twin}` (`calibration-twin-mismatch`,
|
|
114
|
+
exit 1 — binds the twin *source identity*, not the measured floor value);
|
|
115
|
+
the `floor` *value* is asserted to satisfy `calibrate-render.mjs`'s own
|
|
116
|
+
sanity envelope via the shared `scripts/_calib-consts.mjs`
|
|
117
|
+
(`floor-implausible`, exit 1 — a floor calibrate-render could not have
|
|
118
|
+
emitted is rejected, killing the absurd-floor attack; a floor *within* that
|
|
119
|
+
envelope but looser than the true measured one is a disclosed residual, see
|
|
120
|
+
below); the judge **negative control is bound** to the shipped, hash-pinned
|
|
121
|
+
`assets/calibration/swiftui-twin-divergent` source files (structured
|
|
122
|
+
`{stimulus_source_hash,rejected,differences}` under **forced-difference-3**;
|
|
123
|
+
the legacy bare string is rejected and an unbound control VOIDs any `YES`);
|
|
124
|
+
mask budget ≤10% with a non-empty reason per mask; the structured gate is
|
|
125
|
+
evaluated per iteration (a text-region `iou` of `null` is a FAIL; pHash is
|
|
126
|
+
necessary-not-sufficient and never short-circuits); best-of-N retains
|
|
127
|
+
**only built + gate-passing iterations** chosen by the script
|
|
128
|
+
(monotone-or-fail; caller's pick ignored); a present `blocked.json` or no
|
|
129
|
+
built+passing iteration ⇒ never converged. **Named irreducible residuals
|
|
130
|
+
(honest, §1.1) — BOTH disclosed:** (1) the grader cannot re-run the
|
|
131
|
+
simulator, so it trusts the per-iteration `pixel-diff.mjs` JSONs were
|
|
132
|
+
produced by the real `pixel-diff.mjs` on real `sim-screenshot.sh` renders
|
|
133
|
+
(bounded by that script's no-fake spine); (2) the grader cannot re-measure
|
|
134
|
+
the calibration floor — it asserts the supplied `floor` is within
|
|
135
|
+
`calibrate-render.mjs`'s own sanity envelope and recomputes the gate from
|
|
136
|
+
it, but a floor *within* that envelope yet looser than the true measured
|
|
137
|
+
floor is trusted, mitigated by the orchestrator's obligation to run the
|
|
138
|
+
real, sanity-spined `calibrate-render.mjs` and the recorded
|
|
139
|
+
`calibration_provenance`. Maximally provenance-bound, not zero-trust. The
|
|
140
|
+
**whole-assembled-screen SSIM-trend check is NOT an automated Stage-5
|
|
141
|
+
guard** — see the known limitation below; it is a documented **Stage-7
|
|
142
|
+
manual** cross-check.
|
|
143
|
+
- **Calibrated, not asserted.** Stage 5 gates against the **measured** floor
|
|
144
|
+
from `calibration.json`, never a hardcoded SSIM constant.
|
|
145
|
+
- **v1 scope.** Mapping authored for vanilla + React only; other detected
|
|
146
|
+
stacks stop at Stage 0 with an explicit report.
|
|
147
|
+
- **Compile-failure branch.** Non-building patch ⇒ revert to best
|
|
148
|
+
gate-passing iteration, consume an iteration; terminal ⇒ `needs-human`.
|
|
149
|
+
|
|
150
|
+
## References (read on demand — progressive disclosure)
|
|
151
|
+
|
|
152
|
+
- `references/stack-detection.md` — detection heuristics, why rewrite > webview/transpile, v1 gate
|
|
153
|
+
- `references/design-token-extraction.md` — static∪runtime DTCG pipeline, token-gap rule
|
|
154
|
+
- `references/css-to-swiftui-map.md` — flex/grid/positioning/box-model tables, custom-`Layout` triggers
|
|
155
|
+
- `references/render-equivalence-calibration.md` — Stage 2.5 normalization + floor measurement + `calibration.json` schema
|
|
156
|
+
- `references/visual-diff-loop-protocol.md` — Stage 5 mechanism, payload + artifact schemas, tiered verdict, anti-gaming
|
|
157
|
+
- `references/high-risk-triage.md` — Tier 1/2/3 catalog, stub format, `conversion-report.json` schema
|
|
158
|
+
|
|
159
|
+
## Scripts
|
|
160
|
+
|
|
161
|
+
`detect-stack.mjs` `extract-tokens.mjs` `capture-reference.mjs`
|
|
162
|
+
`calibrate-render.mjs` `pixel-diff.mjs` `mark-overlay.mjs`
|
|
163
|
+
`evaluate-convergence.mjs` `sim-screenshot.sh` — each supports `--help`;
|
|
164
|
+
capability/build probes degrade to an explicit block, never a fake success.
|
|
165
|
+
|
|
166
|
+
`scripts/evaluate-convergence.mjs` is the **sole executable convergence
|
|
167
|
+
authority**: it consumes the per-iteration `pixel-diff.mjs` JSON, the
|
|
168
|
+
structured `calibration.json` gate, the masks, and the judge result, then
|
|
169
|
+
mechanically decides the tier and **exits non-zero** (3 = needs-human/guard
|
|
170
|
+
violation, 4 = blocked) so the verdict cannot be faked or ignored. The
|
|
171
|
+
orchestrator MUST call it and MUST NOT hand-write `convergence/<component>.json`.
|
|
172
|
+
|
|
173
|
+
### Known limitation (honest)
|
|
174
|
+
|
|
175
|
+
The **whole-assembled-screen SSIM-trend check** described in `spec.md` is
|
|
176
|
+
**not** an automated Stage-5 guard — there is no executable component that
|
|
177
|
+
diffs the assembled screen during the loop, so advertising it as active
|
|
178
|
+
would be a prose-only claim. It is instead a **Stage-7 manual cross-check**:
|
|
179
|
+
after assembly, a human (or a separate verification pass) compares the
|
|
180
|
+
assembled-screen capture against the reference so per-component `converged`
|
|
181
|
+
results cannot mask a broken composition. Treat per-component verdicts as
|
|
182
|
+
authoritative only at component granularity until that Stage-7 check is done.
|
|
183
|
+
|
|
184
|
+
## Assets
|
|
185
|
+
|
|
186
|
+
`assets/calibration/` — known-correct SwiftUI screen (`swiftui-twin/`) + H5
|
|
187
|
+
twin (`h5-twin/`) for Stage 2.5, plus a deliberately-wrong
|
|
188
|
+
`swiftui-twin-divergent/` used as the Stage-5 judge **negative control**.
|
|
189
|
+
Calibration content is **textured** (text + a 4-stripe multi-color region),
|
|
190
|
+
never flat solids, so SSIM is meaningful (`calibrate-render.mjs` blocks a
|
|
191
|
+
flat pair). `assets/sample-h5-vanilla/` + `assets/sample-h5-react/` are the
|
|
192
|
+
dry-run fixtures (the React one is the text-heavy / custom-`Layout` / Tier-3
|
|
193
|
+
hard path).
|
|
194
|
+
|
|
195
|
+
## Done = evidence
|
|
196
|
+
|
|
197
|
+
A run is complete only with: `stack-report.json`, `calibration.json` (finite
|
|
198
|
+
floor), per-component `convergence/*.json` (pinned-version header, iteration
|
|
199
|
+
history, masks, negative-control result, tiered verdict),
|
|
200
|
+
`conversion-report.json`, and an honest `convergence-summary.json`. No
|
|
201
|
+
success claim without these.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Stage 2.5 Calibration Pair
|
|
2
|
+
|
|
3
|
+
This directory contains a **hand-built, known-correct calibration pair** for
|
|
4
|
+
the `h5-to-swiftui` skill's render-equivalence calibration stage. The two
|
|
5
|
+
sides (`h5-twin/` and `swiftui-twin/`) render the **same intended design** on
|
|
6
|
+
an iPhone 15 Pro logical viewport (393×852 pt).
|
|
7
|
+
|
|
8
|
+
> **Key principle:** any measured rendering difference between these two sides
|
|
9
|
+
> is the **irreducible cross-renderer floor** — not a defect. The pair is
|
|
10
|
+
> equivalent by construction, so the floor reflects only the unavoidable
|
|
11
|
+
> divergence between WebKit/Skia glyph rasterization and CoreText/Metal
|
|
12
|
+
> rendering, color-space pipeline differences (sRGB vs Display-P3), and
|
|
13
|
+
> sub-pixel sampling. Never grade real conversion screens against a tighter
|
|
14
|
+
> bound than this measured floor.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Contents
|
|
19
|
+
|
|
20
|
+
| Path | Description |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `h5-twin/index.html` | Static H5 page — open directly, no build step |
|
|
23
|
+
| `h5-twin/style.css` | All design tokens as CSS custom properties (`--*`) |
|
|
24
|
+
| `swiftui-twin/Package.swift` | Swift Package manifest (Swift 5.9+, iOS 17+) |
|
|
25
|
+
| `swiftui-twin/Sources/CalibrationScreen/CalibrationScreen.swift` | `CalibrationScreenView` + `#Preview` — the **known-correct** SwiftUI side |
|
|
26
|
+
| `swiftui-twin-divergent/Package.swift` | Swift Package manifest for the negative control |
|
|
27
|
+
| `swiftui-twin-divergent/Sources/CalibrationScreenDivergent/CalibrationScreenDivergent.swift` | **Deliberately WRONG** SwiftUI screen — the Stage 5 judge **negative control** |
|
|
28
|
+
| `tokens.json` | Ground-truth DTCG-style token map — the single source of truth |
|
|
29
|
+
| `.gitignore` | Ignores Swift Package `.build/` (never commit build output) |
|
|
30
|
+
| `README.md` | This file |
|
|
31
|
+
|
|
32
|
+
### The divergent twin (negative control)
|
|
33
|
+
|
|
34
|
+
`swiftui-twin-divergent/` is **intentionally wrong** versus the H5 twin:
|
|
35
|
+
wrong colors (green background, blue circle, recolored stripes, inverted text
|
|
36
|
+
colors), shifted layout (much larger top inset, doubled section gap, circle
|
|
37
|
+
moved to the trailing edge, near-square taller card), and different copy.
|
|
38
|
+
|
|
39
|
+
Its role: the Stage 5 **independent judge must REJECT** the pair
|
|
40
|
+
(`h5-twin` vs `swiftui-twin-divergent`) under the adversarial
|
|
41
|
+
forced-difference-3 framing. If the judge instead calls them equivalent, the
|
|
42
|
+
run's `judge.negative_control` is recorded as **`failed`** and any `YES`
|
|
43
|
+
verdict is **VOID** for that run. This is enforced mechanically — not by
|
|
44
|
+
prose — in `scripts/evaluate-convergence.mjs` (guard 4).
|
|
45
|
+
|
|
46
|
+
### Textured-content requirement (NOT flat solids)
|
|
47
|
+
|
|
48
|
+
The bundled calibration content **must be textured** — text plus a
|
|
49
|
+
multi-color structured region. Flat solid blocks make SSIM **insensitive to a
|
|
50
|
+
uniform mean shift**: a clearly-divergent solid pair can still score ~0.95,
|
|
51
|
+
yielding a falsely-high floor. The card is therefore a **4-stripe multi-color
|
|
52
|
+
region** (blue/purple/teal/amber), not a single solid block, on every side
|
|
53
|
+
(`h5-twin`, `swiftui-twin`, `swiftui-twin-divergent`).
|
|
54
|
+
`scripts/calibrate-render.mjs` additionally **blocks** (writes `blocked.json`,
|
|
55
|
+
exits 1) if BOTH normalized images are effectively flat (near-zero luma
|
|
56
|
+
variance) — so a flat calibration pair can never produce a trusted floor.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Design Tokens
|
|
61
|
+
|
|
62
|
+
All values are shared across both sides. `tokens.json` is the authoritative
|
|
63
|
+
source; `style.css` and `CalibrationScreen.swift` must match it exactly.
|
|
64
|
+
|
|
65
|
+
### Colors
|
|
66
|
+
|
|
67
|
+
| Token | Hex | CSS var | Swift `Color(red:green:blue:)` |
|
|
68
|
+
|---|---|---|---|
|
|
69
|
+
| `color.background` | `#F2F2F7` | `--color-background` | `r=0.9490 g=0.9490 b=0.9686` |
|
|
70
|
+
| `color.card` | `#4A90D9` | `--color-card` | `r=0.2902 g=0.5647 b=0.8510` |
|
|
71
|
+
| `color.circle` | `#E8744F` | `--color-circle` | `r=0.9098 g=0.4549 b=0.3098` |
|
|
72
|
+
| `color.textHeading` | `#1C1C1E` | `--color-text-heading` | `r=0.1098 g=0.1098 b=0.1176` |
|
|
73
|
+
| `color.textBody` | `#636366` | `--color-text-body` | `r=0.3882 g=0.3882 b=0.4000` |
|
|
74
|
+
| `color.stripeA` | `#4A90D9` | `--color-stripe-a` | `r=0.2902 g=0.5647 b=0.8510` |
|
|
75
|
+
| `color.stripeB` | `#7E57C2` | `--color-stripe-b` | `r=0.4941 g=0.3412 b=0.7608` |
|
|
76
|
+
| `color.stripeC` | `#26A69A` | `--color-stripe-c` | `r=0.1490 g=0.6510 b=0.6039` |
|
|
77
|
+
| `color.stripeD` | `#F4B400` | `--color-stripe-d` | `r=0.9569 g=0.7059 b=0.0000` |
|
|
78
|
+
|
|
79
|
+
The card is a **4 equal-width vertical stripe** region (A→D, left to right),
|
|
80
|
+
not a flat solid — see the textured-content requirement above.
|
|
81
|
+
|
|
82
|
+
### Spacing (CSS px = Swift pt at 1× logical scale)
|
|
83
|
+
|
|
84
|
+
| Token | Value | CSS var | Swift constant |
|
|
85
|
+
|---|---|---|---|
|
|
86
|
+
| `space.safeTop` | 59 px/pt | `--space-safe-top` | `spaceSafeTop = 59` |
|
|
87
|
+
| `space.pageH` | 20 px/pt | `--space-page-h` | `spacePageH = 20` |
|
|
88
|
+
| `space.sectionGap` | 24 px/pt | `--space-section-gap` | `spaceSectionGap = 24` |
|
|
89
|
+
| `space.cardPadding` | 20 px/pt | `--space-card-padding`| `spaceCardPadding = 20` |
|
|
90
|
+
| `space.cardGap` | 16 px/pt | `--space-card-gap` | `spaceCardGap = 16` |
|
|
91
|
+
|
|
92
|
+
### Radii
|
|
93
|
+
|
|
94
|
+
| Token | Value | CSS var | Swift constant |
|
|
95
|
+
|---|---|---|---|
|
|
96
|
+
| `radius.card` | 16 px/pt | `--radius-card` | `radiusCard = 16` |
|
|
97
|
+
|
|
98
|
+
### Typography
|
|
99
|
+
|
|
100
|
+
| Token | Value | CSS | Swift |
|
|
101
|
+
|---|---|---|---|
|
|
102
|
+
| `font.family` | `-apple-system` | `font-family: -apple-system, system-ui` | `.system(size:weight:)` |
|
|
103
|
+
| `font.sizeHeading` | 22 px/pt | `font-size: 22px` | `.system(size: 22, weight: .semibold)` |
|
|
104
|
+
| `font.weightHeading` | 600 / semibold | `font-weight: 600` | `.semibold` |
|
|
105
|
+
| `font.lineHeightHeading` | 1.27× | `line-height: 1.27` | `lineSpacing: 22 × 0.27 ≈ 5.9 pt` |
|
|
106
|
+
| `font.sizeBody` | 15 px/pt | `font-size: 15px` | `.system(size: 15, weight: .regular)` |
|
|
107
|
+
| `font.weightBody` | 400 / regular | `font-weight: 400` | `.regular` |
|
|
108
|
+
| `font.lineHeightBody` | 1.47× | `line-height: 1.47` | `lineSpacing: 15 × 0.47 ≈ 7.1 pt` |
|
|
109
|
+
|
|
110
|
+
### Shape
|
|
111
|
+
|
|
112
|
+
| Token | Value | CSS var | Swift constant |
|
|
113
|
+
|---|---|---|---|
|
|
114
|
+
| `shape.circleSize` | 64 px/pt | `--size-circle` | `sizeCircle = 64` |
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Screen layout (both sides)
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
┌─────────────── 393 pt ───────────────┐
|
|
122
|
+
│ │
|
|
123
|
+
│ ← 59 pt top safe-area inset → │
|
|
124
|
+
│ │
|
|
125
|
+
│ ┌─ 20pt padding ──────────────────┐ │
|
|
126
|
+
│ │ Calibration Screen │ │ ← heading 22pt semibold #1C1C1E
|
|
127
|
+
│ │ This screen is the known-… │ │ ← body 15pt regular #636366
|
|
128
|
+
│ └─────────────────────────────────┘ │
|
|
129
|
+
│ │ ← 24pt gap
|
|
130
|
+
│ ┌─ 20pt padding ──────────────────┐ │
|
|
131
|
+
│ │ ┃A┃B┃C┃D┃ 4-stripe card r=16pt │ │ ← stripes #4A90D9 #7E57C2
|
|
132
|
+
│ │ ┗━┻━┻━┻━┛ (textured, 40pt h) │ │ #26A69A #F4B400
|
|
133
|
+
│ │ ● ← #E8744F circle 64×64pt │ │ ← 16pt gap below card
|
|
134
|
+
│ └─────────────────────────────────┘ │
|
|
135
|
+
│ │
|
|
136
|
+
└───────────────────────────────────────┘
|
|
137
|
+
total height: 852 pt
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## How to run
|
|
143
|
+
|
|
144
|
+
**H5 twin** — open `h5-twin/index.html` directly in a browser. No build step.
|
|
145
|
+
Set browser viewport to 393×852. (Playwright capture uses `--viewport 393x852`.)
|
|
146
|
+
|
|
147
|
+
**SwiftUI twin** (known-correct) — requires Xcode 15+ or Swift 5.9+ with iOS SDK:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
cd swiftui-twin && swift build
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Divergent twin** (negative control) — same toolchain:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
cd swiftui-twin-divergent && swift build
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Preview in Xcode: open either package; the `#Preview` renders the screen in
|
|
160
|
+
an iPhone 15 Pro simulator. `.build/` is gitignored — never commit it.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Updating this pair
|
|
165
|
+
|
|
166
|
+
If any token value is changed:
|
|
167
|
+
1. Update `tokens.json`.
|
|
168
|
+
2. Update the matching `--*` custom property in `h5-twin/style.css`.
|
|
169
|
+
3. Update the matching constant in `swiftui-twin/.../CalibrationScreen.swift`.
|
|
170
|
+
4. Re-run Stage 2.5 calibration to re-measure the floor.
|
|
171
|
+
|
|
172
|
+
The known-correct trio (`tokens.json`, `h5-twin/style.css`,
|
|
173
|
+
`swiftui-twin/.../CalibrationScreen.swift`) must stay in sync; `tokens.json`
|
|
174
|
+
is the single source of truth. The **divergent twin is intentionally NOT in
|
|
175
|
+
sync** — its job is to differ; only keep it textured (text + stripes) and
|
|
176
|
+
buildable.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<!--
|
|
3
|
+
Calibration Twin — h5-twin/index.html
|
|
4
|
+
Known-correct H5 side of the Stage 2.5 render-equivalence calibration pair.
|
|
5
|
+
Open directly as a static file — zero JS framework, zero build step.
|
|
6
|
+
|
|
7
|
+
IMPORTANT: every color, size, and spacing value here is driven by the CSS
|
|
8
|
+
custom properties in style.css, which must remain in sync with
|
|
9
|
+
tokens.json and swiftui-twin/Sources/CalibrationScreen/CalibrationScreen.swift.
|
|
10
|
+
-->
|
|
11
|
+
<html lang="en">
|
|
12
|
+
<head>
|
|
13
|
+
<meta charset="UTF-8" />
|
|
14
|
+
<!--
|
|
15
|
+
Viewport: fixed 393px logical width, no user scaling.
|
|
16
|
+
Matches iPhone 15 Pro logical resolution used in the SwiftUI twin.
|
|
17
|
+
-->
|
|
18
|
+
<meta name="viewport" content="width=393, initial-scale=1.0, user-scalable=no" />
|
|
19
|
+
<title>Calibration Twin</title>
|
|
20
|
+
<link rel="stylesheet" href="style.css" />
|
|
21
|
+
</head>
|
|
22
|
+
<body>
|
|
23
|
+
<div class="screen">
|
|
24
|
+
|
|
25
|
+
<!-- TEXT BLOCK: heading + body paragraph -->
|
|
26
|
+
<section class="text-block" aria-label="text-block">
|
|
27
|
+
<h1 class="text-block__heading">Calibration Screen</h1>
|
|
28
|
+
<p class="text-block__body">
|
|
29
|
+
This screen is the known-correct H5 twin used to measure the
|
|
30
|
+
cross-renderer fidelity floor. It is not a conversion target.
|
|
31
|
+
</p>
|
|
32
|
+
</section>
|
|
33
|
+
|
|
34
|
+
<!-- SHAPE BLOCK: structured (multi-color stripes) card + circle.
|
|
35
|
+
Deliberately NOT a flat solid block — SSIM is insensitive to a
|
|
36
|
+
uniform mean shift on flat content, so the calibration region must
|
|
37
|
+
carry structure for the floor to be meaningful. -->
|
|
38
|
+
<section class="shape-block" aria-label="shape-block">
|
|
39
|
+
<div class="shape-block__card" aria-label="card">
|
|
40
|
+
<div class="shape-block__stripe shape-block__stripe--a"></div>
|
|
41
|
+
<div class="shape-block__stripe shape-block__stripe--b"></div>
|
|
42
|
+
<div class="shape-block__stripe shape-block__stripe--c"></div>
|
|
43
|
+
<div class="shape-block__stripe shape-block__stripe--d"></div>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="shape-block__circle-row">
|
|
46
|
+
<div class="shape-block__circle" aria-label="circle"></div>
|
|
47
|
+
</div>
|
|
48
|
+
</section>
|
|
49
|
+
|
|
50
|
+
</div>
|
|
51
|
+
</body>
|
|
52
|
+
</html>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* Calibration Twin — style.css
|
|
2
|
+
Design tokens as CSS custom properties.
|
|
3
|
+
Every value here MUST match tokens.json and CalibrationScreen.swift exactly.
|
|
4
|
+
Do NOT add, remove, or change values without updating all three files.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* ── Design Tokens ──────────────────────────────────────────────── */
|
|
8
|
+
:root {
|
|
9
|
+
/* colors */
|
|
10
|
+
--color-background: #F2F2F7;
|
|
11
|
+
--color-card: #4A90D9;
|
|
12
|
+
--color-circle: #E8744F;
|
|
13
|
+
--color-text-heading: #1C1C1E;
|
|
14
|
+
--color-text-body: #636366;
|
|
15
|
+
|
|
16
|
+
/* card stripes — structured multi-color region (NOT a flat block) so the
|
|
17
|
+
measured SSIM floor is meaningful (flat content makes SSIM blind to a
|
|
18
|
+
uniform mean shift). */
|
|
19
|
+
--color-stripe-a: #4A90D9; /* blue */
|
|
20
|
+
--color-stripe-b: #7E57C2; /* purple */
|
|
21
|
+
--color-stripe-c: #26A69A; /* teal */
|
|
22
|
+
--color-stripe-d: #F4B400; /* amber */
|
|
23
|
+
|
|
24
|
+
/* spacing */
|
|
25
|
+
--space-safe-top: 59px; /* iPhone 15 Pro top safe-area inset */
|
|
26
|
+
--space-page-h: 20px; /* horizontal page padding */
|
|
27
|
+
--space-section-gap: 24px; /* gap between text block and shape block */
|
|
28
|
+
--space-card-padding: 20px; /* inner padding of the blue card */
|
|
29
|
+
--space-card-gap: 16px; /* gap between card and circle row */
|
|
30
|
+
|
|
31
|
+
/* radii */
|
|
32
|
+
--radius-card: 16px;
|
|
33
|
+
|
|
34
|
+
/* typography */
|
|
35
|
+
--font-family: -apple-system, system-ui, BlinkMacSystemFont, sans-serif;
|
|
36
|
+
--font-size-heading: 22px;
|
|
37
|
+
--font-weight-heading: 600; /* semibold */
|
|
38
|
+
--line-height-heading: 1.27; /* ~28px → matches SF heading leading */
|
|
39
|
+
--font-size-body: 15px;
|
|
40
|
+
--font-weight-body: 400; /* regular */
|
|
41
|
+
--line-height-body: 1.47; /* ~22px → matches SF body leading */
|
|
42
|
+
|
|
43
|
+
/* shape */
|
|
44
|
+
--size-circle: 64px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* ── Reset / Base ───────────────────────────────────────────────── */
|
|
48
|
+
*, *::before, *::after {
|
|
49
|
+
box-sizing: border-box;
|
|
50
|
+
margin: 0;
|
|
51
|
+
padding: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
html, body {
|
|
55
|
+
width: 393px; /* iPhone 15 Pro logical width */
|
|
56
|
+
min-height: 852px; /* iPhone 15 Pro logical height */
|
|
57
|
+
background-color: var(--color-background);
|
|
58
|
+
font-family: var(--font-family);
|
|
59
|
+
-webkit-font-smoothing: antialiased;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* ── Screen container ───────────────────────────────────────────── */
|
|
63
|
+
.screen {
|
|
64
|
+
width: 393px;
|
|
65
|
+
min-height: 852px;
|
|
66
|
+
background-color: var(--color-background);
|
|
67
|
+
padding-top: var(--space-safe-top);
|
|
68
|
+
padding-left: var(--space-page-h);
|
|
69
|
+
padding-right: var(--space-page-h);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* ── Text block ─────────────────────────────────────────────────── */
|
|
73
|
+
.text-block {
|
|
74
|
+
/* sits immediately below safe-area inset, no extra top margin */
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.text-block__heading {
|
|
78
|
+
font-family: var(--font-family);
|
|
79
|
+
font-size: var(--font-size-heading);
|
|
80
|
+
font-weight: var(--font-weight-heading);
|
|
81
|
+
line-height: var(--line-height-heading);
|
|
82
|
+
color: var(--color-text-heading);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.text-block__body {
|
|
86
|
+
margin-top: 8px;
|
|
87
|
+
font-family: var(--font-family);
|
|
88
|
+
font-size: var(--font-size-body);
|
|
89
|
+
font-weight: var(--font-weight-body);
|
|
90
|
+
line-height: var(--line-height-body);
|
|
91
|
+
color: var(--color-text-body);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* ── Shape block ────────────────────────────────────────────────── */
|
|
95
|
+
.shape-block {
|
|
96
|
+
margin-top: var(--space-section-gap);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.shape-block__card {
|
|
100
|
+
background-color: var(--color-card);
|
|
101
|
+
border-radius: var(--radius-card);
|
|
102
|
+
/* fixed height instead of padding-only so the stripes have a stable box;
|
|
103
|
+
2 × card padding (40px) keeps the same overall card height as before. */
|
|
104
|
+
height: calc(var(--space-card-padding) * 2);
|
|
105
|
+
overflow: hidden;
|
|
106
|
+
display: flex;
|
|
107
|
+
flex-direction: row;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* 4 equal-width vertical stripes — a structured, multi-color region. */
|
|
111
|
+
.shape-block__stripe {
|
|
112
|
+
flex: 1 1 25%;
|
|
113
|
+
height: 100%;
|
|
114
|
+
}
|
|
115
|
+
.shape-block__stripe--a { background-color: var(--color-stripe-a); }
|
|
116
|
+
.shape-block__stripe--b { background-color: var(--color-stripe-b); }
|
|
117
|
+
.shape-block__stripe--c { background-color: var(--color-stripe-c); }
|
|
118
|
+
.shape-block__stripe--d { background-color: var(--color-stripe-d); }
|
|
119
|
+
|
|
120
|
+
.shape-block__circle-row {
|
|
121
|
+
margin-top: var(--space-card-gap);
|
|
122
|
+
display: flex;
|
|
123
|
+
flex-direction: row;
|
|
124
|
+
align-items: center;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.shape-block__circle {
|
|
128
|
+
width: var(--size-circle);
|
|
129
|
+
height: var(--size-circle);
|
|
130
|
+
border-radius: 50%;
|
|
131
|
+
background-color: var(--color-circle);
|
|
132
|
+
flex-shrink: 0;
|
|
133
|
+
}
|