diff --git a/README.md b/README.md index c99af3e..c6120ce 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,12 @@ This devkit solves that by using structured documentation as the shared state. T | `cmk:sui-sdk` | gRPC-first guidance for talking to a Sui full node — JSON-RPC is deprecated | | `cmk:sui-devstack` | Worktree-safe local Sui network setup for development and e2e tests | +### Design family + +| Skill | Purpose | +|---|---| +| `cmk:blueprint-animation` | Animated before → after UX redesign (or one-screen explainer), explained step by step through a blueprint drawing. Third-party port of [moguzbulbul/blueprint-animation](https://github.com/moguzbulbul/blueprint-animation) — **CC BY-NC 4.0, non-commercial use only** | + ## Usage A deeper tour, in the order docs build on each other when starting a new project. Every line in the blocks below is a real trigger — paste and go. diff --git a/docs/ai/skills/README.md b/docs/ai/skills/README.md index 6d6df22..a376213 100644 --- a/docs/ai/skills/README.md +++ b/docs/ai/skills/README.md @@ -1,6 +1,6 @@ # Skills -The `cmk:*` skill packages under [`skills/`](../../../skills/): eight docs-family skills, thirteen setup-family skills, nine delivery-family skills, two knowledge-family skills, and one session-discipline skill (`cmk:interpret`). Each is a directory with a `SKILL.md` (frontmatter `name`/`description`/`version` plus the body the agent reads), and most ship a `references/` folder of guidance, templates, and conventions the workflow loads on demand. +The `cmk:*` skill packages under [`skills/`](../../../skills/): eight docs-family skills, thirteen setup-family skills, nine delivery-family skills, two knowledge-family skills, one design-family skill (`cmk:blueprint-animation`), and one session-discipline skill (`cmk:interpret`). Each is a directory with a `SKILL.md` (frontmatter `name`/`description`/`version` plus the body the agent reads), and most ship a `references/` folder of guidance, templates, and conventions the workflow loads on demand. Docs-family skills follow the same shape: a "Workflow: Create" / "Workflow: Iterate" pair, with placement rules, shaping guidance, and templates kept out of `SKILL.md` itself and cited via "Read `references/.md`" lines. Setup-family skills instead follow a facet shape (modes and/or a single workflow, plus a report-only `## Verify` section). Delivery-family skills follow a tracker-neutral phase/gate shape and never carry a `## Verify` section — that contract is setup-family only. Knowledge-family skills are reference packs with no create/iterate or phase shape at all. See [conventions.md](./conventions.md) for the exceptions and the full breakdown. @@ -48,6 +48,10 @@ Docs-family skills follow the same shape: a "Workflow: Create" / "Workflow: Iter - [sui-sdk.md](./sui-sdk.md) — `cmk:sui-sdk`, gRPC-first guidance for talking to a Sui full node. - [sui-devstack.md](./sui-devstack.md) — `cmk:sui-devstack`, worktree-safe local Sui network setup for development and tests. +## Design family + +- [blueprint-animation.md](./blueprint-animation.md) — `cmk:blueprint-animation`, step-by-step blueprint animation explaining UX decisions (Redesign or Explain mode). Third-party port, CC BY-NC 4.0. + ## Session - [interpret.md](./interpret.md) — `cmk:interpret`, companion session beside another window: stance plus a carry-back reply. User-invoked. diff --git a/docs/ai/skills/blueprint-animation.md b/docs/ai/skills/blueprint-animation.md new file mode 100644 index 0000000..a7e2164 --- /dev/null +++ b/docs/ai/skills/blueprint-animation.md @@ -0,0 +1,37 @@ +# cmk:blueprint-animation + +## What +Design-family skill that builds one continuous, never-cutting animation of a +single screen, in 3–6 numbered steps, each explaining one UX decision +through a cyan blueprint drawing. Redesign mode (Before + After screens) +rebuilds only the parts that change; Explain mode (one screen) keeps the +design fixed and annotates each module's what and why. Ported from +[moguzbulbul/blueprint-animation](https://github.com/moguzbulbul/blueprint-animation) +v1.3.1; licensed CC BY-NC 4.0, not the repo's MIT. + +## Approach +Figma fidelity outranks every other rule: values, fonts, and icons come +from the Figma file, and each built screen is pixel-diffed against the +Figma export before any motion is added. Each step runs a fixed phase +sequence — focus, scan-line blueprint in, construct (or annotate), scan-line +reveal, hold — with old→new swaps only while covered by the blueprint. +The scene builds on Claude Design's `animations_v3` starter and reuses the +blueprint kit from the bundled reference scene. Keeps the upstream §0–8 +section numbering so cross-references survive the split into references. + +## Where +- Skill body: `skills/blueprint-animation/SKILL.md` — §0 fidelity, §1 + gather and mode pick, §2 per-step sequence, §7 QA. +- `skills/blueprint-animation/references/blueprint-style.md` — §3 drawing + style, §4 text/overlap rules. +- `skills/blueprint-animation/references/architecture.md` — §5 scene + architecture, §6 performance budget. +- `skills/blueprint-animation/references/explain-mode.md` — §8 Explain + mode: phase table, mark vocabulary, worked example. +- `skills/blueprint-animation/references/example-scene.jsx` — Redesign-mode + reference scene (CRM record page, 5 steps). +- `skills/blueprint-animation/LICENSE` — CC BY-NC 4.0 legal code and + attribution. + +## Links +Standalone: cites no other `cmk:` skill. diff --git a/docs/ai/skills/conventions.md b/docs/ai/skills/conventions.md index 0dc27ee..ab17d6a 100644 --- a/docs/ai/skills/conventions.md +++ b/docs/ai/skills/conventions.md @@ -8,7 +8,7 @@ Frontmatter declares three fields the host (Claude Code or OpenCode) reads to di - `name` — `cmk:`, used as the slash command and skill ID. - `description` — opens in the second person (`Use when…` / `Use whenever…`) with trigger phrases plus an **outcome noun** (the deliverable), not a workflow step list. Used by the agent to auto-select the skill from user intent. A user-invoked skill (`disable-model-invocation: true`) writes one plain human-facing line naming the deliverable instead — the agent never routes on that line. -- `version` — `0.6.x` on `cmk:design`; `0.5.x` on `cmk:delivery-pipeline`; `0.4.x` on `cmk:cicd` (security-scanning facet) and `cmk:requirements` (Standard elicitation: close package, scope band, guards); `0.3.x` on `cmk:delivery-workflow`, `cmk:agent-instructions`, `cmk:adr`, `cmk:docs`, and `cmk:local-stack`; `0.2.0` on two docs-family skills (`learn`, `rule`) and six setup-family skills (`agent-instructions`, `agent-vendors`, `infra`, `mcp-config`, `project-layout`, `toolchain`); `0.1.x` on the rest — `repo-setup` and `sync`, `test-resources`, `rust`, and `testcontainers` (new setup-family skills), the other delivery-family skills (incl. new `cmk:delivery-simplify` at `0.1.0`), both knowledge-family skills, the two remaining docs-family skills (`codebase-docs`, `glossary`), and `cmk:interpret`. +- `version` — `0.6.x` on `cmk:design`; `0.5.x` on `cmk:delivery-pipeline`; `0.4.x` on `cmk:cicd` (security-scanning facet) and `cmk:requirements` (Standard elicitation: close package, scope band, guards); `0.3.x` on `cmk:delivery-workflow`, `cmk:agent-instructions`, `cmk:adr`, `cmk:docs`, and `cmk:local-stack`; `0.2.0` on two docs-family skills (`learn`, `rule`) and six setup-family skills (`agent-instructions`, `agent-vendors`, `infra`, `mcp-config`, `project-layout`, `toolchain`); `0.1.x` on the rest — `repo-setup` and `sync`, `test-resources`, `rust`, and `testcontainers` (new setup-family skills), the other delivery-family skills (incl. new `cmk:delivery-simplify` at `0.1.0`), both knowledge-family skills, the two remaining docs-family skills (`codebase-docs`, `glossary`), `cmk:interpret`, and `cmk:blueprint-animation`. - `disable-model-invocation: true` — optional, fourth field only. Present on `cmk:interpret`. The closer is still `---`. No skill file references outside its own package by relative path — the rule binds a package's own references, not content it emits into a target repo; a skill that needs a target-repo artifact names it repo-root-relative, and a skill that needs another skill cites it by `cmk:` name — see `cmk:agent-vendors`. @@ -23,12 +23,14 @@ Delivery-family skills (`delivery-workflow`, `discover-efforts`, `delivery-intak Session-discipline skills (`interpret`) are neither create/iterate nor a setup facet nor a delivery phase. `cmk:interpret` is user-invoked (`disable-model-invocation: true`), stays read-only toward the repo, and ships a `references/digest.md` loaded only at session end. +Design-family skills (`blueprint-animation`) produce a visual design artifact rather than a doc or a repo facet. `cmk:blueprint-animation` is a third-party skill ported under its own licence (CC BY-NC 4.0, `LICENSE` inside the package, not the repo's MIT): it keeps the upstream section numbering (§0–8) across `SKILL.md` and `references/`, and ships a non-Markdown reference scene, `references/example-scene.jsx`, that the agent copies as the starting scene. No `## Verify` section, no `eval.json`. + Knowledge-family skills (`sui-sdk`, `sui-devstack`) are domain reference packs sitting beside the generic model rather than replacing it. `cmk:sui-sdk` is a single file with no `references/` directory: it corrects one specific stale-training-data pattern (reaching for Sui JSON-RPC instead of gRPC) and runs no workflow at all. `cmk:sui-devstack` has a `references/` folder and layers Sui-specific detail — Devstack's config shape, account/package staging, instance isolation — on top of `cmk:local-stack`'s generic `(worktree, config, instance)` primitive; it does not restate or replace that primitive. Neither knowledge skill has a `## Verify` section or an `eval.json`. ## Where - Frontmatter, on every skill: open any `skills//SKILL.md` and read lines 1–5 (1–6 when `disable-model-invocation: true` is present). -- Skills with `references/`: `skills/adr/`, `skills/agent-instructions/`, `skills/agent-vendors/`, `skills/cicd/`, `skills/codebase-docs/`, `skills/design/`, `skills/docs/`, `skills/infra/`, `skills/learn/`, `skills/local-stack/`, `skills/project-layout/`, `skills/repo-setup/`, `skills/requirements/`, `skills/rule/`, `skills/rust/`, `skills/sync/`, `skills/test-resources/`, `skills/toolchain/`, `skills/delivery-workflow/`, `skills/discover-efforts/`, `skills/delivery-intake/`, `skills/delivery-simplify/`, `skills/delivery-review/`, `skills/delivery-ship/`, `skills/delivery-pipeline/`, `skills/sui-devstack/`, `skills/interpret/`. Skills without one: `skills/glossary/`, `skills/mcp-config/`, `skills/delivery-spec-plan/`, `skills/delivery-handoff/`, `skills/sui-sdk/`, `skills/testcontainers/`. -- Skills with `eval.json`: `skills/agent-instructions/eval.json`, `skills/codebase-docs/eval.json`, `skills/local-stack/eval.json`, `skills/repo-setup/eval.json`, `skills/sync/eval.json`, `skills/interpret/eval.json`. No delivery-family or knowledge-family skill ships one. +- Skills with `references/`: `skills/adr/`, `skills/agent-instructions/`, `skills/agent-vendors/`, `skills/cicd/`, `skills/codebase-docs/`, `skills/design/`, `skills/docs/`, `skills/infra/`, `skills/learn/`, `skills/local-stack/`, `skills/project-layout/`, `skills/repo-setup/`, `skills/requirements/`, `skills/rule/`, `skills/rust/`, `skills/sync/`, `skills/test-resources/`, `skills/toolchain/`, `skills/delivery-workflow/`, `skills/discover-efforts/`, `skills/delivery-intake/`, `skills/delivery-simplify/`, `skills/delivery-review/`, `skills/delivery-ship/`, `skills/delivery-pipeline/`, `skills/sui-devstack/`, `skills/interpret/`, `skills/blueprint-animation/`. Skills without one: `skills/glossary/`, `skills/mcp-config/`, `skills/delivery-spec-plan/`, `skills/delivery-handoff/`, `skills/sui-sdk/`, `skills/testcontainers/`. +- Skills with `eval.json`: `skills/agent-instructions/eval.json`, `skills/codebase-docs/eval.json`, `skills/local-stack/eval.json`, `skills/repo-setup/eval.json`, `skills/sync/eval.json`, `skills/interpret/eval.json`. No delivery-family, knowledge-family, or design-family skill ships one. - The shared docs-family workflow shape: grep for `^## Workflow: Create` and `^## Workflow: Iterate` across `skills/*/SKILL.md`. - The shared setup-family Verify contract: grep for the exact heading `^## Verify$` across `skills/*/SKILL.md` — every hit is a setup-family skill. `skills/delivery-review/SKILL.md` has a similarly named but distinct `## Verify before acting` section (adversarial verification of review findings, not a report-only facet check) — match on the exact heading, not the prefix, to tell them apart. - The delivery-family tracker binding: grep for `references/linear.md` across `skills/delivery-*/SKILL.md` and `skills/discover-efforts/SKILL.md`, then confirm each hit is the sole conditional pointer line, not body prose. diff --git a/lib/skill-graph-layout.ts b/lib/skill-graph-layout.ts index 28f72e7..79772d3 100644 --- a/lib/skill-graph-layout.ts +++ b/lib/skill-graph-layout.ts @@ -16,7 +16,7 @@ export type PersistedSkillGraphLayout = { * no longer exists, and restoring them would scatter nodes across lanes that * have moved. */ -export const LAYOUT_VERSION = 3; +export const LAYOUT_VERSION = 4; const STORAGE_KEY = "ai-devkit-skill-graph-layout"; @@ -39,6 +39,7 @@ const LANE_ORDER = [ "agent", "testing", "sui", + "design", "sync", "session", "other", diff --git a/lib/skill-types.ts b/lib/skill-types.ts index fa45ed9..3e1fd43 100644 --- a/lib/skill-types.ts +++ b/lib/skill-types.ts @@ -22,6 +22,7 @@ export const CATEGORY_LABELS: Record = { docs: "Documentation", testing: "Testing & Code", sui: "Sui Network", + design: "Design", session: "Session", other: "Other", }; @@ -66,6 +67,7 @@ export const CATEGORY_MAP: Record = { rust: "testing", "sui-sdk": "sui", "sui-devstack": "sui", + "blueprint-animation": "design", interpret: "session", }; @@ -86,6 +88,7 @@ export const SKILL_PURPOSE: Record = { "agent-instructions": "Set up CLAUDE.md and AGENTS.md", "agent-vendors": "Vendor skills for each coding agent", cicd: "Set up or speed up CI and deploys", + "blueprint-animation": "Animate a UX redesign as a blueprint", "codebase-docs": "Generate AI-navigable codebase docs", "delivery-handoff": "Hand tracked work to another agent", "delivery-intake": "Pick up a ticket and gather its context", diff --git a/skills/blueprint-animation/LICENSE b/skills/blueprint-animation/LICENSE new file mode 100644 index 0000000..19d77ac --- /dev/null +++ b/skills/blueprint-animation/LICENSE @@ -0,0 +1,414 @@ +Copyright (c) 2026 Oğuz (@moguzbulbul, https://oguz.design) + +This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 +International License (CC BY-NC 4.0). Commercial use requires written +permission from the author. The full legal code follows. + +Attribution-NonCommercial 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-NonCommercial 4.0 International Public +License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial 4.0 International Public License ("Public +License"). To the extent this Public License may be interpreted as a +contract, You are granted the Licensed Rights in consideration of Your +acceptance of these terms and conditions, and the Licensor grants You +such rights in consideration of benefits the Licensor receives from +making the Licensed Material available under these terms and +conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + j. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + k. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + l. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for + NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/skills/blueprint-animation/SKILL.md b/skills/blueprint-animation/SKILL.md new file mode 100644 index 0000000..a29590f --- /dev/null +++ b/skills/blueprint-animation/SKILL.md @@ -0,0 +1,95 @@ +--- +name: cmk:blueprint-animation +description: Use when the user asks to "make a blueprint animation", "animate this redesign before and after", "explain this screen's UX decisions", "animate a UX case study", or shares Before/After screens (or one screen) and wants one continuous step-by-step blueprint animation that explains UX decisions — Redesign mode rebuilds the parts that change, Explain mode annotates each module's what and why. For case studies, redesign walkthroughs, design rationale, and social posts. +version: 0.1.0 +--- + +# Blueprint Animation + +Adapted from [blueprint-animation](https://github.com/moguzbulbul/blueprint-animation) v1.3.1 by Oğuz ([@moguzbulbul](https://x.com/moguzbulbul)), inspired by Arjun Mahesh. Licensed **CC BY-NC 4.0**: non-commercial use only, with credit; commercial use needs the author's written permission. See `LICENSE` in this package. + +Start your first question form or reply with `cmk:blueprint-animation · `, so the user can see which version and mode is running. + +One continuous animation of ONE screen. The page never cuts; it runs in N numbered steps. Each step explains a single UX decision. + +Two modes. Pick the mode from what the user gives you (§1); with one screen, Explain is always offered first: +- **Redesign** (Before + After screens): the screen is redesigned step by step. §1–7 describe this mode. +- **Explain** (one screen, no Before): the design never changes. Each step turns one module into a blueprint and draws why it is built that way. Read `references/explain-mode.md` (§8). Everything in §1–7 still applies unless §8 says otherwise. + +In both modes the design comes from Figma and is reproduced exactly (§0). + +Where each section lives: +- §0–2 and §7: this file. +- §3 drawing style and §4 text/overlap rules: read `references/blueprint-style.md` before drawing any wire. +- §5 architecture and §6 performance: read `references/architecture.md` before writing the scene. +- §8 Explain mode: `references/explain-mode.md`. +- Reference scene: `references/example-scene.jsx` (Redesign mode: a CRM record page redesigned in 5 steps). + +## 0. Fidelity — the Figma design is exact + +The screens the user gives are reproduced 1:1. This rule beats every other rule in this skill, performance included. + +- Read every value from the Figma source, not from a screenshot: frame size; each layer's x, y, w, h; fills, strokes, radii, effects; text style (family, size, weight, line height, letter spacing, case). Use the file's colour and text styles as they are. +- If a value can't be read (only a screenshot, a missing font, a hidden layer), list what is missing and ask. Never guess, round or "tidy up" a value. +- Copy all text exactly: wording, capitals, numbers, dates, punctuation. +- Load the file's real fonts. If a font can't be loaded, stop and ask for it: a stand-in font changes every text width and wrap. +- Icons, logos and images: export them from Figma (SVG for vectors) and use them as they are. Never redraw them or swap in a lookalike from an icon set. +- Place every element at its Figma coordinates relative to the frame (`abs(x, y, w, h)`). Don't re-flow the frame into flex or grid if that moves anything by even 1 px. +- Convert Figma units exactly: letter spacing % → em (−2% = −0.02em); line height in px stays px; an inside stroke stays inside the box (`box-sizing: border-box` border or `inset` shadow); drop shadows keep the same x, y, blur, spread and colour. +- The app is the Figma frame's own size at 1:1 (1440×900 only if the frame is). The canvas grows to fit it. +- No restyling, no new spacing, no removed shadows, no "improvements". The only colours outside the design are the blueprint's. +- Redesign mode: a screen you design or derive (because the user picked that option, §1) reuses the given screen's components and changes only what the step list says. + +Order of work: +1. Build each given screen as static real-UI components. +2. Render it at 1:1 and compare it with the Figma export of the same frame (50% overlay or pixel diff). Fix every difference before going on. +3. Only then build the blueprint and the motion. At rest (before step 1 and after the last step) the real UI matches the Figma frames exactly. + +## 1. Before you build — gather + +- **Redesign:** the Before and After screens, as Figma frames (screenshots only when there is no file; see §0). The After is the source of truth; don't redesign beyond it. + **Explain:** the one screen, as a Figma frame. It is the source of truth and nothing on it changes. +- The list of steps, 3–6. + **Redesign:** each step needs **name** (2–4 words), **problem** (one sentence, ≤ 12 words), **fix** (one sentence). + **Explain:** each step is one module and needs **name** (the module, 2–4 words), **what** (one sentence, ≤ 12 words: the decision), **why** (one sentence: the user benefit or principle behind it). +- The design system for the real UI. Blueprint colours are the only colours outside it. +- Canvas size: the app is the Figma frame at 1:1 on top, with a margin and a text band below (a 1440×900 frame gives the default 1600×1200). + +Pick the mode: +- **Two screens given → Redesign mode.** No mode question. +- **One screen given →** the first question is the mode. It MUST include this option, listed first, in the user's language: + **"Continue with this one screen: the design stays as it is; explain what and why, module by module (Explain)"** + Other options may follow: it is the Before (you design the After), it is the After (you derive the Before), or the user uploads the other screen. +- A one-screen request can always go ahead in Explain mode. Never say you can't start without a second screen. + +Then: +- **Explain:** propose 3–6 modules (name · what · why) and get them confirmed. Proposals describe the screen as it is, never changes to it. +- **Redesign:** propose 3–6 changes (name · problem · fix) and get them confirmed. +- Anything else missing (a font, a Figma value, see §0): ask before building. + +## 2. The per-step sequence (never skip a phase) + +Local step time `t` (authored seconds ÷ K, K = 1.4 slow factor). For a 5 s step with construct end `c1 = 3.2`: + +| Phase | t | What happens | +|---|---|---| +| Problem | 0 → 0.9 | Everything except the focus rect fades toward white (≈ 78%). A thin grey outline draws around the focus. The text band shows number, name and problem. | +| Blueprint in | 0.95 → 1.75 | A cyan **scan line** sweeps top → bottom. Above it, the WHOLE app is a blueprint drawing; below it, the real old UI. | +| Construct | 1.9 → c1 | Only the changing wires move / resize / merge. The static blueprint behind them dims 0.7 → 0.3. Guides and dimension lines draw. | +| Reveal | c1 + 0.05 → c1 + 0.85 | The scan line sweeps again. Above it, the real NEW UI; below it, the blueprint. | +| Hold | → end | The fix sentence fades in. Then the focus fades out. | + +Rules that make it feel smooth: +- Real UI regions swap from old to new **only while fully covered** by the blueprint (the swap is invisible). Never fade old UI out in view: it reads as "the UI disappeared". +- Every opacity keys to the smooth wipe/reveal curves, never to near-instant ramps. No value may change from 0 to 1 in under ~0.3 s unless it is hidden. +- Layout pushes happen BEFORE the elements that land in the freed space (for example, the timeline moves down first, then the tasks rise into the gap). +- Stagger groups of moving wires (0.08–0.12 s apart) so they never cross each other. +- Last 1 s of the piece: fade the app out so the loop seam is soft. + +## 7. QA before handing over + +1. Filmstrip with `data-om-seek-to-time-frame` at each step's problem, blueprint-in, mid-construct, reveal and hold. +2. At mid-construct: no text sits on text, and no moving wire crosses a label. +3. Every counter and date on screen matches the data. +4. Fidelity (§0): the real UI at rest matches the Figma exports at 1:1 in an overlay or pixel diff, including text wraps, icon shapes, strokes and shadows. +5. Performance numbers from §6 (`references/architecture.md`). diff --git a/skills/blueprint-animation/references/architecture.md b/skills/blueprint-animation/references/architecture.md new file mode 100644 index 0000000..35d4b5a --- /dev/null +++ b/skills/blueprint-animation/references/architecture.md @@ -0,0 +1,27 @@ +# Scene architecture and performance + +Sections §5–6 of `cmk:blueprint-animation`. Adapted from [blueprint-animation](https://github.com/moguzbulbul/blueprint-animation) v1.3.1 by Oğuz (@moguzbulbul), CC BY-NC 4.0. + +## 5. Architecture (animations_v3 starter) + +- The engine is Claude Design's `animations_v3` starter, copied into the project as `animations-v3.jsx`. It is not part of this skill; build on it, don't write your own. +- `OM_SCENES` literal in the DC helmet: `Before, , After`. The scene is one `.jsx` loaded through ``. +- Start the scene from `references/example-scene.jsx`. Keep its blueprint kit as it is: `phases`, `tw`/`lerp`/`LR`, `Wire`, `Guide`, `Line`, `Label`, `DimH`, `Num`, `curve`/`ctr`, `Focus`, the clip + scan-line layer and the text band. Rewrite only what belongs to the new screen: the real-UI components, `StaticBP`, the geometry and `STEPS`. +- `phases(T, start, dur, c1)` returns `{focus, hl, call, bp, wipe, rev, cdim, lines, p, before, after, fix}` for each step. All choreography reads from these. +- Global layout values are derived from step progress: column x/width, header right edge, logo x, timeline y, panel x. +- Layers inside the app, bottom → top: + 1. Real UI regions: each has a `before` and an `after` component with its own opacity. + 2. An SVG with `clipPath` = the scan-line band. Inside it, a white sheet, the **static full-screen blueprint** (memoized `StaticBP`) and each step's `` wires. + 3. The scan line. +- The text band sits below the app, outside the SVG. + +## 6. Performance (required, or it stutters) + +- Every layer stays **mounted** all the time. Hide it with `visibility: hidden` when opacity is 0; never mount/unmount at section boundaries. +- `React.memo` every real-UI component. Pass quantized props (`Math.round(v*2)/2` for positions, 2 decimals for opacity). +- `StaticBP` is memoized with rounded props, so it re-renders once per step, not every frame. +- Build a step's `` JSX only while `focus > 0`. +- Move with `transform: translate`, not `left/top`. +- No blurred box-shadows on layers that move, no `text-wrap: pretty`, no nested `` per wire, no stroked text halos. A shadow that is in the design stays (§0). +- In the engine, persist the playhead to `localStorage` at most every 500 ms (not every frame). +- Measure: a seek loop over the whole timeline (< 7 ms per frame), plus a rAF loop during real playback (no frames > 34 ms). diff --git a/skills/blueprint-animation/references/blueprint-style.md b/skills/blueprint-animation/references/blueprint-style.md new file mode 100644 index 0000000..33232dc --- /dev/null +++ b/skills/blueprint-animation/references/blueprint-style.md @@ -0,0 +1,21 @@ +# Blueprint drawing style and text rules + +Sections §3–4 of `cmk:blueprint-animation`. Adapted from [blueprint-animation](https://github.com/moguzbulbul/blueprint-animation) v1.3.1 by Oğuz (@moguzbulbul), CC BY-NC 4.0. + +## 3. Blueprint drawing style + +- Draw on white, not on a navy background. Line colour is cyan-ink `#0B8FC2`; fill `#2ACCFF14`; guides are dotted `2 4`. +- **Everything on screen** turns into a blueprint in the blueprint phase: rail, breadcrumb, logo (box, mark and outlined wordmark), buttons, rows, tabs, cards, panel. Never convert only part of the screen. +- Each wire uses the exact rect of the element it stands for (§0), so the blueprint lines up with the real UI. +- Wires carry their real text (button labels, row text, tab names). Rounded pills stay rounded, list rows get an icon circle. +- Selection handles (5 px squares) on the 1–3 wires that matter in that step. +- Corner ticks on the focus rect, dotted alignment guides through key edges, one dimension line per step with a short UPPERCASE mono label (for example "CENTERED COLUMN · 760"). +- Labels: 11–12 px mono, `letter-spacing .06em`, no stroked halo. + +## 4. Text and overlap rules (checked every time) + +- **No text on a moving wire.** Wire text fades out when motion starts (q > 0.15) and back in when it settles (q > 0.85). +- Wires that disappear collapse **in place** (height → 0), not across other content. +- Labels live in empty bands (above the focus, between sections). Never on top of a row or a card. +- Only one step's notes are visible at a time, in the bottom band: `[number badge · NAME] [problem] [fix]`. +- No top title bar and no end title unless the user asks for them. diff --git a/skills/blueprint-animation/references/example-scene.jsx b/skills/blueprint-animation/references/example-scene.jsx new file mode 100644 index 0000000..8e066cc --- /dev/null +++ b/skills/blueprint-animation/references/example-scene.jsx @@ -0,0 +1,474 @@ +const { CompositionStage, useComposition, Easing } = window; + +const AS = 1, AX = 80, AY = 100; +const BP = { bg: '#FFFFFF', line: '#0B8FC2', fill: '#2ACCFF14', grid: '#2ACCFF1F', text: '#E8EEF2', mute: '#8FA6B8', accent: '#FFB547' }; +const MONO = 'ui-monospace, SFMono-Regular, Menlo, monospace'; +const M = { enter: Easing.easeOutCubic, move: Easing.easeInOutCubic, draw: Easing.easeInOutQuad }; +const cl = (v) => Math.max(0, Math.min(1, v)); +const tw = (t, a, b, ease) => (ease || M.move)(cl((t - a) / (b - a))); +const lerp = (a, b, p) => a + (b - a) * p; +const LR = (a, b, p) => ({ x: lerp(a.x, b.x, p), y: lerp(a.y, b.y, p), w: lerp(a.w, b.w, p), h: lerp(a.h, b.h, p) }); + +const K = 1.4; +function phases(T, start, dur, c1) { + const t = (T - start) / K; + return { + t, + focus: tw(t, 0, 0.4, M.enter) * (1 - tw(t, dur - 0.6, dur, M.enter)), + hl: tw(t, 0.1, 0.7, M.draw), + call: tw(t, 0.2, 0.6, M.enter) * (1 - tw(t, dur - 0.5, dur - 0.1, M.enter)), + bp: tw(t, 0.9, 0.95, M.enter) * (1 - tw(t, c1 + 0.85, c1 + 0.9, M.enter)), + wipe: tw(t, 0.95, 1.75, M.move), + rev: tw(t, c1 + 0.05, c1 + 0.85, M.move), + cdim: tw(t, 1.75, 2.2, M.move) * (1 - tw(t, c1 - 0.4, c1 - 0.05, M.move)), + lines: tw(t, 1.2, 2.0, M.draw), + p: tw(t, 1.9, c1, M.move), + before: 1 - tw(t, 1.75, 1.8, M.enter), + after: tw(t, c1 - 0.05, c1, M.enter), + fix: tw(t, c1 + 0.45, c1 + 1.05, M.enter) + }; +} + +// ---------- small UI atoms (Amplifidor tokens) ---------- +const ICON = { + mail: 'M4 6.5h16v11H4zM4.5 7l7.5 6 7.5-6', note: 'M6 4h9l3 3v13H6zM9 10h6M9 13.5h6M9 17h4', + doc: 'M7 3.5h7l4 4V20.5H7zM14 3.5v4h4', deal: 'M4 12l8-8h7v7l-8 8zM15.5 8.5h.01', + sys: 'M12 8v4l2.5 1.5M20 12a8 8 0 1 1-16 0 8 8 0 0 1 16 0', reply: 'M9 14 4 9l5-5M4 9h10a6 6 0 0 1 6 6v5', + chev: 'M9 6l6 6-6 6', down: 'M6 9l6 6 6-6', star: 'M12 3.5l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.9l-5.2 2.7 1-5.8-4.3-4.1 5.9-.9z', + share: 'M12 15V4M8 8l4-4 4 4M5 13v6h14v-6', close: 'M6 6l12 12M18 6L6 18' +}; +const Ic = ({ k, s = 14 }) => ; +const abs = (x, y, w, h, extra) => ({ position: 'absolute', left: 0, top: 0, width: w, height: h, boxSizing: 'border-box', transform: `translate(${x}px, ${y}px)`, ...extra }); +const pill = (w, extra) => ({ width: w, height: 36, borderRadius: 999, background: 'var(--amp-gray-2)', color: 'var(--amp-gray-7)', fontSize: 14, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6, flex: 'none', ...extra }); +const Tag = ({ tone, children, dot }) => { + const t = { error: ['var(--amp-error-bg)', 'var(--amp-error)'], pending: ['#ff7d331f', 'var(--amp-pending)'], gray: ['var(--amp-gray-2)', 'var(--amp-gray-7)'], success: ['var(--amp-success-bg)', 'var(--amp-success)'] }[tone]; + return {dot ? : null}{children}; +}; + +const B_BTNS = [['Add to list', 104], ['Edit', 60], ['Run workflow', 124], ['Compose email', 136], ['star', 36], ['share', 36], ['⋯', 36]]; +const btnRects = (right) => { let x = right - 580; return B_BTNS.map(([l, w]) => { const r = { x, y: 78, w, h: 36, l }; x += w + 8; return r; }); }; +const rowR = (i) => ({ x: 96, y: 172 + i * 30, w: 284, h: 26 }); +const FILLED = [['Industry', 'B2B SaaS'], ['Employees', '240'], ['HQ', 'Berlin'], ['Customer since', 'Mar 2024'], ['ARR', '$48k'], ['Owner', 'Alex'], ['Domain', 'northwind.io'], ['Stage', 'Customer']]; +const EMPTY = ['Description', 'AngelList', 'Instagram', 'LinkedIn', 'Twitter', 'Facebook', 'Founded', 'Funding', 'Revenue range', 'Parent company', 'Phone', 'Address', 'Timezone', 'Tags']; +const ID_PARTS = [['B2B SaaS', 72], ['240 people', 84], ['Berlin', 50], ['Customer since Mar 2024', 188], ['$48k ARR', 76]]; +const idRects = (x0) => { let x = x0; const out = ID_PARTS.map(([l, w]) => { const r = { x, y: 148, w, h: 22 }; x += w + 20; return r; }); return { parts: out, details: { x, y: 148, w: 92, h: 22 } }; }; +const TABS = [['Activity', 70], ['Emails (12)', 100], ['Notes (3)', 76], ['Tasks (2)', 78], ['Files', 44], ['Deals', 52]]; +const tabRects = (x0, y) => { let x = x0; return TABS.map(([l, w]) => { const r = { x, y: y + 10, w, h: 24, l }; x += w + 16; return r; }); }; +const SYS = [['Alex', 'viewed this record', 'Today'], ['Enrichment', 'updated 3 attributes', 'Tue'], ['HubSpot sync', 'completed', 'Mon'], ['Reminder', 'task “Send proposal” passed its due date', 'Sep 23'], ['Alex', 'changed Domains and 1 other attribute', 'Sep 17'], ['Workflow', '“Customer health” ran', 'Sep 15'], ['System', 'created this record', 'Mar 4, 2024']]; +const REL = [['mail', 'Mia Chen', '“Re: Renewal pricing”', 'Tue'], ['note', 'Alex', '“Mia wants 3-year pricing before the QBR”', 'Mon'], ['doc', '', 'Northwind_Renewal_Proposal_v2.pdf', 'Mon'], ['mail', 'Alex → Mia', '“Renewal next steps”', 'Sep 19'], ['deal', 'Renewal 2027', 'moved to Proposal · $52k', 'Sep 18'], ['note', 'Alex', '“Call notes: expanding to 2 new teams”', 'Sep 12'], ['mail', 'Mia → Alex', '“Intro to our CFO”', 'Sep 10']]; + +// ---------- real UI layers ---------- +function Chrome() { + return <> +
+
+ {[0, 1, 2, 3, 4].map(i =>
)} +
+
+ Companies/Northwind +
+ ; +} + +function NameBlock({ x, pillOp }) { + return <> +
+ +
+
Northwind
+
Customer
+ ; +} + +function BeforeActions({ right, op }) { + return
+ {B_BTNS.map(([l, w]) =>
{l === 'star' ? : l === 'share' ? : l}
)} +
; +} +function AfterActions({ right, op }) { + return
+
Compose email
+
⋯
+
; +} + +function Sidebar({ op }) { + return
+
Details
+ {FILLED.map(([l, v]) =>
{l}{v}
)} + {EMPTY.map(l =>
{l}Set {l}…
)} +
; +} + +function Identity({ x, op }) { + const r = idRects(x); + return
+
northwind.io · Owner Alex
+ {r.parts.map((p, i) => + {i > 0 ? · : null} + {ID_PARTS[i][0]} + )} + · + All details +
; +} + +const TASKS = [ + ['Send renewal proposal', 'Due Sep 23 · v2 draft ready', Overdue, 'Send proposal', true], + ['Reply to Mia', '“Re: Renewal pricing” · Tue', Unanswered, 'Reply', false], + ['Schedule QBR', 'With Mia Chen', Due Fri, 'Schedule', false] +]; +function NeedsYou({ x, op }) { + return
+
+ Needs you3 + + Renewal 2027·$52k·Proposal +
+ {TASKS.map(([t, s, tag, b, prim]) =>
+
{t}{s}
+ {tag} +
{b}
+
)} +
; +} + +function BeforeTimeline({ x, y, w, op, dimRow }) { + let tx = 0; + return
+
+ {TABS.map(([l, tw_], i) => { const left = tx; tx += tw_ + 16; return {l}{i === 0 ? : null}; })} +
+
+ Showing + All activity + All users + Sort: Last modified +
+ {SYS.map(([a, b, d], i) =>
+ + {a} {b} + {d} +
)} +
; +} + +function AfterTimeline({ x, y, op }) { + return
+
+ Timeline + Relationship +
+ {REL.map(([ic, a, b, d], i) =>
+ + {a} {b} + {d} +
)} +
; +} + +function Panel({ x, op }) { + return
+
+ +
Reply to Mia ChenRe: Renewal pricing · Renewal 2027
+ +
+
Task · Reply to Mia · Assigned to you (Alex)
+
+
+
Mia ChenTue, Sep 22
+ Hi Alex, could you share 3-year pricing before the QBR? Our CFO wants to compare it with the annual option. +
+
FileNorthwind_Renewal_Proposal_v2.pdfAttach
+
Hi Mia, here is the 3-year pricing ahead of the QBR.
+
+
Draft saved. It stays here if you close the panel.Send reply
+
; +} + +// ---------- blueprint primitives (app coords, drawn in an svg over the app) ---------- +const Wire = ({ r, op = 1, label, dashed, handles, text, round, ts = 12, center, dot, q }) => (r.w < 0.5 || op < 0.01) ? null : + + {text && (q == null || q < 0.15 || q > 0.85) ? + {dot ? : null} + {text} + : null} + {handles ? [[r.x, r.y], [r.x + r.w, r.y], [r.x, r.y + r.h], [r.x + r.w, r.y + r.h]].map(([x, y], i) => ) : null} + {label ? {label} : null} +; +const LogoWire = ({ x, op = 1, name = true }) => op < 0.01 ? null : + + + + + {name ? Northwind : null} + {name ? : null} +; +const Guide = ({ x, y, x2, y2, op }) => ; +const Line = ({ d, draw, op = 1, arrow, color }) => 0.95 ? 'url(#bpArrow)' : null} />; +const Label = ({ x, y, children, op = 1, anchor = 'start', color }) => {children}; +const DimH = ({ x1, x2, y, label, draw, op = 1 }) => + + + +; +const Num = ({ x, y, n, op }) => {n}; +const curve = (a, b) => `M${a.x} ${a.y}C${a.x} ${(a.y + b.y) / 2} ${b.x} ${(a.y + b.y) / 2} ${b.x} ${b.y}`; +const ctr = (r) => ({ x: r.x + r.w / 2, y: r.y + r.h / 2 }); + +function Focus({ ph, rect, children, bpAll = 0 }) { + if (ph.focus <= 0.001) return null; + const { x, y, w, h } = rect; + return + + + + {children} + ; +} + +const StaticBP = React.memo(function StaticBP({ act, s1p, s2p, s3p, s4p, s5p, out, logoX, hdrRight, colX, colW, tlY, panelX }) { + return <> + + + + {[0, 1, 2, 3, 4].map(i => )} + + + {act !== 0 ? (s1p < 0.5 + ? btnRects(hdrRight).map((r, i) => ) + : <>) : null} + {act !== 1 && s2p < 0.5 ? <> + + + {[...FILLED.map(x => `${x[0]} · ${x[1]}`), ...EMPTY.map(e => `Set ${e}…`)].map((t, i) => )} + : null} + {act !== 1 && s2p >= 0.5 ? (() => { const ix = logoX + 52, ir = idRects(ix); return <> + + + + {ir.parts.map((r, i) => )} + + ; })() : null} + {act !== 2 && s3p >= 0.5 ? <> + + + + {['Send renewal proposal', 'Reply to Mia', 'Schedule QBR'].map((t, i) => { const y = 264 + i * 64; return + + + + ; })} + : null} + {act !== 3 && s4p < 0.5 ? <> + {tabRects(colX, tlY).map((r, i) => (act === 2 && (i === 1 || i === 3)) ? null : )} + + + {SYS.map((s_, i) => { const y = tlY + 88 + i * 52 + 8; return (y > 890 || (act === 2 && i === 3)) ? null : ; })} + : null} + {act !== 3 && s4p >= 0.5 ? <> + + + {REL.map((r_, i) => { const y = tlY + 44 + i * 52 + 8; return y > 890 ? null : ; })} + : null} + {act !== 4 && s5p >= 0.5 && out < 0.5 ? <> + + + + + : null} +; +}); + +// ---------- the piece ---------- +const STEPS = [ + { key: 'Actions', n: '01', name: 'One primary action', prob: 'Six buttons with the same weight. You mostly send email.', fix: 'Compose stays. The rest move into ⋯.', side: 'right' }, + { key: 'Details', n: '02', name: 'Hide absence', prob: '22 detail rows. 14 of them only say “Set…”.', fix: 'Eight facts become one line. The rest is one click away.', side: 'left' }, + { key: 'Open work', n: '03', name: 'Open work first', prob: 'An overdue task sits in a tab and a system log.', fix: 'Three tasks, one primary action, on top.', side: 'left' }, + { key: 'Timeline', n: '04', name: 'One timeline', prob: 'Six tabs and two filters. The default feed is a system log.', fix: 'People and deals by default. Filters live in one menu.', side: 'right' }, + { key: 'Panel', n: '05', name: 'Act in context', prob: 'Every action leaves the record.', fix: 'A side panel opens next to the page and keeps the draft.', side: 'right' } +]; + +const MChrome = React.memo(Chrome), MName = React.memo(NameBlock), MBA = React.memo(BeforeActions), MAA = React.memo(AfterActions), MSide = React.memo(Sidebar), MId = React.memo(Identity), MNY = React.memo(NeedsYou), MBT = React.memo(BeforeTimeline), MAT = React.memo(AfterTimeline), MPanel = React.memo(Panel); +const q2 = (v) => Math.round(v * 2) / 2, o3 = (v) => Math.round(v * 100) / 100; + +function Piece() { + const { T, CUES, authoredTotal } = useComposition(); + const s1 = phases(T, CUES.Actions, 5, 3.2), s2 = phases(T, CUES.Details, 6, 3.9), s3 = phases(T, CUES['Open work'], 5, 3.2), s4 = phases(T, CUES.Timeline, 5, 3.2), s5 = phases(T, CUES.Panel, 5, 3.2); + const PH = [s1, s2, s3, s4, s5]; + const out = tw(T, CUES.After, CUES.After + 0.8 * K); + const P5 = s5.p * (1 - out); + const bpAll = Math.max(s1.bp, s2.bp, s3.bp, s4.bp, s5.bp); + const act = PH.findIndex(p => p.bp > 0.001); + const wipe = act >= 0 ? PH[act].wipe : 0, rev = act >= 0 ? PH[act].rev : 0; + const clipTop = rev > 0 ? 900 * rev : -20, clipBot = wipe >= 1 ? 920 : 900 * wipe; + const scanY = wipe > 0 && wipe < 1 ? 900 * wipe : (rev > 0 && rev < 1 ? 900 * rev : -1); + const endFade = 1 - tw(T, authoredTotal - 1.1, authoredTotal - 0.05, M.move); + const colXc = lerp(368, 104, P5); + const colX = lerp(420, colXc, s2.p), colW = lerp(988, 760, s2.p); + const hdrRight = lerp(1408, colXc + 760, s2.p); + const logoX = lerp(88, colXc, s2.p); + const s3push = tw(s3.t, 1.9, 2.5), s3rise = (i) => tw(s3.t, 2.4 + i * 0.12, 3.1 + i * 0.12); + const s2push = tw(s2.t, 1.7, 2.2); + const tlY = 144 + 60 * s2push + 284 * s3push; + const panelX = 1000 + 440 * out; + const appIn = tw(T, 0, 0.5 * K, M.enter); + const zoom = lerp(1, 0.96, tw(T, CUES.After + 0.5 * K, CUES.After + 3 * K, M.move)); + + // wire geometry + const bb = btnRects(1408); + const afterBtn = { c: { x: 1408 - 188, y: 76, w: 140, h: 40 }, m: { x: 1368, y: 76, w: 40, h: 40 } }; + const ids = idRects(420); + const fTargets = [...ids.parts, { x: 520, y: 120, w: 84, h: 20 }, { x: 420, y: 120, w: 90, h: 20 }, { x: 604, y: 84, w: 104, h: 24 }]; + const tabsB3 = tabRects(368, 204); + const remB = { x: 368, y: 204 + 88 + 3 * 52 + 6, w: 760, h: 40 }; + const nyRows = [0, 1, 2].map(i => ({ x: 380, y: 204 + 52 + i * 64 + 8, w: 736, h: 48 })); + const tabs4 = tabRects(368, 488); + const dd = { x: 368 + 760 - 150, y: 494, w: 150, h: 32 }; + const titleR = { x: 368, y: 498, w: 90, h: 24 }; + + return
+ {/* app */} +
+
+ + + + + + + + + + 0.999 ? 0 : s5.after)} /> + + + + + + + + + + 0.001 ? 'visible' : 'hidden' }}> + + = 0 ? lerp(0.7, 0.3, PH[act].cdim) : 0.7)}> + + + + + {scanY >= 0 ? + + + : null} + + {/* 01 actions */} + {s1.focus > 0.001 ? + {bb.map((r, i) => { + const tgt = i === 3 ? afterBtn.c : i === 6 ? afterBtn.m : { x: afterBtn.m.x + 20, y: 96, w: 0, h: 0 }; + const keep = i === 3 || i === 6; + const tx = ['Add to list', 'Edit', 'Run workflow', 'Compose email', '★', '↑', '⋯'][i]; + return ; + })} + + {[0, 1, 2, 4, 5].map(i => )} + + + + : null} + + {/* 02 details */} + {s2.focus > 0.001 ? + + + {FILLED.map((f, i) => { const q = tw(s2.t, 2.2 + i * 0.1, 3.3 + i * 0.1); const txt = i < 5 ? ID_PARTS[i][0] : i === 5 ? 'Owner Alex' : i === 6 ? 'northwind.io' : 'Customer'; return 0.5} ts={q < 0.5 ? 12 : 13} />; })} + {EMPTY.map((e, i) => { const q = tw(s2.t, 1.9 + (13 - i) * 0.03, 2.6 + (13 - i) * 0.03); const r0 = rowR(8 + i); return ; })} + + + + + + + + + : null} + + {/* 03 open work */} + {s3.focus > 0.001 ? + + + + + + {nyRows.map((r, i) => { const o = tw(s3.t, 2.7 + i * 0.08, 3.2 + i * 0.08); return + + + ; })} + + {[256, 320, 384].map(y => )} + + + + + + + : null} + + {/* 04 timeline */} + {s4.focus > 0.001 ? + {tabs4.map((r, i) => )} + + + + {SYS.slice(0, 5).map((s_, i) => )} + {REL.map((r_, i) => )} + + + + + {[1, 2, 3, 4, 5].map(i => )} + + : null} + + {/* 05 panel */} + {s5.focus > 0.001 ? + + + {(() => { const px = lerp(1440, 1000, s5.p); return <> + + + + + + + + ; })()} + + + + + + + : null} + +
+
+ + {/* callout band, one at a time */} + {STEPS.map((st, i) => { + const ph = PH[i]; + if (ph.call <= 0.001) return null; + return
+ {st.n}{st.name.toUpperCase()} + {st.prob} + {st.fix} +
; + })} +
; +} + +function NorthwindBlueprintApp() { + return ; +} +window.NorthwindBlueprintApp = NorthwindBlueprintApp; diff --git a/skills/blueprint-animation/references/explain-mode.md b/skills/blueprint-animation/references/explain-mode.md new file mode 100644 index 0000000..ed78871 --- /dev/null +++ b/skills/blueprint-animation/references/explain-mode.md @@ -0,0 +1,55 @@ +# Explain mode (one screen, no Before) + +Section §8 of `cmk:blueprint-animation`. Adapted from [blueprint-animation](https://github.com/moguzbulbul/blueprint-animation) v1.3.1 by Oğuz (@moguzbulbul), CC BY-NC 4.0. + +## 8. Explain mode + +Same piece, same blueprint, same pacing. Nothing is redesigned: the blueprint is an x-ray that shows the reasoning behind each module. + +Per-step sequence (timings as in §2): + +| Phase | t | What happens | +|---|---|---| +| Focus | 0 → 0.9 | As Problem in §2. The text band shows number, name and **what**. | +| Blueprint in | 0.95 → 1.75 | As §2. Above the scan line, the WHOLE app is a blueprint drawing. | +| Annotate | 1.9 → c1 | Nothing moves. The module's wires stay in place; the static blueprint behind them dims 0.7 → 0.3. The reasoning draws in, staggered 0.08–0.12 s: handles on the key wires → guides → dimension line → labels. | +| Reveal | c1 + 0.05 → c1 + 0.85 | The scan line sweeps again and brings back the SAME real UI. | +| Hold | → end | The **why** sentence fades in. Then the focus fades out. | + +Pick the marks from the reason, 1–3 per step plus one dimension line: + +| The reason is about | Draw | +|---|---| +| Hierarchy, the primary action | Handles on the primary wire only; label "1 PRIMARY · 2 SECONDARY" | +| Alignment, grid, column | Dotted guides through the shared edges; dimension "CENTERED COLUMN · 760" | +| Spacing, rhythm | Dimension lines across the gaps: "GAP · 24" | +| Grouping | A dashed rect around the group; label naming it: "DEAL CONTEXT" | +| Reading order, flow | Accent number badges (`Num`) in reading order, joined by one arrowed `Line` | +| Size, hit area | A dimension on the element: "40 × 40" | +| Progressive disclosure | A label on the entry point: "14 EMPTY FIELDS BEHIND THIS" | +| Colour, state | A label naming the rule: "RED ONLY FOR OVERDUE" | + +Rules: +- The real UI is identical at the start and end of every step. There is no before/after swap; each region has one component. +- Wires never move or resize, so wire text stays visible the whole time (no `q` fade). +- Marks draw in (`Line` with `pathLength`, opacity ramps ≥ 0.3 s). They never slide across content. +- The number goes in the dimension label, the reason goes in the text band. Labels on the drawing name the rule, not the pixels. +- Text band: `[number badge · NAME] [what] [why]`. The why sits where the fix sits in Redesign mode (cyan). + +Architecture changes from §5 (`references/architecture.md`): +- `OM_SCENES`: `Screen, , End`. Where the redesign scene reads `CUES.After`, read `CUES.End`. +- Use the same `phases()`. Ignore `before`, `after` and `p`; drive each mark from a `ph.t` window inside 1.9 → c1 (for example `tw(ph.t, 2.0, 2.6, M.draw)`). +- Global layout values are constants. `StaticBP` takes no step props, so it renders once. +- A step's `` children are the module's own wires (with handles) plus its marks. + +QA: the §7 filmstrip (Annotate in place of mid-construct), plus: the real UI in the frame before Focus and the frame after Hold is pixel-identical for every step; no mark covers text. + +Example: the After screen of the reference scene (`references/example-scene.jsx`), explained. + +| # | Module | What | Why | Marks | +|---|---|---|---|---| +| 01 | Header actions | One button; the rest sit in ⋯. | You mostly send email, so that is one click. | handles on Compose · "1 ACTION + OVERFLOW" | +| 02 | Facts line | Eight facts on one line. | You read the company at a glance; empty fields stay out of sight. | guide on the baseline · "14 EMPTY FIELDS BEHIND THIS" on All details | +| 03 | Needs you | Open tasks sit above the timeline. | Overdue work is the first thing you see. | dashed group rect · `Num` 1–3 · "1 PRIMARY ACTION" | +| 04 | Timeline | One feed, Relationship view by default. | People and deals matter more than system events. | handles on the Relationship pill · "1 VIEW MENU" | +| 05 | Column | Content in one centred column. | Short lines are easier to scan on a wide screen. | guides at 368 and 1128 · "CENTERED COLUMN · 760" |