Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions learn/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,17 @@ assets/icon-index.json
# Python bytecode cache, and the audition_voices.py voice cache.
__pycache__/
.voice-catalog.json

# --- cloud handoff: Meet-Microsoft-Scout ---
# Source of this video's composition is tracked so the cloud builder can hand it back;
# renders + heavy artifacts stay local-only. Never merged to main.
!output/
output/*
!output/Meet-Microsoft-Scout/
!output/Meet-Microsoft-Scout/**
# never the licensed Segoe woff2 (regenerable locally; cloud renders on fallback fonts)
output/Meet-Microsoft-Scout/fonts/
# ignore render OUTPUTS only — keep input media (end card, screen recordings) tracked
output/Meet-Microsoft-Scout/renders/
output/Meet-Microsoft-Scout/Meet-Microsoft-Scout.mp4
output/Meet-Microsoft-Scout/Meet-Microsoft-Scout_thumbnail.png
24 changes: 24 additions & 0 deletions learn/output/Meet-Microsoft-Scout/BRIEF.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Meet Microsoft Scout

- **Profile:** `companion-short` — Learn companion video (short)
- **Target:** ~105s content (60–180s), word budget 145–435 (target 254) @ 2.42 w/s
- **Scenes:** aim ~5 (chrome 5 stamped + ~1-10 body)
- **Max static hold:** 4.0s · **Voice:** en-US-Ava:DragonHDLatestNeural
- **Source:** https://learn.microsoft.com/en-us/microsoft-scout/use-microsoft-scout

## Fill the placeholders

Every `__FILL__` below must be replaced before render (guarded by `tools/check_placeholders.py`).

- `opening.bumper` → [scenes/01-bumper.html](scenes/01-bumper.html)
- `opening.title` → [scenes/02-title.html](scenes/02-title.html)
- `opening.objectives` → [scenes/03-objectives.html](scenes/03-objectives.html)
- `closing.recap` → [scenes/90-recap.html](scenes/90-recap.html)
- `closing.cta` → [scenes/91-cta.html](scenes/91-cta.html)

## Next steps

1. Write the script + beat plan (script-writer) and fill the chrome placeholders above.
2. Author the teaching-body scenes into `scenes/` and insert them into `scenes.json` between the opening and closing chrome (see `scenes.json` → `body_slot`).
3. Run the gated pipeline (voice → fact-check QA → build → snapshot QA → render).
4. Guard: `py tools/check_placeholders.py --project .` must be clean before render.
93 changes: 93 additions & 0 deletions learn/output/Meet-Microsoft-Scout/anchors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// GENERATED by tools/word_anchors.py - do not hand-edit.
// Every value is a REAL spoken-word time from transcript.json,
// with a 3.0s lead-in applied. Regenerate after any re-record.
window.__anchors = {
"t2Kicker": 3.03,
"t2KickerEnd": 3.54,
"t2Meet": 4.99,
"t2MeetEnd": 5.53,
"t2Name": 6.53,
"t2NameEnd": 8.33,
"t2Rule": 7.39,
"t2RuleEnd": 8.33,
"t2Sub": 7.92,
"t2SubEnd": 8.88,
"t3One": 10.4,
"t3OneEnd": 11.96,
"t3Three": 14.28,
"t3ThreeEnd": 15.29,
"t3Two": 12.39,
"t3TwoEnd": 13.56,
"t4AlwaysOn": 21.65,
"t4AlwaysOnEnd": 22.63,
"t4Autopilot": 18.82,
"t4AutopilotEnd": 19.74,
"t4Behalf": 27.71,
"t4BehalfEnd": 28.68,
"t4Calendar": 35.13,
"t4CalendarEnd": 35.76,
"t4Files": 36.5,
"t4FilesEnd": 37.16,
"t4Grounded": 29.25,
"t4GroundedEnd": 30.1,
"t4Identity": 25.45,
"t4IdentityEnd": 26.48,
"t4M365": 31.13,
"t4M365End": 32.62,
"t4Outlook": 34.14,
"t4OutlookEnd": 34.87,
"t4Teams": 33.64,
"t4TeamsEnd": 34.14,
"t5Cap1": 50.63,
"t5Cap1End": 52.28,
"t5Cap2": 52.43,
"t5Cap2End": 53.54,
"t5Cap3": 54.78,
"t5Cap3End": 56.2,
"t5Header": 38.31,
"t5HeaderEnd": 38.86,
"t5Row1": 40.65,
"t5Row1End": 41.73,
"t5Row2": 42.99,
"t5Row2End": 43.61,
"t5Row3": 45.39,
"t5Row3End": 46.25,
"t5Row4": 47.15,
"t5Row4End": 48.07,
"t6Identity": 60.43,
"t6IdentityEnd": 61.4,
"t6Moment": 68.81,
"t6MomentEnd": 68.92,
"t6Permissions": 64.38,
"t6PermissionsEnd": 65.21,
"t6Purview": 66.5,
"t6PurviewEnd": 66.85,
"t6Sensitive": 70.01,
"t6SensitiveEnd": 70.49,
"t6Shared": 62.75,
"t6SharedEnd": 63.54,
"t6Signoff": 72.81,
"t6SignoffEnd": 73.52,
"t6Trusted": 57.62,
"t6TrustedEnd": 58.24,
"t90Kicker": 73.55,
"t90KickerEnd": 74.41,
"t90Line1": 73.8,
"t90Line1End": 74.99,
"t90Line2": 74.61,
"t90Line2End": 75.36,
"t90Rule": 75.55,
"t90RuleEnd": 76.88,
"t90Sub": 77.13,
"t90SubEnd": 78.29,
"t91Kicker": 80.21,
"t91KickerEnd": 81.4,
"t91Line1": 80.73,
"t91Line1End": 81.4,
"t91Line2": 81.2,
"t91Line2End": 82.01,
"t91Rule": 82.17,
"t91RuleEnd": 82.92,
"t91Sub": 83.19,
"t91SubEnd": 84.22
};
54 changes: 54 additions & 0 deletions learn/output/Meet-Microsoft-Scout/anchors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"_note": "Cue anchor spec: anchorName -> spoken phrase. Resolved against transcript.json by tools/word_anchors.py with --lead-in 3.0 (narration starts 3.0s into the composition, after the bumper). Regenerate anchors.js after any re-record.",

"t2Kicker": "Most AI",
"t2Meet": "answers",
"t2Name": "Microsoft Scout keeps",
"t2Rule": "Scout keeps",
"t2Sub": "keeps going",

"t3One": "Microsoft Scout is #1",
"t3Two": "does across your day",
"t3Three": "stays firmly",

"t4Autopilot": "autopilot",
"t4AlwaysOn": "always on",
"t4Identity": "identity and",
"t4Behalf": "your behalf",
"t4Grounded": "grounded in",
"t4M365": "Microsoft 365",
"t4Teams": "Teams",
"t4Outlook": "Outlook",
"t4Calendar": "calendar",
"t4Files": "files",

"t5Header": "coordination",
"t5Row1": "schedules meetings",
"t5Row2": "blocks time",
"t5Row3": "flags the meetings",
"t5Row4": "catches stalled",
"t5Cap1": "Powered by Work IQ",
"t5Cap2": "learns how you work",
"t5Cap3": "priorities forward",

"t6Trusted": "trusted",
"t6Identity": "governed entry",
"t6Shared": "shared account",
"t6Permissions": "permissions",
"t6Purview": "Purview",
"t6Moment": "moment #2",
"t6Sensitive": "sensitive",
"t6Signoff": "sign-off",

"t90Kicker": "So the follow-through",
"t90Line1": "follow-through happens",
"t90Line2": "happens for you",
"t90Rule": "always-on agent",
"t90Sub": "keeps work moving",

"t91Kicker": "Microsoft Scout is rolling",
"t91Line1": "Scout is rolling",
"t91Line2": "rolling out now",
"t91Rule": "preview through",
"t91Sub": "Frontier program"
}
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions learn/output/Meet-Microsoft-Scout/assets/vendor/gsap.min.js

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions learn/output/Meet-Microsoft-Scout/design-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Design plan — Meet Microsoft Scout

**Preset:** learn-ilt · **Profile:** companion-short
Chrome is already scaffolded (bumper, title, objectives, recap, cta). Body = 3 teaching beats.
Dark-field is spent **once**, on the trust beat (its gravitas earns it).

## Per-beat plan

| # | Scene id | Kit block | Ground | Focal / config | Seam in |
|---|----------|-----------|--------|----------------|---------|
| 01 | `01-bumper` | `bumper` (brand) | hero-swoosh | kicker: **Microsoft 365** | — |
| 02 | `02-title` | `title-hero` | hero-swoosh | title: "Meet / Microsoft Scout"; subtitle: "Your always-on personal agent" | cut-left |
| 03 | `03-objectives` | `list-steps` (chrome) | content-wash | 3 chips: **What it is** · **What it does** · **In your control** | cut-left |
| 04 | `04-what-it-is` | `callout-note` | section-field | label **NEW CATEGORY**, term **Autopilot**, body: always-on agent, own identity, acts on your behalf — grounded in Microsoft 365 | cut-left |
| 05 | `05-what-it-does` | `list-specs` | content-wash | 4 capability rows — Schedule / Deliverables / Meetings / Risks (see below); Work IQ as caption | cut-left |
| 06 | `06-trust` | `diagram-layers` | **dark-field** | concentric protection: outer **Your permissions & policies** → **Microsoft Purview** → **Governed Entra identity** → core **Scout acts** | cut-up |
| 90 | `90-recap` | `title-hero` (chrome) | hero-swoosh | recap payoff line | cut-up |
| 91 | `91-cta` | `title-hero` (chrome) | hero-swoosh | CTA: preview via Frontier | cut-left |
| — | endcard | AI disclosure clip | — | mandatory final clip | — |

## Beat 05 capability rows (`list-specs`)
- **Schedules** — meetings across time zones
- **Protects time** — blocks focus time for deliverables you owe
- **Surfaces signal** — flags the meetings that matter
- **Catches risk** — spots stalled decisions before they block

## Notes for the builder
- `04` spends `section-field` as the one segment-opener cool ground; `06` spends the single `dark-field`. No other scene uses either.
- `list-specs` label/value rows carry the four capabilities; keep Work IQ in the caption, not a 5th row.
- `diagram-layers` auto-inverts to white ink on dark-field — never hardcode white.
- Anchor every beat start + in-scene cue to `transcript.json` word times.
160 changes: 160 additions & 0 deletions learn/output/Meet-Microsoft-Scout/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1920, height=1080">
<title>Meet Microsoft Scout</title>
<script src="assets/vendor/gsap.min.js"></script>
<script src="anchors.js"></script>
<style>
@font-face {
font-family: "Segoe UI";
font-weight: 400;
font-style: normal;
src: url("fonts/segoeui-regular.woff2") format("woff2");
font-display: block;
}

@font-face {
font-family: "Segoe UI Semibold";
font-weight: 600;
font-style: normal;
src: url("fonts/segoeui-semibold.woff2") format("woff2");
font-display: block;
}

* { box-sizing: border-box; }

html, body {
width: 1920px; height: 1080px;
margin: 0; overflow: hidden;
background: #fff8f3;
font-family: "Segoe UI", sans-serif;
}

#root {
position: relative;
width: 1920px; height: 1080px;
overflow: hidden;
/* Opaque stage ground: white-flash guard for any seam dip (seam-craft). */
background: #fff8f3;
}

