mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
add swiss-user-research-video-template template skill (#1054)
Introduce a Swiss editorial user-research live-artifact template with self-contained HTML seed/example and checklist, and register i18n fallback ids for DE/FR/RU so localized coverage stays green. Co-authored-by: Tuola Ge <gexingli@refly.ai> Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
ecddcd4fbd
commit
dd439c29bf
7 changed files with 637 additions and 0 deletions
|
|
@ -366,6 +366,7 @@ export const FR_SKILL_IDS_WITH_EN_FALLBACK = [
|
|||
// Fallback for now so the localized-content coverage test passes.
|
||||
'social-media-dashboard',
|
||||
'social-media-matrix-tracker-template',
|
||||
'swiss-user-research-video-template',
|
||||
'web-prototype-taste-brutalist',
|
||||
'web-prototype-taste-editorial',
|
||||
'web-prototype-taste-soft',
|
||||
|
|
|
|||
|
|
@ -366,6 +366,7 @@ export const RU_SKILL_IDS_WITH_EN_FALLBACK = [
|
|||
// Fallback for now so the localized-content coverage test passes.
|
||||
'social-media-dashboard',
|
||||
'social-media-matrix-tracker-template',
|
||||
'swiss-user-research-video-template',
|
||||
'web-prototype-taste-brutalist',
|
||||
'web-prototype-taste-editorial',
|
||||
'web-prototype-taste-soft',
|
||||
|
|
|
|||
|
|
@ -415,6 +415,7 @@ const DE_SKILL_IDS_WITH_EN_FALLBACK = [
|
|||
// Fallback for now so the localized-content coverage test passes.
|
||||
'social-media-dashboard',
|
||||
'social-media-matrix-tracker-template',
|
||||
'swiss-user-research-video-template',
|
||||
'web-prototype-taste-brutalist',
|
||||
'web-prototype-taste-editorial',
|
||||
'web-prototype-taste-soft',
|
||||
|
|
|
|||
80
skills/swiss-user-research-video-template/SKILL.md
Normal file
80
skills/swiss-user-research-video-template/SKILL.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
name: swiss-user-research-video-template
|
||||
description: |
|
||||
Swiss-style user-research narrative template in warm-paper editorial aesthetics.
|
||||
Use when users ask for a premium research deck or story-first live artifact with
|
||||
minimalist typography, high-clarity layout, subtle motion, donut breakdowns,
|
||||
and keyboard/click navigation across slides in a single HTML file.
|
||||
triggers:
|
||||
- "swiss user research template"
|
||||
- "editorial research deck template"
|
||||
- "minimal user research slides"
|
||||
- "warm paper swiss style"
|
||||
- "research synthesis template"
|
||||
- "瑞士风用户研究模板"
|
||||
- "高级调性研究汇报"
|
||||
od:
|
||||
mode: template
|
||||
platform: desktop
|
||||
scenario: live-artifacts
|
||||
preview:
|
||||
type: html
|
||||
entry: index.html
|
||||
reload: debounce-100
|
||||
design_system:
|
||||
requires: true
|
||||
sections: [color, typography, layout, components]
|
||||
outputs:
|
||||
primary: index.html
|
||||
secondary:
|
||||
- template.html
|
||||
- example.html
|
||||
example_prompt: "Create a Swiss-style user research synthesis deck with premium minimalist typography, warm paper tone, a participant donut breakdown, and subtle editorial interactions."
|
||||
capabilities_required:
|
||||
- file_write
|
||||
---
|
||||
|
||||
# Swiss User Research Video Template
|
||||
|
||||
A premium Swiss-editorial user research template for narrative-heavy live artifacts.
|
||||
The visual language is warm paper, strict spacing rhythm, thin rules, and restrained
|
||||
micro-interactions that keep attention on the story.
|
||||
|
||||
## Resource map
|
||||
|
||||
```text
|
||||
swiss-user-research-video-template/
|
||||
├── SKILL.md
|
||||
├── assets/
|
||||
│ └── template.html
|
||||
├── references/
|
||||
│ └── checklist.md
|
||||
└── example.html
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Read `DESIGN.md`, then map tokens to the template CSS variables (`--paper`, `--ink`, `--muted`, rule colors, segment colors) without changing layout semantics.
|
||||
2. Start from `assets/template.html`; keep the three-slide structure:
|
||||
- title / framing
|
||||
- participant breakdown donut
|
||||
- behavioral pattern + evidence panel
|
||||
3. Preserve interactions:
|
||||
- click/keyboard slide navigation (`ArrowLeft`/`ArrowRight`)
|
||||
- bottom pagination dots with active state
|
||||
- donut legend hover highlight
|
||||
- subtle line-draw and panel-lift transitions
|
||||
4. Keep all data realistic and internally consistent between copy, donut labels, and percentages.
|
||||
5. Keep HTML self-contained (inline CSS/JS), with no external framework dependencies.
|
||||
6. Validate using `references/checklist.md` before output.
|
||||
|
||||
## Output contract
|
||||
|
||||
Emit one concise orientation sentence and then a single HTML artifact:
|
||||
|
||||
```xml
|
||||
<artifact identifier="swiss-user-research-deck" type="text/html" title="Swiss User Research Synthesis">
|
||||
<!doctype html>
|
||||
<html>...</html>
|
||||
</artifact>
|
||||
```
|
||||
265
skills/swiss-user-research-video-template/assets/template.html
Normal file
265
skills/swiss-user-research-video-template/assets/template.html
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Swiss User Research Template</title>
|
||||
<style>
|
||||
:root {
|
||||
--paper: #f7f6ea;
|
||||
--ink: #161616;
|
||||
--muted: #5d5a51;
|
||||
--line: rgba(22, 22, 22, 0.2);
|
||||
--seg1: #171717;
|
||||
--seg2: #595959;
|
||||
--seg3: #8b8b84;
|
||||
--seg4: #c8c8bf;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, "Helvetica Neue", Arial, sans-serif;
|
||||
background: var(--paper);
|
||||
color: var(--ink);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.deck {
|
||||
max-width: 1360px;
|
||||
min-height: 860px;
|
||||
margin: 26px auto;
|
||||
border: 1px solid rgba(22, 22, 22, 0.08);
|
||||
background: var(--paper);
|
||||
box-shadow: 0 18px 60px rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 14px 20px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.18em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
}
|
||||
.toolbar .btns { display: flex; gap: 8px; }
|
||||
.toolbar button {
|
||||
border: 1px solid var(--line);
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
border-radius: 999px;
|
||||
height: 30px;
|
||||
padding: 0 12px;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.08em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.slides { position: relative; flex: 1; }
|
||||
.slide {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
padding: 52px 64px;
|
||||
opacity: 0;
|
||||
transform: translateX(28px);
|
||||
transition: opacity .45s ease, transform .45s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
.slide.active {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
pointer-events: auto;
|
||||
}
|
||||
.rule-top, .rule-bottom {
|
||||
height: 1px;
|
||||
background: var(--line);
|
||||
transform-origin: 0 50%;
|
||||
transform: scaleX(0);
|
||||
transition: transform .6s ease;
|
||||
}
|
||||
.slide.active .rule-top, .slide.active .rule-bottom { transform: scaleX(1); }
|
||||
.meta { font-size: 11px; letter-spacing: .24em; text-transform: uppercase; color: var(--muted); }
|
||||
h1, h2 { font-weight: 300; letter-spacing: -0.02em; margin: 0; }
|
||||
h1 { font-size: 88px; line-height: 1.02; margin-top: 24px; }
|
||||
h2 { font-size: 58px; line-height: 1.05; margin-top: 18px; }
|
||||
p { color: var(--muted); line-height: 1.55; }
|
||||
.s1-main { margin-top: 84px; max-width: 980px; }
|
||||
.s1-main p { font-size: 24px; max-width: 760px; margin-top: 26px; }
|
||||
.foot {
|
||||
position: absolute;
|
||||
left: 64px;
|
||||
right: 64px;
|
||||
bottom: 44px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 11px;
|
||||
letter-spacing: .2em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
}
|
||||
.s2-grid {
|
||||
margin-top: 52px;
|
||||
display: grid;
|
||||
grid-template-columns: 420px 1fr;
|
||||
gap: 80px;
|
||||
align-items: center;
|
||||
}
|
||||
.donut-wrap { width: 420px; height: 420px; margin: 0 auto; }
|
||||
.legend { display: grid; gap: 18px; }
|
||||
.legend-row {
|
||||
display: grid;
|
||||
grid-template-columns: 16px 1fr auto;
|
||||
gap: 14px;
|
||||
align-items: center;
|
||||
font-size: 21px;
|
||||
transition: transform .2s ease;
|
||||
}
|
||||
.legend-row:hover { transform: translateX(6px); }
|
||||
.swatch { width: 16px; height: 16px; border-radius: 2px; }
|
||||
.pct { font-variant-numeric: tabular-nums; color: var(--muted); font-size: 20px; }
|
||||
.s3-grid {
|
||||
margin-top: 44px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 520px;
|
||||
gap: 52px;
|
||||
}
|
||||
.s3-grid p { font-size: 29px; max-width: 760px; margin-top: 16px; }
|
||||
.bullets { margin-top: 30px; display: grid; gap: 14px; font-size: 20px; }
|
||||
.bullets div { padding-left: 24px; position: relative; }
|
||||
.bullets div::before { content: "—"; position: absolute; left: 0; color: var(--muted); }
|
||||
.evidence {
|
||||
border: 1px solid var(--line);
|
||||
min-height: 360px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: var(--muted);
|
||||
position: relative;
|
||||
background: linear-gradient(140deg, rgba(0, 0, 0, 0.02), rgba(0, 0, 0, 0.06));
|
||||
transition: box-shadow .3s ease, transform .3s ease;
|
||||
}
|
||||
.evidence:hover {
|
||||
box-shadow: 0 24px 48px rgba(0, 0, 0, 0.12);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.cap { font-size: 12px; letter-spacing: .1em; margin-top: 14px; color: var(--muted); }
|
||||
.dots {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 14px;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
z-index: 20;
|
||||
}
|
||||
.dots button {
|
||||
width: 9px; height: 9px; border-radius: 50%;
|
||||
border: 1px solid var(--ink);
|
||||
background: transparent; cursor: pointer;
|
||||
}
|
||||
.dots button.active { background: var(--ink); transform: scale(1.3); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="deck">
|
||||
<header class="toolbar">
|
||||
<span>Swiss research template</span>
|
||||
<div class="btns">
|
||||
<button type="button" id="prevBtn">Prev</button>
|
||||
<button type="button" id="nextBtn">Next</button>
|
||||
</div>
|
||||
</header>
|
||||
<section class="slides">
|
||||
<article class="slide active" data-slide="0">
|
||||
<div class="rule-top"></div>
|
||||
<div class="s1-main">
|
||||
<div class="meta">User research synthesis · [month, year]</div>
|
||||
<h1>User Research Synthesis</h1>
|
||||
<p>What we learned from [N] interviews and what it means for the product.</p>
|
||||
</div>
|
||||
<div class="rule-bottom" style="margin-top: 84px;"></div>
|
||||
<div class="foot"><span>Research team · [month, year]</span><span>Round [N] · Internal</span></div>
|
||||
</article>
|
||||
|
||||
<article class="slide" data-slide="1">
|
||||
<div class="rule-top"></div>
|
||||
<div class="meta" style="margin-top: 10px;">Participant breakdown</div>
|
||||
<h2>Who we spoke with</h2>
|
||||
<div class="s2-grid">
|
||||
<div class="donut-wrap">
|
||||
<svg viewBox="0 0 400 400" width="420" height="420" aria-label="Participant donut">
|
||||
<g transform="translate(200 200) rotate(-90)" fill="none" stroke-width="38">
|
||||
<circle r="118" cx="0" cy="0" stroke="var(--seg1)" stroke-dasharray="283.39 741.78"></circle>
|
||||
<circle r="118" cx="0" cy="0" stroke="var(--seg2)" stroke-dasharray="186.44 741.78" stroke-dashoffset="-283.39"></circle>
|
||||
<circle r="118" cx="0" cy="0" stroke="var(--seg3)" stroke-dasharray="163.19 741.78" stroke-dashoffset="-469.83"></circle>
|
||||
<circle r="118" cx="0" cy="0" stroke="var(--seg4)" stroke-dasharray="108.76 741.78" stroke-dashoffset="-633.02"></circle>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="legend">
|
||||
<div class="legend-row"><span class="swatch" style="background:var(--seg1)"></span><span>Power users</span><span class="pct">38%</span></div>
|
||||
<div class="legend-row"><span class="swatch" style="background:var(--seg2)"></span><span>Casual users</span><span class="pct">25%</span></div>
|
||||
<div class="legend-row"><span class="swatch" style="background:var(--seg3)"></span><span>Churn-risk users</span><span class="pct">22%</span></div>
|
||||
<div class="legend-row"><span class="swatch" style="background:var(--seg4)"></span><span>Prospects</span><span class="pct">15%</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rule-bottom" style="margin-top: 18px;"></div>
|
||||
<div class="foot"><span>Source: Recruitment screener</span><span>Total participants: [N]</span></div>
|
||||
</article>
|
||||
|
||||
<article class="slide" data-slide="2">
|
||||
<div class="rule-top"></div>
|
||||
<div class="s3-grid">
|
||||
<div>
|
||||
<div class="meta">The pattern</div>
|
||||
<h2>The first 48 hours determine everything</h2>
|
||||
<p>Users who complete three core actions in their first two days have a 4x higher 90-day retention rate.</p>
|
||||
<div class="bullets">
|
||||
<div>Onboarding drop-off peaks at step 3</div>
|
||||
<div>"What do I do next?" is the most common exit trigger</div>
|
||||
<div>Users who invite a teammate retain at 2x the rate</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="evidence">Image placeholder</div>
|
||||
<div class="cap">Session recording review · [month of study]</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rule-bottom" style="margin-top: 24px;"></div>
|
||||
<div class="foot"><span>User research synthesis</span><span>Research team</span></div>
|
||||
</article>
|
||||
</section>
|
||||
<nav class="dots" aria-label="Slide navigation">
|
||||
<button type="button" class="active" data-dot="0" aria-label="Slide 1"></button>
|
||||
<button type="button" data-dot="1" aria-label="Slide 2"></button>
|
||||
<button type="button" data-dot="2" aria-label="Slide 3"></button>
|
||||
</nav>
|
||||
</main>
|
||||
<script>
|
||||
(function () {
|
||||
const slides = Array.from(document.querySelectorAll(".slide"));
|
||||
const dots = Array.from(document.querySelectorAll(".dots button"));
|
||||
let idx = 0;
|
||||
const max = slides.length - 1;
|
||||
|
||||
function show(next) {
|
||||
idx = Math.max(0, Math.min(max, next));
|
||||
slides.forEach((el, i) => el.classList.toggle("active", i === idx));
|
||||
dots.forEach((el, i) => el.classList.toggle("active", i === idx));
|
||||
}
|
||||
|
||||
document.getElementById("prevBtn").addEventListener("click", () => show(idx - 1));
|
||||
document.getElementById("nextBtn").addEventListener("click", () => show(idx + 1));
|
||||
dots.forEach((dot, i) => dot.addEventListener("click", () => show(i)));
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key === "ArrowLeft") show(idx - 1);
|
||||
if (event.key === "ArrowRight") show(idx + 1);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
265
skills/swiss-user-research-video-template/example.html
Normal file
265
skills/swiss-user-research-video-template/example.html
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>User Research Synthesis Example</title>
|
||||
<style>
|
||||
:root {
|
||||
--paper: #f7f6ea;
|
||||
--ink: #161616;
|
||||
--muted: #5d5a51;
|
||||
--line: rgba(22, 22, 22, 0.2);
|
||||
--seg1: #171717;
|
||||
--seg2: #595959;
|
||||
--seg3: #8b8b84;
|
||||
--seg4: #c8c8bf;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, "Helvetica Neue", Arial, sans-serif;
|
||||
background: var(--paper);
|
||||
color: var(--ink);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.deck {
|
||||
max-width: 1360px;
|
||||
min-height: 860px;
|
||||
margin: 26px auto;
|
||||
border: 1px solid rgba(22, 22, 22, 0.08);
|
||||
background: var(--paper);
|
||||
box-shadow: 0 18px 60px rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 14px 20px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.18em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
}
|
||||
.toolbar .btns { display: flex; gap: 8px; }
|
||||
.toolbar button {
|
||||
border: 1px solid var(--line);
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
border-radius: 999px;
|
||||
height: 30px;
|
||||
padding: 0 12px;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.08em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.slides { position: relative; flex: 1; }
|
||||
.slide {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
padding: 52px 64px;
|
||||
opacity: 0;
|
||||
transform: translateX(28px);
|
||||
transition: opacity .45s ease, transform .45s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
.slide.active {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
pointer-events: auto;
|
||||
}
|
||||
.rule-top, .rule-bottom {
|
||||
height: 1px;
|
||||
background: var(--line);
|
||||
transform-origin: 0 50%;
|
||||
transform: scaleX(0);
|
||||
transition: transform .6s ease;
|
||||
}
|
||||
.slide.active .rule-top, .slide.active .rule-bottom { transform: scaleX(1); }
|
||||
.meta { font-size: 11px; letter-spacing: .24em; text-transform: uppercase; color: var(--muted); }
|
||||
h1, h2 { font-weight: 300; letter-spacing: -0.02em; margin: 0; }
|
||||
h1 { font-size: 88px; line-height: 1.02; margin-top: 24px; }
|
||||
h2 { font-size: 58px; line-height: 1.05; margin-top: 18px; }
|
||||
p { color: var(--muted); line-height: 1.55; }
|
||||
.s1-main { margin-top: 84px; max-width: 980px; }
|
||||
.s1-main p { font-size: 24px; max-width: 760px; margin-top: 26px; }
|
||||
.foot {
|
||||
position: absolute;
|
||||
left: 64px;
|
||||
right: 64px;
|
||||
bottom: 44px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 11px;
|
||||
letter-spacing: .2em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
}
|
||||
.s2-grid {
|
||||
margin-top: 52px;
|
||||
display: grid;
|
||||
grid-template-columns: 420px 1fr;
|
||||
gap: 80px;
|
||||
align-items: center;
|
||||
}
|
||||
.donut-wrap { width: 420px; height: 420px; margin: 0 auto; }
|
||||
.legend { display: grid; gap: 18px; }
|
||||
.legend-row {
|
||||
display: grid;
|
||||
grid-template-columns: 16px 1fr auto;
|
||||
gap: 14px;
|
||||
align-items: center;
|
||||
font-size: 21px;
|
||||
transition: transform .2s ease;
|
||||
}
|
||||
.legend-row:hover { transform: translateX(6px); }
|
||||
.swatch { width: 16px; height: 16px; border-radius: 2px; }
|
||||
.pct { font-variant-numeric: tabular-nums; color: var(--muted); font-size: 20px; }
|
||||
.s3-grid {
|
||||
margin-top: 44px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 520px;
|
||||
gap: 52px;
|
||||
}
|
||||
.s3-grid p { font-size: 29px; max-width: 760px; margin-top: 16px; }
|
||||
.bullets { margin-top: 30px; display: grid; gap: 14px; font-size: 20px; }
|
||||
.bullets div { padding-left: 24px; position: relative; }
|
||||
.bullets div::before { content: "—"; position: absolute; left: 0; color: var(--muted); }
|
||||
.evidence {
|
||||
border: 1px solid var(--line);
|
||||
min-height: 360px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: var(--muted);
|
||||
position: relative;
|
||||
background: linear-gradient(140deg, rgba(0, 0, 0, 0.02), rgba(0, 0, 0, 0.06));
|
||||
transition: box-shadow .3s ease, transform .3s ease;
|
||||
}
|
||||
.evidence:hover {
|
||||
box-shadow: 0 24px 48px rgba(0, 0, 0, 0.12);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.cap { font-size: 12px; letter-spacing: .1em; margin-top: 14px; color: var(--muted); }
|
||||
.dots {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 14px;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
z-index: 20;
|
||||
}
|
||||
.dots button {
|
||||
width: 9px; height: 9px; border-radius: 50%;
|
||||
border: 1px solid var(--ink);
|
||||
background: transparent; cursor: pointer;
|
||||
}
|
||||
.dots button.active { background: var(--ink); transform: scale(1.3); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="deck">
|
||||
<header class="toolbar">
|
||||
<span>Swiss research synthesis</span>
|
||||
<div class="btns">
|
||||
<button type="button" id="prevBtn">Prev</button>
|
||||
<button type="button" id="nextBtn">Next</button>
|
||||
</div>
|
||||
</header>
|
||||
<section class="slides">
|
||||
<article class="slide active" data-slide="0">
|
||||
<div class="rule-top"></div>
|
||||
<div class="s1-main">
|
||||
<div class="meta">User research synthesis · May, 2026</div>
|
||||
<h1>User Research Synthesis</h1>
|
||||
<p>What we learned from 24 interviews and what it means for the product roadmap.</p>
|
||||
</div>
|
||||
<div class="rule-bottom" style="margin-top: 84px;"></div>
|
||||
<div class="foot"><span>Research team · May, 2026</span><span>Round 1 · Internal</span></div>
|
||||
</article>
|
||||
|
||||
<article class="slide" data-slide="1">
|
||||
<div class="rule-top"></div>
|
||||
<div class="meta" style="margin-top: 10px;">Participant breakdown</div>
|
||||
<h2>Who we spoke with</h2>
|
||||
<div class="s2-grid">
|
||||
<div class="donut-wrap">
|
||||
<svg viewBox="0 0 400 400" width="420" height="420" aria-label="Participant donut">
|
||||
<g transform="translate(200 200) rotate(-90)" fill="none" stroke-width="38">
|
||||
<circle r="118" cx="0" cy="0" stroke="var(--seg1)" stroke-dasharray="283.39 741.78"></circle>
|
||||
<circle r="118" cx="0" cy="0" stroke="var(--seg2)" stroke-dasharray="186.44 741.78" stroke-dashoffset="-283.39"></circle>
|
||||
<circle r="118" cx="0" cy="0" stroke="var(--seg3)" stroke-dasharray="163.19 741.78" stroke-dashoffset="-469.83"></circle>
|
||||
<circle r="118" cx="0" cy="0" stroke="var(--seg4)" stroke-dasharray="108.76 741.78" stroke-dashoffset="-633.02"></circle>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="legend">
|
||||
<div class="legend-row"><span class="swatch" style="background:var(--seg1)"></span><span>Power users</span><span class="pct">38%</span></div>
|
||||
<div class="legend-row"><span class="swatch" style="background:var(--seg2)"></span><span>Casual users</span><span class="pct">25%</span></div>
|
||||
<div class="legend-row"><span class="swatch" style="background:var(--seg3)"></span><span>Churn-risk users</span><span class="pct">22%</span></div>
|
||||
<div class="legend-row"><span class="swatch" style="background:var(--seg4)"></span><span>Prospects</span><span class="pct">15%</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rule-bottom" style="margin-top: 18px;"></div>
|
||||
<div class="foot"><span>Source: Recruitment screener</span><span>Total participants: 24</span></div>
|
||||
</article>
|
||||
|
||||
<article class="slide" data-slide="2">
|
||||
<div class="rule-top"></div>
|
||||
<div class="s3-grid">
|
||||
<div>
|
||||
<div class="meta">The pattern</div>
|
||||
<h2>The first 48 hours determine everything</h2>
|
||||
<p>Users who complete three core actions in their first two days have a 4x higher 90-day retention rate.</p>
|
||||
<div class="bullets">
|
||||
<div>Onboarding drop-off peaks at step 3</div>
|
||||
<div>"What do I do next?" is the most common exit trigger</div>
|
||||
<div>Users who invite a teammate retain at 2x the rate</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="evidence">Session image placeholder</div>
|
||||
<div class="cap">Session recording review · April, 2026</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rule-bottom" style="margin-top: 24px;"></div>
|
||||
<div class="foot"><span>User research synthesis</span><span>Research team</span></div>
|
||||
</article>
|
||||
</section>
|
||||
<nav class="dots" aria-label="Slide navigation">
|
||||
<button type="button" class="active" data-dot="0" aria-label="Slide 1"></button>
|
||||
<button type="button" data-dot="1" aria-label="Slide 2"></button>
|
||||
<button type="button" data-dot="2" aria-label="Slide 3"></button>
|
||||
</nav>
|
||||
</main>
|
||||
<script>
|
||||
(function () {
|
||||
const slides = Array.from(document.querySelectorAll(".slide"));
|
||||
const dots = Array.from(document.querySelectorAll(".dots button"));
|
||||
let idx = 0;
|
||||
const max = slides.length - 1;
|
||||
|
||||
function show(next) {
|
||||
idx = Math.max(0, Math.min(max, next));
|
||||
slides.forEach((el, i) => el.classList.toggle("active", i === idx));
|
||||
dots.forEach((el, i) => el.classList.toggle("active", i === idx));
|
||||
}
|
||||
|
||||
document.getElementById("prevBtn").addEventListener("click", () => show(idx - 1));
|
||||
document.getElementById("nextBtn").addEventListener("click", () => show(idx + 1));
|
||||
dots.forEach((dot, i) => dot.addEventListener("click", () => show(i)));
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key === "ArrowLeft") show(idx - 1);
|
||||
if (event.key === "ArrowRight") show(idx + 1);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# Checklist
|
||||
|
||||
## P0
|
||||
|
||||
- `assets/template.html` exists and opens directly from disk.
|
||||
- `example.html` is complete and uses realistic user-research labels and values.
|
||||
- Skill frontmatter uses `od.mode: template` and `od.scenario: live-artifacts`.
|
||||
- Exactly three slides are present, and nav dots reflect active slide.
|
||||
- Keyboard navigation works (`ArrowLeft` / `ArrowRight`) and click navigation works.
|
||||
- Participant donut and legend percentages are consistent (sum to 100%).
|
||||
- No sandbox-hostile APIs are used (`localStorage`, `sessionStorage`, `alert`, `confirm`, `prompt`, `window.open`).
|
||||
|
||||
## P1
|
||||
|
||||
- Visual language stays Swiss-editorial: warm paper tone, thin rule lines, restrained typography.
|
||||
- Motion remains subtle and legible: no looping flashy effects or jitter.
|
||||
- Layout remains readable on common laptop widths (>= 1280px) without overlap.
|
||||
- Right-panel evidence card in slide 3 includes caption and not just decorative framing.
|
||||
|
||||
## P2
|
||||
|
||||
- Dot navigation is clearly visible on both light and dark room environments.
|
||||
- Legend hover emphasis does not hide percentage values.
|
||||
- Slide transitions feel consistent in duration and easing.
|
||||
Loading…
Reference in a new issue