@struq/skill 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +141 -2
- package/cli/struq.mjs +132 -0
- package/package.json +41 -4
- package/skills/struq/SKILL.md +237 -0
- package/skills/struq/cinematic/README.md +409 -0
- package/skills/struq/cinematic/checklists/01-preproduction.md +15 -0
- package/skills/struq/cinematic/checklists/02-implementation.md +17 -0
- package/skills/struq/cinematic/checklists/03-polish.md +17 -0
- package/skills/struq/cinematic/examples/code/nextjs/README.md +13 -0
- package/skills/struq/cinematic/examples/code/nextjs/app/cinematic-experience.tsx +13 -0
- package/skills/struq/cinematic/examples/code/nextjs/app/components/LenisRoot.tsx +42 -0
- package/skills/struq/cinematic/examples/code/nextjs/app/page.tsx +6 -0
- package/skills/struq/cinematic/examples/code/shared/CameraRig.tsx +65 -0
- package/skills/struq/cinematic/examples/code/shared/ExperienceCanvas.tsx +20 -0
- package/skills/struq/cinematic/examples/code/shared/ExperienceDirector.tsx +57 -0
- package/skills/struq/cinematic/examples/code/shared/ExperienceOverlay.tsx +37 -0
- package/skills/struq/cinematic/examples/code/shared/ExperiencePage.tsx +52 -0
- package/skills/struq/cinematic/examples/code/shared/GsapFrameLoop.tsx +32 -0
- package/skills/struq/cinematic/examples/code/shared/InteriorRoot.tsx +30 -0
- package/skills/struq/cinematic/examples/code/shared/README.md +20 -0
- package/skills/struq/cinematic/examples/code/shared/SubjectRig.tsx +58 -0
- package/skills/struq/cinematic/examples/code/shared/build-experience-timeline.ts +237 -0
- package/skills/struq/cinematic/examples/code/shared/direction.ts +52 -0
- package/skills/struq/cinematic/examples/code/shared/gsap-client.ts +32 -0
- package/skills/struq/cinematic/examples/code/shared/math.ts +12 -0
- package/skills/struq/cinematic/examples/code/shared/registry.ts +58 -0
- package/skills/struq/cinematic/examples/code/shared/runtime.ts +52 -0
- package/skills/struq/cinematic/examples/code/shared/styles.css +127 -0
- package/skills/struq/cinematic/examples/code/shared/useExperienceInput.ts +42 -0
- package/skills/struq/cinematic/examples/code/vite/README.md +14 -0
- package/skills/struq/cinematic/examples/code/vite/src/App.tsx +11 -0
- package/skills/struq/cinematic/examples/code/vite/src/LenisRoot.tsx +37 -0
- package/skills/struq/cinematic/examples/code/vite/src/main.tsx +9 -0
- package/skills/struq/cinematic/examples/concise/01-chapter-spec-example.md +42 -0
- package/skills/struq/cinematic/examples/concise/02-handoff-example.md +25 -0
- package/skills/struq/cinematic/examples/concise/03-audit-finding-example.md +13 -0
- package/skills/struq/cinematic/examples/verbose/01-full-experience-direction.md +687 -0
- package/skills/struq/cinematic/examples/verbose/02-full-audit-example.md +362 -0
- package/skills/struq/cinematic/references/01-core-mental-model.md +221 -0
- package/skills/struq/cinematic/references/02-vocabulary.md +384 -0
- package/skills/struq/cinematic/references/03-experience-architecture.md +302 -0
- package/skills/struq/cinematic/references/04-timeline-choreography.md +264 -0
- package/skills/struq/cinematic/references/05-handoff-contracts.md +241 -0
- package/skills/struq/cinematic/references/06-three-rig-architecture.md +286 -0
- package/skills/struq/cinematic/references/07-stack-integration.md +228 -0
- package/skills/struq/cinematic/references/08-gsap-plugin-patterns.md +218 -0
- package/skills/struq/cinematic/references/09-tuning-harness.md +202 -0
- package/skills/struq/cinematic/references/10-quality-systems.md +206 -0
- package/skills/struq/cinematic/references/11-agent-workflows.md +246 -0
- package/skills/struq/cinematic/references/12-audit-rubric.md +176 -0
- package/skills/struq/cinematic/references/13-official-docs.md +53 -0
- package/skills/struq/cinematic/templates/01-experience-brief.md +105 -0
- package/skills/struq/cinematic/templates/02-experience-contract.md +80 -0
- package/skills/struq/cinematic/templates/03-chapter-spec.md +103 -0
- package/skills/struq/cinematic/templates/04-handoff-contract.md +102 -0
- package/skills/struq/cinematic/templates/05-ownership-matrix.md +29 -0
- package/skills/struq/cinematic/templates/06-shot-presets.md +59 -0
- package/skills/struq/cinematic/templates/07-implementation-slice.md +66 -0
- package/skills/struq/cinematic/templates/08-tuning-register.md +36 -0
- package/skills/struq/cinematic/templates/09-acceptance-tests.md +57 -0
- package/skills/struq/references/anti-patterns.md +265 -0
- package/skills/struq/references/baseline-prompt.md +118 -0
- package/skills/struq/references/brand.md +143 -0
- package/skills/struq/references/brief-router.md +219 -0
- package/skills/struq/references/composition.md +191 -0
- package/skills/struq/references/depth-parallax.md +235 -0
- package/skills/struq/references/direction.md +188 -0
- package/skills/struq/references/feel-layer.md +107 -0
- package/skills/struq/references/gsap-api.md +293 -0
- package/skills/struq/references/iconography.md +255 -0
- package/skills/struq/references/imagery.md +144 -0
- package/skills/struq/references/loaders.md +287 -0
- package/skills/struq/references/micro-interactions.md +270 -0
- package/skills/struq/references/mobile-composition.md +70 -0
- package/skills/struq/references/nav-header.md +296 -0
- package/skills/struq/references/page-architecture.md +134 -0
- package/skills/struq/references/page-entrances.md +198 -0
- package/skills/struq/references/performance.md +235 -0
- package/skills/struq/references/pinning-scrub.md +341 -0
- package/skills/struq/references/pitfalls.md +290 -0
- package/skills/struq/references/route-transitions.md +281 -0
- package/skills/struq/references/scaling.md +151 -0
- package/skills/struq/references/scroll-reveals.md +280 -0
- package/skills/struq/references/seo.md +219 -0
- package/skills/struq/references/setup.md +397 -0
- package/skills/struq/references/showcase.md +87 -0
- package/skills/struq/references/stack-targets.md +78 -0
- package/skills/struq/references/struq-imagery.md +107 -0
- package/skills/struq/references/svg-motion.md +390 -0
- package/skills/struq/references/transitions.md +160 -0
- package/skills/struq/references/triage.md +71 -0
- package/skills/struq/references/typography.md +720 -0
- package/skills/struq/references/vibe-presets.md +287 -0
- package/skills/struq/references/webgl-r3f.md +274 -0
- package/skills/struq/references/webgl-scenes.md +593 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Cinematic Transitions & Easing Philosophy
|
|
2
|
+
|
|
3
|
+
Two halves: the easing reference (used by every other file) and the transition patterns (page curtains, section curtains, shared-element moves).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Easing philosophy: why custom beziers feel "designed"
|
|
8
|
+
|
|
9
|
+
Default `ease-in-out` (`cubic-bezier(0.4, 0, 0.2, 1)`) is symmetric and polite: it accelerates and decelerates by similar amounts. Nothing in the physical world moves like that on arrival. Things that *arrive* decelerate hard at the end (a hand placing a glass); things that *leave* accelerate away. Designed motion encodes intent in the curve:
|
|
10
|
+
|
|
11
|
+
- **Entrances → strong out-eases.** Almost all the velocity happens in the first 20% of the duration, and the long deceleration tail is where the eye reads "settled, weighted, premium." This is why expo-out at 1s feels *faster* than ease-in-out at 0.5s: perceived speed is initial velocity, and perceived quality is the tail.
|
|
12
|
+
- **Exits → in-eases.** The element commits and accelerates away. Slow-decelerating exits read as reluctance or lag.
|
|
13
|
+
- **In-outs → only for things that move from A to B on screen** (curtains, position swaps, reordering) where both endpoints are visible.
|
|
14
|
+
- **Never linear** except scrub-tied values, where scroll itself is the easing.
|
|
15
|
+
|
|
16
|
+
### The beziers that actually ship
|
|
17
|
+
|
|
18
|
+
CSS-side (these go in `@theme`, see [vibe-presets.md](vibe-presets.md)) and their GSAP equivalents:
|
|
19
|
+
|
|
20
|
+
| Name | cubic-bezier | GSAP | Use for | Character |
|
|
21
|
+
|---|---|---|---|---|
|
|
22
|
+
| **expo-out** | `(0.16, 1, 0.3, 1)` | `expo.out` | reveals, hero entrances, masks | the agency default; violent start, infinite-feeling settle |
|
|
23
|
+
| **quart-out** | `(0.25, 1, 0.5, 1)` | `power3.out` | hovers, dropdowns, micro | expo's calmer sibling; snappy without drama |
|
|
24
|
+
| **quint-in-out** | `(0.83, 0, 0.17, 1)` | `power4.inOut` | curtains, wipes, panel slides | holds, then *commits*; the cinematic door |
|
|
25
|
+
| **quart-in-out** | `(0.76, 0, 0.24, 1)` | `power3.inOut` | position swaps, accordions | quint's softer sibling |
|
|
26
|
+
| **back-out** | `(0.34, 1.56, 0.64, 1)` | `back.out(1.4)` | badges, toasts, playful pops | 5-6% overshoot; personality, so ration it |
|
|
27
|
+
| **circ-out** | `(0, 0.55, 0.45, 1)` | `circ.out` | cursor effects, trailing UI | mechanical-smooth |
|
|
28
|
+
|
|
29
|
+
Per-vibe personality = picking 2 to 3 of these plus a duration scale ([vibe-presets.md](vibe-presets.md)). A site that uses expo-out/quint-in-out at 0.8 to 1.4s feels heavy and cinematic; the same site on quart-out/back-out at 0.25 to 0.6s feels kinetic and product-y.
|
|
30
|
+
|
|
31
|
+
For a true signature ease, GSAP `CustomEase.create("brand", "M0,0 C0.2,0 0.1,1 1,1")`. The table covers 99% of shipping needs.
|
|
32
|
+
|
|
33
|
+
**Cheap tell:** `transition-all duration-300 ease-in-out` on everything, `duration-500` on big things. **Instead:** Asymmetric curves chosen per role, durations spanning 0.2s→1.4s by element weight.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 1. Page transition curtain
|
|
38
|
+
|
|
39
|
+
The route curtain is one system, and it lives in [route-transitions.md](route-transitions.md): the GSAP `PageTransitionProvider` and `TransitionLink` (cover, swap, reveal), with session-gated loaders in [loaders.md](loaders.md) and per-zone entrances in [page-entrances.md](page-entrances.md). Build every multi-page site from there. The ease is quint-in-out for the panel and expo-out for the content rising behind it, per the table above.
|
|
40
|
+
|
|
41
|
+
**Cheap tell:** route changes hard-cut, or cross-fade via `opacity` on the whole page. **Instead:** A surface with a committed quint-in-out sweep, content rising in its wake.
|
|
42
|
+
|
|
43
|
+
<sub>Footnote: a Motion-only `app/template.tsx` that plays a reveal-on-mount curtain (no cover phase, because `template.tsx` cannot animate the old page out) is a valid stopgap for a two-page site that will never grow a provider. It is not the canonical system; prefer [route-transitions.md](route-transitions.md) whenever a site has more than two routes or a loader.</sub>
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 2. Section curtain (in-page)
|
|
48
|
+
|
|
49
|
+
**Term:** Surface handoff.
|
|
50
|
+
**Mechanic:** A section's background sweeps up over the previous section as it enters, so the *surface itself* transitions rather than content scrolling past a boundary. Scrub-tied curtain = the page feels like layered sheets.
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
"use client";
|
|
54
|
+
|
|
55
|
+
import { useRef } from "react";
|
|
56
|
+
import { gsap, useGSAP } from "@/lib/gsap";
|
|
57
|
+
|
|
58
|
+
export function CurtainSection({ children }: { children: React.ReactNode }) {
|
|
59
|
+
const container = useRef<HTMLElement>(null);
|
|
60
|
+
|
|
61
|
+
useGSAP(
|
|
62
|
+
() => {
|
|
63
|
+
gsap.fromTo(
|
|
64
|
+
container.current,
|
|
65
|
+
{ clipPath: "inset(100% 0% 0% 0%)" },
|
|
66
|
+
{
|
|
67
|
+
clipPath: "inset(0% 0% 0% 0%)",
|
|
68
|
+
ease: "none",
|
|
69
|
+
scrollTrigger: {
|
|
70
|
+
trigger: container.current,
|
|
71
|
+
start: "top bottom",
|
|
72
|
+
end: "top 25%",
|
|
73
|
+
scrub: true, // tied to the hand: the user drags the curtain up
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
{ scope: container }
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// -mt-[20vh] makes it sweep OVER the previous section's tail (see composition.md)
|
|
82
|
+
return (
|
|
83
|
+
<section ref={container} className="relative z-20 -mt-[20vh] bg-surface-2 px-6 py-32">
|
|
84
|
+
{children}
|
|
85
|
+
</section>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Use at 1 to 2 major act-breaks per page, on a strong surface change (surface-0 → surface-2, or the accent). Every section curtaining = visual exhaustion.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 3. Shared-element transition (`layoutId`)
|
|
95
|
+
|
|
96
|
+
**Term:** Shared-element / match-cut transition.
|
|
97
|
+
**Mechanic:** An element (project thumbnail) appears to *become* its counterpart in the next view (case-study hero). Motion interpolates position/scale between two elements sharing a `layoutId`. It is the strongest continuity illusion available in React, and pure Motion (GSAP has no equivalent; this is React-tree-aware layout animation).
|
|
98
|
+
|
|
99
|
+
This is the one place Motion genuinely beats GSAP, and it **complements** the canonical page-flow system: use the cover wipe ([route-transitions.md](route-transitions.md)) for route changes, and `layoutId` for list→detail moves *within* a route.
|
|
100
|
+
|
|
101
|
+
**When:** List→detail moves inside one route (modal/expanding card). Across App Router *pages*, `layoutId` does not survive the unmount/remount, so use the curtain instead, or keep the "detail" as an in-route overlay (parallel route/modal pattern) so both elements live in one tree.
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
"use client";
|
|
105
|
+
|
|
106
|
+
import { useState } from "react";
|
|
107
|
+
import { motion, AnimatePresence } from "motion/react";
|
|
108
|
+
|
|
109
|
+
export function ProjectGrid({ projects }: { projects: { id: string; img: string; title: string }[] }) {
|
|
110
|
+
const [active, setActive] = useState<string | null>(null);
|
|
111
|
+
const QUINT_INOUT = [0.83, 0, 0.17, 1] as const;
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<>
|
|
115
|
+
<div className="grid grid-cols-12 gap-4">
|
|
116
|
+
{projects.map((p) => (
|
|
117
|
+
<motion.button key={p.id} layoutId={`card-${p.id}`} onClick={() => setActive(p.id)}
|
|
118
|
+
className="col-span-4 overflow-hidden">
|
|
119
|
+
<motion.img layoutId={`img-${p.id}`} src={p.img} className="aspect-[4/3] w-full object-cover" />
|
|
120
|
+
</motion.button>
|
|
121
|
+
))}
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<AnimatePresence>
|
|
125
|
+
{active && (
|
|
126
|
+
<motion.div className="fixed inset-0 z-[90] bg-surface-0/90"
|
|
127
|
+
initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
|
|
128
|
+
onClick={() => setActive(null)}>
|
|
129
|
+
<motion.div layoutId={`card-${active}`} transition={{ duration: 0.6, ease: QUINT_INOUT }}
|
|
130
|
+
className="absolute inset-x-0 top-0 mx-auto max-w-5xl overflow-hidden">
|
|
131
|
+
<motion.img layoutId={`img-${active}`} src={projects.find((p) => p.id === active)!.img}
|
|
132
|
+
className="aspect-[16/9] w-full object-cover" />
|
|
133
|
+
</motion.div>
|
|
134
|
+
</motion.div>
|
|
135
|
+
)}
|
|
136
|
+
</AnimatePresence>
|
|
137
|
+
</>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Note the aspect-ratio change (4/3 → 16/9): Motion interpolates the crop too, which reads as a deliberate match-cut. Keep the moving element simple (an image, not a complex card), because layout animations of deep trees stutter.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 4. Stagger-out (the forgotten half)
|
|
147
|
+
|
|
148
|
+
Entrances get all the attention, but exits sell the system. When content leaves (accordion closing, filter change, modal dismiss), it should exit with the same system: `power2.in` (accelerating), ~60% of the entrance duration, reverse stagger (`stagger: { each: 0.04, from: "end" }`). Motion: `exit={{ y: -16, opacity: 0, transition: { duration: 0.35, ease: "easeIn" } }}` inside `AnimatePresence`. An interface whose exits are abrupt `display: none` while entrances are choreographed feels half-built. This asymmetry of care is a top-five LLM tell.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Transition decision table
|
|
153
|
+
|
|
154
|
+
| Situation | Tool | Pattern |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| Route change, narrative site | GSAP `PageTransitionProvider` | Route curtain ([route-transitions.md](route-transitions.md)) |
|
|
157
|
+
| Act-break between sections | GSAP scrub | Section curtain (§2) |
|
|
158
|
+
| List → detail, same route | Motion `layoutId` | Shared element (§3) |
|
|
159
|
+
| Anything mounting/unmounting | Motion `AnimatePresence` | Enter + designed exit (§4) |
|
|
160
|
+
| Scroll-driven anything | GSAP | other reference files |
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Triage: what to fix and what to leave alone
|
|
2
|
+
|
|
3
|
+
When Struq is invoked to **fix or improve an existing build** (not greenfield), the
|
|
4
|
+
failure mode is *over-correction*: rewriting the brand, the copy, and the component
|
|
5
|
+
library along with the actual problems, then handing back something the owner does not
|
|
6
|
+
recognize. This file is the restraint rule. Read it first on any remediation task.
|
|
7
|
+
|
|
8
|
+
The principle: **fix the execution, preserve the identity.** Type, spacing, surfaces,
|
|
9
|
+
motion, scaling, and icon misuse are execution, so they are fair game. Brand color, words,
|
|
10
|
+
and the component foundation are identity, so leave them unless explicitly asked.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Preserve by default: do NOT touch unless the user asks
|
|
15
|
+
|
|
16
|
+
### 1. Brand colors / palette
|
|
17
|
+
Keep the brand and accent hues as they are. You may fix **how** color is used
|
|
18
|
+
(remove a blue→purple gradient, fix a contrast failure, stop an accent appearing five times
|
|
19
|
+
per viewport) but do **not reassign the brand color** to something you find more
|
|
20
|
+
tasteful. If the brand is a specific blue, the fix keeps that blue and applies it with
|
|
21
|
+
restraint; it does not swap it for sienna because a preset uses sienna.
|
|
22
|
+
|
|
23
|
+
### 2. Copy / content
|
|
24
|
+
Do **not** rewrite headlines or body copy. Treat the existing words as fixed. Fix the
|
|
25
|
+
*typography, layout, and motion around* the copy, never the copy itself, unless the user
|
|
26
|
+
flags a specific line. (This is the opposite of greenfield, where you would write real copy
|
|
27
|
+
instead of lorem; here the copy already exists and is someone's decision.)
|
|
28
|
+
|
|
29
|
+
### 3. Component-library primitives
|
|
30
|
+
Do not rip out shadcn / Radix / the existing design-system base and replace it with custom
|
|
31
|
+
components. **Style within** the primitives: restyle the button, don't delete the
|
|
32
|
+
`<Button>`; retheme the card, don't swap the card library. The foundation stays; you
|
|
33
|
+
change its dress.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Fair game: fix freely (this is what you were called for)
|
|
38
|
+
|
|
39
|
+
- **Layout / structure / IA**: restructure sections, reorder, break the grid, fix the
|
|
40
|
+
symmetric "SaaS stack." Layout is execution, not identity. ([page-architecture.md](page-architecture.md))
|
|
41
|
+
- **Spacing rhythm**: kill uniform `py-16`, vary padding by section role.
|
|
42
|
+
- **Type scale + weight**: fix the five-mid-sizes problem, lighten hero weights, enforce
|
|
43
|
+
the readable floor and contrast minimums ([anti-patterns.md](anti-patterns.md) §12). If the
|
|
44
|
+
brand already owns its typefaces, keep them and change how they are set, not which they are
|
|
45
|
+
([typography.md](typography.md)).
|
|
46
|
+
- **Surfaces / elevation**: replace `shadow-lg` cards with the tonal ladder.
|
|
47
|
+
- **Motion / reveals**: replace opacity-only fades, add transform+stagger, fix easing.
|
|
48
|
+
- **Scaling**: convert px-everything + per-breakpoint size ladders to the fluid root-rem
|
|
49
|
+
system ([scaling.md](scaling.md)).
|
|
50
|
+
- **Icon misuse**: remove Sparkles/Rocket/Zap/emoji, colored chips, decorative filler;
|
|
51
|
+
consolidate to one icon family ([iconography.md](iconography.md)): the brand's own set if it has one, else Struq Icons (`@struq/icons`). A redesign that already uses one coherent non-Lucide family keeps it (preserve by default); one family per site, never mixed.
|
|
52
|
+
- **Everything in [anti-patterns.md](anti-patterns.md)**: that gallery is the fix list.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Workflow
|
|
57
|
+
|
|
58
|
+
1. **Scan** with [anti-patterns.md](anti-patterns.md) and collect every tell.
|
|
59
|
+
2. **Filter** the findings through the preserve-list above. A "fix" that reassigns brand
|
|
60
|
+
color, rewrites copy, or replaces a component primitive is dropped (or downgraded to a
|
|
61
|
+
*suggestion* the user can opt into), not applied.
|
|
62
|
+
3. **Apply** the remaining fixes.
|
|
63
|
+
4. **Report what you intentionally left unchanged and why**, for example: "kept your brand blue
|
|
64
|
+
and all copy; restyled gradient usage, spacing, type weights, and icons within your
|
|
65
|
+
existing shadcn components." This makes the restraint visible and lets the user lift any
|
|
66
|
+
preserved item into scope if they want it changed after all.
|
|
67
|
+
|
|
68
|
+
When unsure whether something is identity or execution, **ask** rather than assume, but
|
|
69
|
+
default to preserving the three categories above.
|
|
70
|
+
|
|
71
|
+
If the work started from a brief, [brief-router.md](brief-router.md) still runs, with this file's rules overriding it: identity is preserved and the router only re-decides execution.
|