/* Scene slots fill the root and stack by mount order. */
#root > div[data-composition-src] { position: absolute; inset: 0; }

/* Fade bookends: opaque covers above everything; the timeline drives their opacity. */
.fade-cover { position: absolute; inset: 0; background: #000; z-index: 100; pointer-events: none; }
</style>
</head>
<body>
<div id="root" data-composition-id="root" data-start="0" data-duration="96.287"
data-width="1920" data-height="1080" data-resolution="landscape">

<audio id="narration" class="clip" src="narration.wav" data-start="3.0" data-duration="81.116" data-track-index="10"></audio>

<div id="slot-01-bumper" class="clip"
data-composition-id="01-bumper"
data-composition-src="scenes/01-bumper.html"
data-start="0.0" data-duration="3.0"
data-track-index="1"
data-width="1920" data-height="1080"></div>

<div id="slot-02-title" class="clip"
data-composition-id="02-title"
data-composition-src="scenes/02-title.html"
data-start="3.0" data-duration="5.895"
data-track-index="1"
data-width="1920" data-height="1080"></div>

<div id="slot-03-objectives" class="clip"
data-composition-id="03-objectives"
data-composition-src="scenes/03-objectives.html"
data-start="8.895" data-duration="7.88"
data-track-index="1"
data-width="1920" data-height="1080"></div>

<div id="slot-04-what-it-is" class="clip"
data-composition-id="04-what-it-is"
data-composition-src="scenes/04-what-it-is.html"
data-start="16.775" data-duration="20.43"
data-track-index="1"
data-width="1920" data-height="1080"></div>

<div id="slot-05-what-it-does" class="clip"
data-composition-id="05-what-it-does"
data-composition-src="scenes/05-what-it-does.html"
data-start="37.205" data-duration="19.01"
data-track-index="1"
data-width="1920" data-height="1080"></div>

<div id="slot-06-trust" class="clip"
data-composition-id="06-trust"
data-composition-src="scenes/06-trust.html"
data-start="56.215" data-duration="17.32"
data-track-index="1"
data-width="1920" data-height="1080"></div>

<div id="slot-90-recap" class="clip"
data-composition-id="90-recap"
data-composition-src="scenes/90-recap.html"
data-start="73.535" data-duration="6.66"
data-track-index="1"
data-width="1920" data-height="1080"></div>

<div id="slot-91-cta" class="clip"
data-composition-id="91-cta"
data-composition-src="scenes/91-cta.html"
data-start="80.195" data-duration="5.425"
data-track-index="1"
data-width="1920" data-height="1080"></div>

<video id="ai-end-card" class="clip" src="assets/AI_End_Card.mp4" data-start="85.62" data-duration="10.667" data-track-index="11" muted></video>

<div id="fade-in" class="fade-cover clip" data-start="0" data-duration="0.5" data-track-index="20"></div>

<div id="fade-out" class="fade-cover clip" data-start="95.587" data-duration="0.7" data-track-index="20"></div>
</div>

<script>
window.__timelines = window.__timelines || {};
// Thin root timeline: scene motion lives in each scene file. This timeline carries only
// the cross-scene seams, stamped against the slot-<id> hosts.
const tl = gsap.timeline({ paused: true });
window.__timelines["root"] = tl;

// <seams:auto> — cross-scene cut-the-curve, stamped by assemble_scenes.py from scenes.json.
// SEAM 02-title -> 03-objectives : cut-left (cut @8.895)
tl.to("#slot-02-title", { xPercent: -12, autoAlpha: 0, duration: 0.34, ease: "power3.in" }, 8.555);
tl.set("#slot-02-title", { autoAlpha: 0 }, 8.895);
tl.fromTo("#slot-03-objectives", { xPercent: 10, autoAlpha: 0.35 }, { xPercent: 0, autoAlpha: 1, duration: 0.42, ease: "power4.out", immediateRender: false }, 8.895);
// SEAM 03-objectives -> 04-what-it-is : cut-left (cut @16.775)
tl.to("#slot-03-objectives", { xPercent: -12, autoAlpha: 0, duration: 0.34, ease: "power3.in" }, 16.435);
tl.set("#slot-03-objectives", { autoAlpha: 0 }, 16.775);
tl.fromTo("#slot-04-what-it-is", { xPercent: 10, autoAlpha: 0.35 }, { xPercent: 0, autoAlpha: 1, duration: 0.42, ease: "power4.out", immediateRender: false }, 16.775);
// SEAM 04-what-it-is -> 05-what-it-does : cut-left (cut @37.205)
tl.to("#slot-04-what-it-is", { xPercent: -12, autoAlpha: 0, duration: 0.34, ease: "power3.in" }, 36.865);
tl.set("#slot-04-what-it-is", { autoAlpha: 0 }, 37.205);
tl.fromTo("#slot-05-what-it-does", { xPercent: 10, autoAlpha: 0.35 }, { xPercent: 0, autoAlpha: 1, duration: 0.42, ease: "power4.out", immediateRender: false }, 37.205);
// SEAM 05-what-it-does -> 06-trust : cut-up (cut @56.215)
tl.to("#slot-05-what-it-does", { yPercent: -12, autoAlpha: 0, duration: 0.34, ease: "power3.in" }, 55.875);
tl.set("#slot-05-what-it-does", { autoAlpha: 0 }, 56.215);
tl.fromTo("#slot-06-trust", { yPercent: 10, autoAlpha: 0.35 }, { yPercent: 0, autoAlpha: 1, duration: 0.42, ease: "power4.out", immediateRender: false }, 56.215);
// SEAM 06-trust -> 90-recap : cut-up (cut @73.535)
tl.to("#slot-06-trust", { yPercent: -12, autoAlpha: 0, duration: 0.34, ease: "power3.in" }, 73.195);
tl.set("#slot-06-trust", { autoAlpha: 0 }, 73.535);
tl.fromTo("#slot-90-recap", { yPercent: 10, autoAlpha: 0.35 }, { yPercent: 0, autoAlpha: 1, duration: 0.42, ease: "power4.out", immediateRender: false }, 73.535);
// SEAM 90-recap -> 91-cta : cut-left (cut @80.195)
tl.to("#slot-90-recap", { xPercent: -12, autoAlpha: 0, duration: 0.34, ease: "power3.in" }, 79.855);
tl.set("#slot-90-recap", { autoAlpha: 0 }, 80.195);
tl.fromTo("#slot-91-cta", { xPercent: 10, autoAlpha: 0.35 }, { xPercent: 0, autoAlpha: 1, duration: 0.42, ease: "power4.out", immediateRender: false }, 80.195);
// </seams:auto>

// <bookends> — fade-in breath + fade-to-black on the end card.
gsap.set("#fade-in", { autoAlpha: 1 });
tl.to("#fade-in", { autoAlpha: 0, duration: 0.5, ease: "power2.out" }, 0);
tl.fromTo("#fade-out", { autoAlpha: 0 }, { autoAlpha: 1, duration: 0.7, ease: "power2.in", immediateRender: false }, 95.587);
// </bookends>
</script>
</body>
</html>
Loading
Loading