stylegallery 0.1.0 → 0.1.2
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/AGENTS.md +4 -1
- package/DOMAINS.md +2 -6
- package/GOVERNANCE.md +10 -9
- package/README.md +29 -127
- package/consumer-reference/agent-native/v2/admission-policy.json +646 -0
- package/consumer-reference/agent-native/v2/material-registry.json +1 -0
- package/consumer-reference/agent-native/v2/schema/admission-policy.schema.json +50 -0
- package/consumer-reference/agent-native/v2/schema/material-manifest.schema.json +17 -0
- package/consumer-reference/agent-native/v2/schema/material-record.schema.json +20 -0
- package/consumer-reference/contract.md +1 -1
- package/consumer-reference/index.md +5 -3
- package/layout/index.md +124 -0
- package/log.md +57 -0
- package/package.json +183 -22
- package/scripts/agent-native/v2/experimental-extension-registry.mjs +143 -0
- package/scripts/agent-native/v2/extensions/a2a-projection.mjs +264 -0
- package/scripts/agent-native/v2/extensions/agui-projection.mjs +191 -0
- package/scripts/agent-native/v2/material-admission.mjs +295 -0
- package/scripts/agent-native/v2/material-cli-adapter.mjs +134 -0
- package/scripts/agent-native/v2/material-context.mjs +251 -0
- package/scripts/agent-native/v2/material-identity.mjs +71 -0
- package/scripts/agent-native/v2/material-mcp-adapter.mjs +253 -0
- package/scripts/agent-native/v2/material-operation-registry.mjs +123 -0
- package/scripts/agent-native/v2/material-queries.mjs +398 -0
- package/scripts/agent-native/v2/material-registry.mjs +319 -0
- package/scripts/sg-material-mcp.mjs +98 -0
- package/scripts/sg-material.mjs +27 -0
- package/consumer-reference/adapters/style-dictionary.config.mjs +0 -36
- package/consumer-reference/baselines/calibration.json +0 -260
- package/consumer-reference/baselines/manifest.json +0 -21
- package/consumer-reference/fixtures/consumer-conformance/e2e-fixture.mjs +0 -282
- package/consumer-reference/fixtures/consumer-conformance/manifest.json +0 -102
- package/consumer-reference/fixtures/consumer-conformance/runtime-proof.mjs +0 -32
- package/consumer-reference/fixtures/consumer-conformance/valid-migration-result.json +0 -18
- package/consumer-reference/fixtures/consumer-conformance/valid-migration.json +0 -142
- package/consumer-reference/fixtures/invalid-stable-ended-support.json +0 -19
- package/consumer-reference/fixtures/promotion/invalid-blocking-evidence.json +0 -26
- package/consumer-reference/fixtures/promotion/invalid-count-only.json +0 -29
- package/consumer-reference/fixtures/promotion/invalid-missing-owner-migration.json +0 -25
- package/consumer-reference/fixtures/promotion/invalid-normative-bypass-no-regression.json +0 -25
- package/consumer-reference/fixtures/promotion/invalid-related-counted-independent.json +0 -45
- package/consumer-reference/fixtures/promotion/invalid-stable-ended-support.json +0 -26
- package/consumer-reference/fixtures/promotion/manifest.json +0 -15
- package/consumer-reference/fixtures/promotion/valid-deferred-example.json +0 -67
- package/consumer-reference/fixtures/promotion/valid-normative-bypass.json +0 -67
- package/consumer-reference/fixtures/token-portability/invalid-cycle.json +0 -7
- package/consumer-reference/fixtures/token-portability/invalid-dangling-alias.json +0 -6
- package/consumer-reference/fixtures/token-portability/invalid-extends.json +0 -4
- package/consumer-reference/fixtures/token-portability/invalid-json-pointer.json +0 -7
- package/consumer-reference/fixtures/token-portability/invalid-resolver.json +0 -9
- package/consumer-reference/fixtures/token-portability/invalid-type-mismatch.json +0 -10
- package/consumer-reference/fixtures/token-portability/invalid-unknown-reserved.json +0 -6
- package/consumer-reference/fixtures/token-portability/invalid-untested-type.json +0 -6
- package/consumer-reference/fixtures/token-portability/valid-border.json +0 -14
- package/consumer-reference/fixtures/token-portability/valid-reference.json +0 -32
- package/consumer-reference/fixtures/token-portability/valid-whole-alias.json +0 -7
- package/consumer-reference/fixtures/valid-deprecated.json +0 -21
- package/consumer-reference/fixtures/valid-experimental.json +0 -19
- package/consumer-reference/generated/manifest.json +0 -40
- package/consumer-reference/generated/tokens.css +0 -12
- package/consumer-reference/policies/shared-experimental.json +0 -37
- package/consumer-reference/schema/ax-evidence.schema.json +0 -30
- package/consumer-reference/schema/baseline-manifest.schema.json +0 -55
- package/consumer-reference/schema/calibration-record.schema.json +0 -190
- package/consumer-reference/schema/capture-session.schema.json +0 -161
- package/consumer-reference/schema/component-state.schema.json +0 -150
- package/consumer-reference/schema/consumer-conformance-record.schema.json +0 -365
- package/consumer-reference/schema/dom-evidence.schema.json +0 -38
- package/consumer-reference/schema/evidence-record.schema.json +0 -81
- package/consumer-reference/schema/fixture-manifest.schema.json +0 -32
- package/consumer-reference/schema/item.schema.json +0 -188
- package/consumer-reference/schema/page-evidence-manifest.schema.json +0 -216
- package/consumer-reference/schema/page-evidence-session.schema.json +0 -119
- package/consumer-reference/schema/portable-tokens.schema.json +0 -104
- package/consumer-reference/schema/promotion-rfc.schema.json +0 -219
- package/consumer-reference/schema/runtime-evidence-manifest.schema.json +0 -33
- package/consumer-reference/schema/visual-evidence.schema.json +0 -31
- package/design-engineering/consumer-migration-readiness.md +0 -124
- package/design-engineering/interface-craft.md +0 -107
- package/design-engineering/reference-profiles/external-adaptation/index.md +0 -12
- package/design-engineering/reference-profiles/governed-local/editorial/components/button.component.json +0 -125
- package/design-engineering/reference-profiles/governed-local/editorial/evidence/button.evidence.json +0 -3504
- package/design-engineering/reference-profiles/governed-local/editorial/fixtures/button.fixture.json +0 -65
- package/design-engineering/reference-profiles/governed-local/editorial/generated/evidence-coverage.md +0 -23
- package/design-engineering/reference-profiles/governed-local/editorial/generated/keyboard-matrix.md +0 -19
- package/design-engineering/reference-profiles/governed-local/editorial/generated/state-matrix.md +0 -21
- package/design-engineering/reference-profiles/governed-local/editorial/local-foundations.json +0 -12
- package/design-engineering/reference-profiles/governed-local/editorial/states/button.states.json +0 -195
- package/design-engineering/reference-profiles/governed-local/editorial/tokens.dtcg.json +0 -17
- package/design-engineering/reference-profiles/governed-local/terminal/components/button.component.json +0 -125
- package/design-engineering/reference-profiles/governed-local/terminal/evidence/button.evidence.json +0 -3504
- package/design-engineering/reference-profiles/governed-local/terminal/fixtures/button.fixture.json +0 -65
- package/design-engineering/reference-profiles/governed-local/terminal/generated/evidence-coverage.md +0 -23
- package/design-engineering/reference-profiles/governed-local/terminal/generated/keyboard-matrix.md +0 -19
- package/design-engineering/reference-profiles/governed-local/terminal/generated/state-matrix.md +0 -21
- package/design-engineering/reference-profiles/governed-local/terminal/local-foundations.json +0 -12
- package/design-engineering/reference-profiles/governed-local/terminal/profile.json +0 -43
- package/design-engineering/reference-profiles/governed-local/terminal/states/button.states.json +0 -195
- package/design-engineering/reference-profiles/governed-local/terminal/tokens.dtcg.json +0 -17
- package/game-ui/classification.md +0 -82
- package/game-ui/reference-record.md +0 -62
- package/game-ui/screen-hierarchy.md +0 -107
- package/game-ui/unity/architecture.md +0 -166
- package/game-ui/unity/cli-loop.md +0 -84
- package/game-ui/unity/data/unity-technologies-public-repositories.json +0 -26654
- package/game-ui/unity/org-wiki.md +0 -146
- package/game-ui/unity/repository-map.md +0 -102
- package/game-ui/unity/ui-systems.md +0 -85
- package/motion/practice-reference.md +0 -145
- package/motion/review-workflow.md +0 -86
- package/motion/vocabulary.md +0 -82
- package/platform-guides/apple-interaction.md +0 -89
- package/scripts/agent-native/events.mjs +0 -113
- package/scripts/agent-native/immutable-store.mjs +0 -102
- package/scripts/artifact-metadata.mjs +0 -20
- package/scripts/audit-evidence-freshness.mjs +0 -308
- package/scripts/baseline-contract.mjs +0 -189
- package/scripts/baseline-schema-parity.mjs +0 -40
- package/scripts/build-reference-artifacts.mjs +0 -127
- package/scripts/calibration-raw-contract.mjs +0 -172
- package/scripts/capture-session-contract.mjs +0 -187
- package/scripts/component-state-artifact-fixture.mjs +0 -44
- package/scripts/component-state-contract.mjs +0 -99
- package/scripts/component-state-semantics.mjs +0 -128
- package/scripts/component-state-workflow-contract.mjs +0 -67
- package/scripts/component-state-workflow-negative-cases.mjs +0 -64
- package/scripts/consumer-conformance-contract.mjs +0 -198
- package/scripts/consumer-evidence-governance-contract.mjs +0 -210
- package/scripts/consumer-reference-case-runner.mjs +0 -93
- package/scripts/consumer-reference-schema.mjs +0 -155
- package/scripts/create-component-state-session.mjs +0 -100
- package/scripts/create-page-evidence-session.mjs +0 -139
- package/scripts/domain-document-boundaries.mjs +0 -40
- package/scripts/domain-validation-checks.mjs +0 -141
- package/scripts/evidence-artifact-contract.mjs +0 -191
- package/scripts/finalize-component-state-evidence.mjs +0 -165
- package/scripts/finalize-page-evidence.mjs +0 -197
- package/scripts/generate-consumer-reference-evidence.mjs +0 -154
- package/scripts/generate-patterns.mjs +0 -218
- package/scripts/governance-matrix-contract.mjs +0 -73
- package/scripts/governance-matrix-negative-cases.mjs +0 -114
- package/scripts/governance-policy-contract.mjs +0 -49
- package/scripts/governance-test-fixture.mjs +0 -321
- package/scripts/governance-workflow-negative-cases.mjs +0 -241
- package/scripts/governed-profile-registry.mjs +0 -125
- package/scripts/json-schema-formats.mjs +0 -31
- package/scripts/markdown-structure.mjs +0 -45
- package/scripts/page-artifact-metadata.mjs +0 -124
- package/scripts/page-evidence-contract.mjs +0 -297
- package/scripts/page-evidence-fixture.mjs +0 -271
- package/scripts/pattern-data.mjs +0 -325
- package/scripts/profile-record-contract.mjs +0 -140
- package/scripts/promotion-attestation-contract.mjs +0 -91
- package/scripts/promotion-boundary-test-contract.mjs +0 -92
- package/scripts/promotion-fixture-inventory.mjs +0 -109
- package/scripts/promotion-governance-contract.mjs +0 -28
- package/scripts/reference-artifact-path-contract.mjs +0 -28
- package/scripts/reference-profile-contract.mjs +0 -114
- package/scripts/reference-token-contract.mjs +0 -156
- package/scripts/run-consumer-page-evidence-ci.mjs +0 -170
- package/scripts/summarize-sentinel-calibration.mjs +0 -98
- package/scripts/test-agent-adapter-conformance.mjs +0 -250
- package/scripts/test-agent-conformance-receipt.mjs +0 -106
- package/scripts/test-agent-events.mjs +0 -81
- package/scripts/test-agent-execution-effects.mjs +0 -114
- package/scripts/test-agent-execution-fixtures.mjs +0 -140
- package/scripts/test-agent-execution-kernel.mjs +0 -39
- package/scripts/test-agent-execution-learning.mjs +0 -130
- package/scripts/test-agent-execution-lifecycle.mjs +0 -143
- package/scripts/test-agent-execution-safety.mjs +0 -158
- package/scripts/test-agent-execution-views.mjs +0 -117
- package/scripts/test-agent-identity-integrity-cases.mjs +0 -160
- package/scripts/test-agent-knowledge-kernel.mjs +0 -183
- package/scripts/test-agent-learning.mjs +0 -246
- package/scripts/test-agent-mcp.mjs +0 -246
- package/scripts/test-agent-native-schemas.mjs +0 -215
- package/scripts/test-agent-projections.mjs +0 -249
- package/scripts/test-agent-registry-mcp-integrity.mjs +0 -215
- package/scripts/test-agent-registry-mutations.mjs +0 -110
- package/scripts/test-audit-evidence-freshness.mjs +0 -177
- package/scripts/test-component-state-sentinel.mjs +0 -35
- package/scripts/test-component-state-source-contract.mjs +0 -83
- package/scripts/test-consumer-conformance-sentinel.mjs +0 -165
- package/scripts/test-consumer-reference-sentinel.mjs +0 -31
- package/scripts/test-generate-consumer-reference-evidence.mjs +0 -124
- package/scripts/test-json-cli-output.mjs +0 -151
- package/scripts/test-json-schema-formats.mjs +0 -40
- package/scripts/test-reference-adapters.mjs +0 -199
- package/scripts/test-renderer-purity.mjs +0 -34
- package/scripts/test-sg-cli.mjs +0 -129
- package/scripts/test-summarize-sentinel-calibration.mjs +0 -226
- package/scripts/test-validate-baseline-manifest.mjs +0 -234
- package/scripts/test-validate-component-state-artifacts.mjs +0 -243
- package/scripts/test-validate-component-state.mjs +0 -106
- package/scripts/test-validate-consumer-conformance.mjs +0 -427
- package/scripts/test-validate-consumer-reference-cli.mjs +0 -69
- package/scripts/test-validate-consumer-reference.mjs +0 -263
- package/scripts/test-validate-domains.mjs +0 -357
- package/scripts/test-validate-governance.mjs +0 -292
- package/scripts/test-validate-ia.mjs +0 -262
- package/scripts/test-validate-okf.mjs +0 -73
- package/scripts/test-validate-page-evidence.mjs +0 -302
- package/scripts/test-validate-patterns.mjs +0 -157
- package/scripts/test-validate-promotion-rfc.mjs +0 -250
- package/scripts/test-validate-reference-profiles.mjs +0 -170
- package/scripts/test-validate-unity-org-wiki.mjs +0 -57
- package/scripts/test-validate-unity-source-contracts.mjs +0 -67
- package/scripts/test-validate-vocabulary.mjs +0 -174
- package/scripts/test-validate-webpage-workflow.mjs +0 -293
- package/scripts/validate-baseline-manifest.mjs +0 -44
- package/scripts/validate-catalog.mjs +0 -65
- package/scripts/validate-component-state.mjs +0 -141
- package/scripts/validate-consumer-conformance.mjs +0 -477
- package/scripts/validate-consumer-reference.mjs +0 -288
- package/scripts/validate-domains.mjs +0 -237
- package/scripts/validate-governance.mjs +0 -248
- package/scripts/validate-ia.mjs +0 -136
- package/scripts/validate-links.mjs +0 -66
- package/scripts/validate-okf.mjs +0 -104
- package/scripts/validate-page-evidence.mjs +0 -191
- package/scripts/validate-patterns.mjs +0 -246
- package/scripts/validate-promotion-rfc.mjs +0 -224
- package/scripts/validate-reference-artifacts.mjs +0 -125
- package/scripts/validate-renderer-purity.mjs +0 -56
- package/scripts/validate-unity-org-wiki.mjs +0 -146
- package/scripts/validate-unity-source-contracts.mjs +0 -107
- package/scripts/validate-vocabulary.mjs +0 -115
- package/scripts/validate-webpage-workflow.mjs +0 -254
- package/scripts/visual-expectation-contract.mjs +0 -20
- package/scripts/workflow-action-contract.mjs +0 -163
package/motion/vocabulary.md
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: Domain Guide
|
|
3
|
-
title: Motion Vocabulary
|
|
4
|
-
description: Evidence-bounded method and reference for naming observable interface motion.
|
|
5
|
-
domain: motion
|
|
6
|
-
lifecycle: experimental
|
|
7
|
-
source_repository: https://github.com/emilkowalski/skills
|
|
8
|
-
source_path: skills/animation-vocabulary/SKILL.md
|
|
9
|
-
source_revision: 220e8607c90b17337d210125777b7b695f26c221
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
# Motion Vocabulary
|
|
13
|
-
|
|
14
|
-
Primary role: motion terminology reference.
|
|
15
|
-
|
|
16
|
-
## Repository Boundary
|
|
17
|
-
|
|
18
|
-
This page helps a reader name observed motion. It does not prescribe implementation, authorize motion in reusable Layout CSS, or make a product-quality judgment.
|
|
19
|
-
|
|
20
|
-
The terms are implementation-neutral. A framework, operating-system behavior, or branded example may illustrate a term only when clearly labeled and separately verified.
|
|
21
|
-
|
|
22
|
-
## Reusable Method
|
|
23
|
-
|
|
24
|
-
1. Record what changes: presence, position, scale, shape, state, scroll relationship, or feedback.
|
|
25
|
-
2. Record what coordinates the change: time, sequence, input, velocity, or viewport progress.
|
|
26
|
-
3. Compare the observation with the closest term families below.
|
|
27
|
-
4. Return one exact term only when the observed cues distinguish it.
|
|
28
|
-
5. When multiple terms remain plausible, return ordered candidates and state the missing observation.
|
|
29
|
-
6. When nothing matches, return `unknown`; do not invent a canonical winner.
|
|
30
|
-
|
|
31
|
-
## Term Families
|
|
32
|
-
|
|
33
|
-
| Term | Observed cues | Distinguish from | Implementation-neutral meaning | Evidence boundary |
|
|
34
|
-
| --- | --- | --- | --- | --- |
|
|
35
|
-
| Fade | Visibility changes without a necessary spatial path. | Reveal | A gradual visibility change. | Does not imply opacity is the implementation. |
|
|
36
|
-
| Slide | The element follows a directional path into, out of, or within a region. | Shared-element transition | A positional transition without necessarily preserving identity across views. | Direction and clipping must be observed. |
|
|
37
|
-
| Scale transition | Apparent size changes around an origin. | Morph | Size changes while the element's basic identity remains stable. | Does not establish the correct origin or amount. |
|
|
38
|
-
| Reveal | A boundary progressively exposes content. | Fade | Visibility is controlled by an advancing edge, mask, or equivalent boundary. | The masking mechanism may be unknown. |
|
|
39
|
-
| Stagger | Similar elements begin related changes at distinct offsets. | Orchestration | A repeated sequence pattern, usually across peers. | The offset value is product-specific. |
|
|
40
|
-
| Orchestration | Several motion events form one coordinated sequence. | Stagger | Coordination may include different elements, jobs, and timings. | Intent must be documented, not inferred from timing alone. |
|
|
41
|
-
| Crossfade | One state loses visibility while another gains it in the same region. | Morph | Identity is exchanged rather than geometrically transformed. | Overlap and source order need inspection. |
|
|
42
|
-
| Shared-element transition | A recognizable element appears to retain identity between states or views. | Layout animation | Continuity connects a source representation with a destination representation. | Identity continuity is a perception claim requiring rendered evidence. |
|
|
43
|
-
| Layout animation | A spatial change is visually interpolated instead of appearing instantly. | Shared-element transition | Position or size changes within the layout state of an element. | Does not endorse animating layout-triggering CSS properties. |
|
|
44
|
-
| Scroll-driven motion | Progress corresponds to scroll progress. | Scroll reveal | The scroll position continuously controls progress rather than merely triggering entry. | Browser and input behavior require local testing. |
|
|
45
|
-
| Parallax | Layers appear to travel at different rates during a shared movement. | Ordinary scroll | Relative speed creates a depth cue. | Depth, comfort, and reduced-motion outcomes are not guaranteed. |
|
|
46
|
-
| Spring motion | Response is modeled as a target-seeking dynamic system rather than a fixed timeline. | Bounce | A spring may settle without visible overshoot. | Parameters and perceived duration remain implementation-specific. |
|
|
47
|
-
| Bounce | Motion overshoots or reverses before settling. | Spring motion | Visible overshoot is the defining cue, regardless of implementation. | Playfulness and appropriateness are product judgments. |
|
|
48
|
-
| Interruptible motion | New input redirects a change from its current presented state. | Restarted animation | Continuity is maintained when the target changes mid-flight. | Requires interaction evidence, not source inspection alone. |
|
|
49
|
-
| Rubber-band response | Movement continues beyond a boundary with increasing resistance, then returns. | Bounce | Resistance is tied to boundary overshoot and direct manipulation. | Platform examples are not a universal physics contract. |
|
|
50
|
-
| Jank | Motion visibly misses expected visual continuity. | Intentional stepped motion | The discontinuity is unintended and associated with delivery or computation limits. | Frame or performance evidence is needed to attribute cause. |
|
|
51
|
-
|
|
52
|
-
## Opinionated Guidance
|
|
53
|
-
|
|
54
|
-
The family ordering favors what a reader can observe before implementation details. It is useful for retrieval, but it is not a complete ontology. Add a term only after a reader task demonstrates that existing terms and aliases cannot express the distinction.
|
|
55
|
-
|
|
56
|
-
## Platform-Specific Guidance
|
|
57
|
-
|
|
58
|
-
Names tied to iOS, macOS, a browser API, Motion, Framer Motion, React, or a component library are examples or implementation facets. Keep the cross-platform term primary and label the platform context separately.
|
|
59
|
-
|
|
60
|
-
## Unsupported Absolutes
|
|
61
|
-
|
|
62
|
-
- Do not call this vocabulary authoritative outside StyleGallery.
|
|
63
|
-
- Do not force the nearest term when the observation is incomplete.
|
|
64
|
-
- Do not attach universal FPS, GPU, duration, easing, or reduced-motion rules to a definition.
|
|
65
|
-
- Do not infer implementation technology from rendered appearance alone.
|
|
66
|
-
|
|
67
|
-
## Verification Contract
|
|
68
|
-
|
|
69
|
-
A vocabulary lookup should exercise exact, ambiguous, and unknown cases. Pass requires one justified term, an ordered candidate set with a stated distinction, or `unknown`; invented winners fail. A new term also requires a findability task showing the current route cannot reach an adequate term within two hops.
|
|
70
|
-
|
|
71
|
-
## Source, License, And Attribution
|
|
72
|
-
|
|
73
|
-
- Upstream inspiration: [animation-vocabulary/SKILL.md](https://github.com/emilkowalski/skills/blob/220e8607c90b17337d210125777b7b695f26c221/skills/animation-vocabulary/SKILL.md)
|
|
74
|
-
- Snapshot: `220e8607c90b17337d210125777b7b695f26c221`
|
|
75
|
-
- Upstream license: MIT, Copyright (c) 2026 Emil Kowalski.
|
|
76
|
-
- Reuse form: independent method rewrite; upstream prose, tables, code, examples, and distinctive ordering were not retained.
|
|
77
|
-
- Evidence boundary: the upstream artifact records practitioner terminology; it does not prove local performance, accessibility, usability, or quality.
|
|
78
|
-
|
|
79
|
-
## IA Navigation
|
|
80
|
-
|
|
81
|
-
Parent: [Motion](index.md).
|
|
82
|
-
Next: [Motion Review Workflow](review-workflow.md).
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: Domain Guide
|
|
3
|
-
title: Apple Interaction As A Comparative Reference
|
|
4
|
-
description: Bounded comparison of Apple interaction themes with explicit web-adaptation and provenance limits.
|
|
5
|
-
domain: platform-guides
|
|
6
|
-
lifecycle: experimental
|
|
7
|
-
source_repository: https://github.com/emilkowalski/skills
|
|
8
|
-
source_path: skills/apple-design/SKILL.md
|
|
9
|
-
source_revision: 220e8607c90b17337d210125777b7b695f26c221
|
|
10
|
-
platform: Apple platforms
|
|
11
|
-
platform_version: verify-current
|
|
12
|
-
reviewed_on: 2026-07-11
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
# Apple Interaction As A Comparative Reference
|
|
16
|
-
|
|
17
|
-
Primary role: platform comparison guide.
|
|
18
|
-
|
|
19
|
-
## Repository Boundary
|
|
20
|
-
|
|
21
|
-
This page uses selected Apple-platform interaction themes as comparative questions. It does not reproduce Apple guidance, establish affiliation, prescribe imitation, or treat a native implementation value as valid for the web.
|
|
22
|
-
|
|
23
|
-
Current official Apple documentation is required for Apple-specific claims. Current web standards and browser documentation are required for web adaptation. Local rendered, device, accessibility, and performance evidence is required for product conclusions.
|
|
24
|
-
|
|
25
|
-
## Reusable Method
|
|
26
|
-
|
|
27
|
-
For each proposed comparison:
|
|
28
|
-
|
|
29
|
-
1. Name the user task, platform, OS/API version, input method, and state transition.
|
|
30
|
-
2. Describe the observable behavior without branded terminology.
|
|
31
|
-
3. Identify the platform convention and its current official source.
|
|
32
|
-
4. Separate the reusable interaction question from native implementation details.
|
|
33
|
-
5. Define the web adaptation, including unavailable or materially different capabilities.
|
|
34
|
-
6. Verify the adapted behavior on its real surface and record what remains unproven.
|
|
35
|
-
|
|
36
|
-
## Comparative Questions
|
|
37
|
-
|
|
38
|
-
| Theme | Question to investigate | Required evidence | Boundary |
|
|
39
|
-
| --- | --- | --- | --- |
|
|
40
|
-
| Response | Does feedback begin close enough to input to preserve cause and effect? | Interaction recording and input-state trace | No universal latency value is implied. |
|
|
41
|
-
| Direct manipulation | Does the presented state follow, cancel, and resume from user input coherently? | Repeated drag/reversal test on target input modes | One-to-one tracking is not always required. |
|
|
42
|
-
| Interruption | Can new input redirect a transition without jumping or locking control? | Mid-transition retarget and reversal evidence | Springs are one option, not a requirement. |
|
|
43
|
-
| Velocity continuity | Does release-to-settle behavior avoid an observable seam? | Gesture and presented-state recording | Native velocity APIs and web libraries differ. |
|
|
44
|
-
| Spatial consistency | Can the reader understand where content came from and where it returns? | Before/intermediate/after render plus source/focus order | Visual path cannot override semantic order. |
|
|
45
|
-
| Recoverability | Can a user cancel, reverse, undo, or safely recover where the task requires it? | Task and error-path evidence | Confirmation is not universally preferable to undo. |
|
|
46
|
-
| Wayfinding | Can the interface answer location, available destinations, contents, and exit? | Navigation task evidence | Familiar platform placement may not transfer across products. |
|
|
47
|
-
| Soft boundaries | Would progressive resistance communicate a limit better than a hard stop? | Comparative prototype and input/device evidence | The resistance curve is not standardized across platforms. |
|
|
48
|
-
| Multimodal feedback | Do visual, audio, and haptic cues share a clear cause and useful purpose? | Device timing and accessibility evidence | Web haptics/audio are not native equivalents and may be unavailable. |
|
|
49
|
-
| Adaptive presentation | Does the interface remain usable across text size, contrast, transparency, motion preference, input, and viewport changes? | Relevant preference and constraint matrix | A platform feature name does not prove web accessibility. |
|
|
50
|
-
|
|
51
|
-
## Opinionated Guidance
|
|
52
|
-
|
|
53
|
-
Momentum-aware settling, source-anchored transitions, progressive boundary resistance, and carefully coordinated feedback can be useful hypotheses for directly manipulated interfaces. Translucent materials, system typography, haptics, and visual delight are product and platform choices outside reusable Layout pattern CSS.
|
|
54
|
-
|
|
55
|
-
## Platform-Specific Guidance
|
|
56
|
-
|
|
57
|
-
- iOS/macOS gesture physics, native spring APIs, Dynamic Type, system materials, haptics, and SwiftUI/UIKit behavior must be labeled as Apple-specific.
|
|
58
|
-
- Any value described as shipped by Apple requires a direct, current official source and version.
|
|
59
|
-
- A web mapping must identify browser support, input differences, accessibility behavior, and fallback semantics.
|
|
60
|
-
- `backdrop-filter`, the Vibration API, web media queries, and JavaScript animation libraries are not equivalents merely because they can approximate one visible effect.
|
|
61
|
-
|
|
62
|
-
## Unsupported Absolutes
|
|
63
|
-
|
|
64
|
-
- Do not call an upstream formula or parameter an exact Apple implementation without a primary official source.
|
|
65
|
-
- Do not require direct manipulation to track one-to-one in every context.
|
|
66
|
-
- Do not require audio and haptic events on one exact frame as a universal web contract.
|
|
67
|
-
- Do not claim translucent chrome is generally superior to opaque structure.
|
|
68
|
-
- Do not adopt a single spring configuration as a safe default across tasks.
|
|
69
|
-
- Do not import a named set of Apple principles as StyleGallery's shared principles.
|
|
70
|
-
- Do not infer native behavior, platform affiliation, or accessibility from visual similarity.
|
|
71
|
-
|
|
72
|
-
## Verification Contract
|
|
73
|
-
|
|
74
|
-
Record the official platform source and version, the web-standard or browser source for adaptation, the exact target devices and input modes, relevant user preferences, and the observed pass/fail behavior. Use a real interactive prototype for interaction claims. State explicitly when native behavior cannot be reproduced or verified on the web.
|
|
75
|
-
|
|
76
|
-
Review this page when Apple changes the cited convention, the web platform changes the adaptation surface, the source revision changes, or local testing contradicts the guidance. `platform_version: verify-current` prevents this experimental page from masquerading as a version-pinned platform contract.
|
|
77
|
-
|
|
78
|
-
## Source, License, And Attribution
|
|
79
|
-
|
|
80
|
-
- Upstream inspiration: [apple-design/SKILL.md](https://github.com/emilkowalski/skills/blob/220e8607c90b17337d210125777b7b695f26c221/skills/apple-design/SKILL.md)
|
|
81
|
-
- Snapshot: `220e8607c90b17337d210125777b7b695f26c221`
|
|
82
|
-
- Upstream license: MIT, Copyright (c) 2026 Emil Kowalski.
|
|
83
|
-
- Reuse form: independent method rewrite; upstream prose, tables, code, exact-value sequences, Apple/WWDC-derived expression, and quotations were not retained.
|
|
84
|
-
- Evidence boundary: the upstream artifact is a practitioner interpretation and provenance record, not an official Apple or web-platform source.
|
|
85
|
-
|
|
86
|
-
## IA Navigation
|
|
87
|
-
|
|
88
|
-
Parent: [Platform Guides](index.md).
|
|
89
|
-
Next: [Layout](../layout/index.md).
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { cloneAndFreeze, canonicalize, hashCanonical } from "./canonical-json.mjs";
|
|
2
|
-
|
|
3
|
-
function sourceObject(value, name) {
|
|
4
|
-
if (Array.isArray(value)) return { events: value };
|
|
5
|
-
if (!value || typeof value !== "object") throw new TypeError(`${name} expects an object`);
|
|
6
|
-
return value;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function pick(value, ...keys) {
|
|
10
|
-
if (!value || typeof value !== "object") return undefined;
|
|
11
|
-
for (const key of keys) if (Object.hasOwn(value, key)) return value[key];
|
|
12
|
-
return undefined;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function eventId(event) {
|
|
16
|
-
return pick(event, "event_id", "eventId", "id", "stable_ref", "stableRef");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function parentIds(event) {
|
|
20
|
-
const parents = pick(event, "parents", "parent_ids", "parentIds");
|
|
21
|
-
if (parents === undefined || parents === null) return [];
|
|
22
|
-
if (!Array.isArray(parents)) throw new TypeError("event parents must be an array");
|
|
23
|
-
return [...new Set(parents.map((parent) => {
|
|
24
|
-
if (typeof parent !== "string" || parent.length === 0) throw new TypeError("event parent IDs must be non-empty strings");
|
|
25
|
-
return parent;
|
|
26
|
-
}))].sort();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function canonicalFreeze(value) {
|
|
30
|
-
return cloneAndFreeze(JSON.parse(canonicalize(value)));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function normalizeEvent(input) {
|
|
34
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) throw new TypeError("event must be an object");
|
|
35
|
-
const copy = structuredClone(input);
|
|
36
|
-
const id = eventId(copy);
|
|
37
|
-
if (id !== undefined && (typeof id !== "string" || id.length === 0)) throw new TypeError("event ID must be a non-empty string");
|
|
38
|
-
const stableRef = pick(copy, "stable_ref", "stableRef");
|
|
39
|
-
const parents = parentIds(copy);
|
|
40
|
-
delete copy.eventId;
|
|
41
|
-
delete copy.event_id;
|
|
42
|
-
delete copy.parentIds;
|
|
43
|
-
delete copy.parent_ids;
|
|
44
|
-
delete copy.parents;
|
|
45
|
-
delete copy.id;
|
|
46
|
-
delete copy.stableRef;
|
|
47
|
-
delete copy.stable_ref;
|
|
48
|
-
const body = { ...copy, parents };
|
|
49
|
-
if (stableRef !== undefined) body.stable_ref = stableRef;
|
|
50
|
-
const stableId = typeof id === "string" && id.length > 0 ? id : `sg:event/${hashCanonical(body).slice("sha256:".length)}`;
|
|
51
|
-
return { event_id: stableId, parents, ...body };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function normalizedEvents(value) {
|
|
55
|
-
const source = sourceObject(value, "event collection");
|
|
56
|
-
const events = pick(source, "events", "items", "entries");
|
|
57
|
-
if (!Array.isArray(events)) throw new TypeError("events must be an array");
|
|
58
|
-
const result = [];
|
|
59
|
-
const byId = new Map();
|
|
60
|
-
for (const item of events) {
|
|
61
|
-
const normalized = normalizeEvent(item);
|
|
62
|
-
const id = normalized.event_id;
|
|
63
|
-
const previous = byId.get(id);
|
|
64
|
-
if (previous) {
|
|
65
|
-
if (canonicalize(previous) !== canonicalize(normalized)) throw new TypeError(`event ${id} is immutable`);
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
byId.set(id, normalized);
|
|
69
|
-
result.push(normalized);
|
|
70
|
-
}
|
|
71
|
-
const ids = new Set(result.map((item) => item.event_id));
|
|
72
|
-
const visiting = new Set();
|
|
73
|
-
const visited = new Set();
|
|
74
|
-
const eventById = new Map(result.map((item) => [item.event_id, item]));
|
|
75
|
-
const visit = (id) => {
|
|
76
|
-
if (visiting.has(id)) throw new TypeError(`event cycle includes ${id}`);
|
|
77
|
-
if (visited.has(id)) return;
|
|
78
|
-
visiting.add(id);
|
|
79
|
-
for (const parent of eventById.get(id).parents) if (eventById.has(parent)) visit(parent);
|
|
80
|
-
visiting.delete(id);
|
|
81
|
-
visited.add(id);
|
|
82
|
-
};
|
|
83
|
-
for (const id of ids) visit(id);
|
|
84
|
-
return result;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Append one event to an immutable causal event collection. Existing IDs are
|
|
89
|
-
* idempotent only when their canonical bytes are identical; a changed payload
|
|
90
|
-
* is rejected rather than silently rewriting history.
|
|
91
|
-
*/
|
|
92
|
-
export function appendEvent(input) {
|
|
93
|
-
const source = sourceObject(input, "appendEvent");
|
|
94
|
-
const existing = normalizedEvents(source);
|
|
95
|
-
const appended = normalizeEvent(pick(source, "event") ?? source);
|
|
96
|
-
const existingById = new Map(existing.map((item) => [item.event_id, item]));
|
|
97
|
-
const previous = existingById.get(appended.event_id);
|
|
98
|
-
if (previous && canonicalize(previous) !== canonicalize(appended)) throw new TypeError(`event ${appended.event_id} is immutable`);
|
|
99
|
-
if (previous) return canonicalFreeze(existing);
|
|
100
|
-
return canonicalFreeze(normalizedEvents({ events: [...existing, appended] }));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export const appendCausalEvent = appendEvent;
|
|
104
|
-
|
|
105
|
-
/** Return the deterministic leaf IDs of an append-only causal DAG. */
|
|
106
|
-
export function eventHeads(input) {
|
|
107
|
-
const events = normalizedEvents(input);
|
|
108
|
-
const ids = new Set(events.map((item) => item.event_id));
|
|
109
|
-
const referenced = new Set(events.flatMap((item) => item.parents.filter((parent) => ids.has(parent))));
|
|
110
|
-
return canonicalFreeze([...ids].filter((id) => !referenced.has(id)).sort());
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export const getEventHeads = eventHeads;
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { canonicalize, cloneAndFreeze, deepFreeze } from "./canonical-json.mjs";
|
|
2
|
-
import { parseStableRef, parseVersionId } from "./identity.mjs";
|
|
3
|
-
|
|
4
|
-
export class ImmutableStoreError extends TypeError {
|
|
5
|
-
constructor(code, message, path = "") {
|
|
6
|
-
super(message);
|
|
7
|
-
this.name = "ImmutableStoreError";
|
|
8
|
-
this.code = code;
|
|
9
|
-
if (path) this.path = path;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function fail(code, message, path) {
|
|
14
|
-
throw new ImmutableStoreError(code, message, path);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function recordRef(record) {
|
|
18
|
-
const stable_ref = record?.stable_ref ?? record?.stableRef;
|
|
19
|
-
const version_id = record?.version_id ?? record?.versionId;
|
|
20
|
-
if (typeof stable_ref !== "string") fail("store_stable_ref_required", "append requires a StableRef", "stable_ref");
|
|
21
|
-
if (typeof version_id !== "string") fail("store_version_id_required", "append requires a VersionID", "version_id");
|
|
22
|
-
parseStableRef(stable_ref);
|
|
23
|
-
parseVersionId({ version_id, stable_ref, payload: record });
|
|
24
|
-
return { stable_ref, version_id };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function cloneRecord(value) {
|
|
28
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) fail("store_record_invalid", "append requires an object record");
|
|
29
|
-
try { canonicalize(value); } catch (error) { fail(error.code ?? "store_record_invalid", error.message); }
|
|
30
|
-
return cloneAndFreeze(value);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function compare(left, right) {
|
|
34
|
-
if (left < right) return -1;
|
|
35
|
-
if (left > right) return 1;
|
|
36
|
-
return 0;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Create an append-only in-memory store exposing only frozen copies. */
|
|
40
|
-
export function createImmutableStore(input = {}) {
|
|
41
|
-
const byVersion = new Map();
|
|
42
|
-
const byStableRef = new Map();
|
|
43
|
-
const initial = input.entries ?? input.records ?? [];
|
|
44
|
-
if (!Array.isArray(initial)) fail("store_entries_required", "store entries must be an array", "entries");
|
|
45
|
-
|
|
46
|
-
const append = (candidate) => {
|
|
47
|
-
const value = !candidate?.stable_ref && !candidate?.stableRef
|
|
48
|
-
? (candidate?.object ?? candidate?.record ?? candidate?.value ?? candidate)
|
|
49
|
-
: candidate;
|
|
50
|
-
const { stable_ref, version_id } = recordRef(value);
|
|
51
|
-
const frozen = cloneRecord(value);
|
|
52
|
-
const existing = byVersion.get(version_id);
|
|
53
|
-
if (existing) {
|
|
54
|
-
if (canonicalize(existing) !== canonicalize(frozen)) fail("store_version_conflict", "VersionID is already bound to different immutable bytes", "version_id");
|
|
55
|
-
return existing;
|
|
56
|
-
}
|
|
57
|
-
byVersion.set(version_id, frozen);
|
|
58
|
-
const versions = byStableRef.get(stable_ref) ?? [];
|
|
59
|
-
byStableRef.set(stable_ref, [...versions, frozen]);
|
|
60
|
-
return frozen;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
for (const entry of initial) append(entry);
|
|
64
|
-
|
|
65
|
-
const entries = () => [...byVersion.values()].sort((left, right) => compare(left.stable_ref ?? left.stableRef, right.stable_ref ?? right.stableRef) || compare(left.version_id ?? left.versionId, right.version_id ?? right.versionId));
|
|
66
|
-
const resolve = (reference) => {
|
|
67
|
-
const value = typeof reference === "string" ? reference : reference?.stable_ref ?? reference?.stableRef ?? reference?.version_id ?? reference?.versionId;
|
|
68
|
-
if (typeof value !== "string") fail("store_reference_required", "resolve requires a StableRef or VersionID");
|
|
69
|
-
if (value.includes("@sha256:")) {
|
|
70
|
-
parseVersionId(value);
|
|
71
|
-
return byVersion.get(value);
|
|
72
|
-
}
|
|
73
|
-
try { parseStableRef(value); } catch (error) { fail(error.code ?? "store_reference_invalid", error.message); }
|
|
74
|
-
const versions = byStableRef.get(value) ?? [];
|
|
75
|
-
return versions.length === 0 ? undefined : versions[versions.length - 1];
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const snapshot = () => deepFreeze({ entries: entries(), size: byVersion.size });
|
|
79
|
-
return deepFreeze({
|
|
80
|
-
append,
|
|
81
|
-
get: resolve,
|
|
82
|
-
resolve,
|
|
83
|
-
has: (reference) => resolve(reference) !== undefined,
|
|
84
|
-
entries: snapshot,
|
|
85
|
-
listEntries: snapshot,
|
|
86
|
-
all: snapshot,
|
|
87
|
-
snapshot,
|
|
88
|
-
get size() { return byVersion.size; },
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export const createStore = createImmutableStore;
|
|
93
|
-
|
|
94
|
-
export function appendImmutable(input) {
|
|
95
|
-
if (!input || typeof input !== "object") fail("store_input_required", "appendImmutable requires {store, record}");
|
|
96
|
-
const store = input.store ?? input.target;
|
|
97
|
-
const record = input.record ?? input.object ?? input.value;
|
|
98
|
-
if (!store || typeof store.append !== "function") fail("store_required", "appendImmutable requires an immutable store", "store");
|
|
99
|
-
return store.append(record);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export const appendObject = appendImmutable;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import crypto from "node:crypto";
|
|
2
|
-
|
|
3
|
-
const pngSignature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
4
|
-
|
|
5
|
-
function pngDimensions(bytes) {
|
|
6
|
-
if (bytes.length < 24 || !bytes.subarray(0, 8).equals(pngSignature) || bytes.toString("ascii", 12, 16) !== "IHDR") return undefined;
|
|
7
|
-
const width = bytes.readUInt32BE(16);
|
|
8
|
-
const height = bytes.readUInt32BE(20);
|
|
9
|
-
return width > 0 && height > 0 ? { height, width } : undefined;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function artifactMetadata(bytes, mediaType) {
|
|
13
|
-
const metadata = {
|
|
14
|
-
byte_length: bytes.length,
|
|
15
|
-
media_type: mediaType,
|
|
16
|
-
sha256: `sha256:${crypto.createHash("sha256").update(bytes).digest("hex")}`,
|
|
17
|
-
};
|
|
18
|
-
if (mediaType === "image/png") Object.assign(metadata, pngDimensions(bytes));
|
|
19
|
-
return metadata;
|
|
20
|
-
}
|