@arbidocs/blocks 0.4.106 → 0.4.108
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/bin/arbidocs-render-take.mjs +27 -0
- package/dist/NativeDocxEditor-UAZUKZ77.js +10 -0
- package/dist/NativeDocxEditor-UAZUKZ77.js.map +1 -0
- package/dist/NativeDocxEditor-YX7B7OFH.cjs +31 -0
- package/dist/NativeDocxEditor-YX7B7OFH.cjs.map +1 -0
- package/dist/{chunk-W2RTZOK3.js → chunk-A2MN2ZLX.js} +1750 -1779
- package/dist/chunk-A2MN2ZLX.js.map +1 -0
- package/dist/{chunk-3R6XBYL7.cjs → chunk-DTBSGG36.cjs} +7 -2
- package/dist/chunk-DTBSGG36.cjs.map +1 -0
- package/dist/{chunk-4GFB5U3K.js → chunk-EGDWNEAG.js} +4 -3
- package/dist/chunk-EGDWNEAG.js.map +1 -0
- package/dist/chunk-GYAUJ4KT.js +71 -0
- package/dist/chunk-GYAUJ4KT.js.map +1 -0
- package/dist/{chunk-PIT2YZCK.js → chunk-JQVPGMLU.js} +3 -3
- package/dist/{chunk-PIT2YZCK.js.map → chunk-JQVPGMLU.js.map} +1 -1
- package/dist/{chunk-LGX6UFYG.js → chunk-P2KPDPFF.js} +8 -3
- package/dist/chunk-P2KPDPFF.js.map +1 -0
- package/dist/{chunk-ZWWN4CUL.cjs → chunk-QT6EGMAJ.cjs} +1748 -1778
- package/dist/chunk-QT6EGMAJ.cjs.map +1 -0
- package/dist/chunk-S24XEVPS.cjs +73 -0
- package/dist/chunk-S24XEVPS.cjs.map +1 -0
- package/dist/{chunk-TP3FAP5J.cjs → chunk-TTXK62YI.cjs} +5 -5
- package/dist/{chunk-TP3FAP5J.cjs.map → chunk-TTXK62YI.cjs.map} +1 -1
- package/dist/{chunk-7LLLQUM7.cjs → chunk-ZYSY4L5L.cjs} +6 -5
- package/dist/chunk-ZYSY4L5L.cjs.map +1 -0
- package/dist/collaboration/index.cjs +15 -15
- package/dist/collaboration/index.js +1 -1
- package/dist/collaboration/mail/MailMessageView.d.ts +3 -1
- package/dist/connect/docx.cjs +7 -6
- package/dist/connect/docx.cjs.map +1 -1
- package/dist/connect/docx.js +5 -4
- package/dist/connect/docx.js.map +1 -1
- package/dist/connect/index.cjs +368 -52
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +356 -41
- package/dist/connect/index.js.map +1 -1
- package/dist/connection/mail/ConnectedMailComposer.d.ts +12 -2
- package/dist/connection/mail/ConnectedMailMessage.d.ts +19 -0
- package/dist/connection/mail/ConnectedMailbox.d.ts +7 -3
- package/dist/connection/mail/MailComposerForm.d.ts +12 -2
- package/dist/connection/mail/index.d.ts +2 -1
- package/dist/connection/mail/types.d.ts +15 -0
- package/dist/connection/mail/useWordBody.d.ts +48 -0
- package/dist/docx/NativeDocxEditor.d.ts +9 -1
- package/dist/docx/index.cjs +51 -50
- package/dist/docx/index.cjs.map +1 -1
- package/dist/docx/index.js +4 -3
- package/dist/docx/index.js.map +1 -1
- package/dist/docx/template/HouseTemplate.d.ts +5 -0
- package/dist/index.cjs +15 -15
- package/dist/index.js +1 -1
- package/dist/record/index.cjs +307 -66
- package/dist/record/index.cjs.map +1 -1
- package/dist/record/index.d.ts +145 -26
- package/dist/record/index.js +301 -67
- package/dist/record/index.js.map +1 -1
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +8 -5
- package/record/render-overlays.mjs +152 -0
- package/record/render-take.py +985 -0
- package/src/docx/styles.css +22 -0
- package/dist/chunk-3R6XBYL7.cjs.map +0 -1
- package/dist/chunk-4GFB5U3K.js.map +0 -1
- package/dist/chunk-7LLLQUM7.cjs.map +0 -1
- package/dist/chunk-LGX6UFYG.js.map +0 -1
- package/dist/chunk-W2RTZOK3.js.map +0 -1
- package/dist/chunk-ZWWN4CUL.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -46,7 +46,7 @@ export { BlocksProvider, useBlocksEnvironment } from './chunk-76JDDMSP.js';
|
|
|
46
46
|
export { daysUntil, displayName, fmtDate, fmtDateTime, formatCount, formatCurrency, formatPageRefs, fromNow, hrs, initials, pct, pluralize } from './chunk-OXF2IFXG.js';
|
|
47
47
|
export { ActionMenu, AddContactsForm, AddContactsResults, ContactCard, DEFAULT_ADD_CONTACTS_LABELS, DEFAULT_CONTACT_CARD_LABELS, DEFAULT_CONTACT_OUTCOME_LABELS, DEFAULT_DM_ACCESS_REQUEST_BANNER_LABELS, DEFAULT_DM_GRANT_ACCESS_DIALOG_LABELS, DEFAULT_DM_INVITE_CHIP_LABELS, DEFAULT_DM_THREAD_FRAME_LABELS, DEFAULT_MAIL_FOLDER_TREE_LABELS, DEFAULT_RECIPIENT_PICKER_LABELS, DmAccessRequestBanner, DmGrantAccessDialogView, DmInviteAvatar, DmInviteChip, DmNewTabIcon, DmThreadFrame, DmThreadHeader, MAX_INVITE_EMAILS, MailFolderTree, MemberBulkActions, MemberListLoading, MemberMutedText, MemberNameCell, MemberRoleCell, RecipientPicker, RoleSelect, WorkspaceDeleteButton, buildMailFolderTree, contactToVCard, descendantFolderIds, downloadVCard, isInboxFolder, parseEmails, toAddContactsRow, toAddContactsRows, toggleMailFolder, vCardFilename } from './chunk-7C35WXYB.js';
|
|
48
48
|
import './chunk-NBV56SGU.js';
|
|
49
|
-
export { MailDeliveryBadge, MailDeliveryList, MailDocumentPicker, MailGrid, MailMessagePreview, MailMessageView, NEEDS_CONNECTION, PlainMailBodyEditor, draftMailCompose, emptyMailCompose, hasCalendarPart, mailAddressLabel, parseMailRecipients, replyMailCompose } from './chunk-
|
|
49
|
+
export { MailDeliveryBadge, MailDeliveryList, MailDocumentPicker, MailGrid, MailMessagePreview, MailMessageView, NEEDS_CONNECTION, PlainMailBodyEditor, draftMailCompose, emptyMailCompose, hasCalendarPart, mailAddressLabel, parseMailRecipients, replyMailCompose } from './chunk-P2KPDPFF.js';
|
|
50
50
|
export { DEFAULT_SHARE_CONTROL_LABELS, ShareControl } from './chunk-K4BGOPGG.js';
|
|
51
51
|
import './chunk-TX2ZICS7.js';
|
|
52
52
|
import './chunk-ZPLG7QYF.js';
|
package/dist/record/index.cjs
CHANGED
|
@@ -1,6 +1,141 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
|
|
6
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
|
|
8
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
9
|
+
|
|
3
10
|
// src/record/index.ts
|
|
11
|
+
var TIMECODE_CELL = 8;
|
|
12
|
+
var round = (n) => Math.round(n * 100) / 100;
|
|
13
|
+
var Take = class _Take {
|
|
14
|
+
constructor(page, options, brand) {
|
|
15
|
+
this.page = page;
|
|
16
|
+
this.options = options;
|
|
17
|
+
this.brand = brand ? cinematicSkin(brand) : {};
|
|
18
|
+
const dir = path__default.default.resolve(options.dir ?? "recordings");
|
|
19
|
+
this.file = path__default.default.join(dir, `${options.name}.waits.json`);
|
|
20
|
+
this.focusFile = path__default.default.join(dir, `${options.name}.focus.json`);
|
|
21
|
+
this.timeline.viewport = page.viewportSize();
|
|
22
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
23
|
+
_Take.active = this;
|
|
24
|
+
this.save();
|
|
25
|
+
}
|
|
26
|
+
page;
|
|
27
|
+
options;
|
|
28
|
+
/** The take running now (one at a time: recordings run one after another). */
|
|
29
|
+
static active = null;
|
|
30
|
+
t0 = Date.now();
|
|
31
|
+
waits = [];
|
|
32
|
+
/** The brand the edit paints the cards, captions and callouts in. */
|
|
33
|
+
brand;
|
|
34
|
+
file;
|
|
35
|
+
focusFile;
|
|
36
|
+
timeline = {
|
|
37
|
+
sync: null,
|
|
38
|
+
viewport: null,
|
|
39
|
+
focus: [],
|
|
40
|
+
cards: [],
|
|
41
|
+
lowerThirds: [],
|
|
42
|
+
captions: []
|
|
43
|
+
};
|
|
44
|
+
/** The take running on `page`, if any. */
|
|
45
|
+
static on(page) {
|
|
46
|
+
return _Take.active?.page === page ? _Take.active : null;
|
|
47
|
+
}
|
|
48
|
+
/** Seconds since the take started. */
|
|
49
|
+
now() {
|
|
50
|
+
return (Date.now() - this.t0) / 1e3;
|
|
51
|
+
}
|
|
52
|
+
/** Log a wait (written at once, so a take that fails part-way still has its cut list). */
|
|
53
|
+
log(label, start, end = this.now()) {
|
|
54
|
+
if (end - start < 1) return;
|
|
55
|
+
this.waits.push({ label, start: round(start), end: round(end) });
|
|
56
|
+
this.save();
|
|
57
|
+
}
|
|
58
|
+
/** Wait for `until` (a UI state), logged as a wait the edit may cut. */
|
|
59
|
+
async wait(label, until) {
|
|
60
|
+
const start = this.now();
|
|
61
|
+
try {
|
|
62
|
+
return await until();
|
|
63
|
+
} finally {
|
|
64
|
+
this.log(label, start);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Paint the sync marker: a magenta frame for a moment, at a logged time. The edit finds it in the
|
|
69
|
+
* video and lines the take's clock up with the video's. Call it before the first navigation.
|
|
70
|
+
*/
|
|
71
|
+
async markSync() {
|
|
72
|
+
await this.page.evaluate(
|
|
73
|
+
() => new Promise((done) => {
|
|
74
|
+
document.documentElement.style.background = "#ff00ff";
|
|
75
|
+
if (document.body) document.body.style.background = "#ff00ff";
|
|
76
|
+
requestAnimationFrame(() => requestAnimationFrame(() => done()));
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
this.timeline.sync = round(this.now());
|
|
80
|
+
await this.page.waitForTimeout(400);
|
|
81
|
+
this.save();
|
|
82
|
+
}
|
|
83
|
+
/** Log a focus event (a `point` with no end lasts until the next event). */
|
|
84
|
+
record(event) {
|
|
85
|
+
const { focus } = this.timeline;
|
|
86
|
+
const open = focus[focus.length - 1];
|
|
87
|
+
if (open && open.kind === "point" && open.end === void 0) open.end = round(event.start);
|
|
88
|
+
focus.push({
|
|
89
|
+
...event,
|
|
90
|
+
start: round(event.start),
|
|
91
|
+
end: event.end === void 0 ? void 0 : round(event.end)
|
|
92
|
+
});
|
|
93
|
+
this.save();
|
|
94
|
+
}
|
|
95
|
+
/** @internal The stage's cards, lower-thirds and captions (drawn by the edit). */
|
|
96
|
+
cardStart(card) {
|
|
97
|
+
this.cardEnd();
|
|
98
|
+
this.captionEnd();
|
|
99
|
+
this.timeline.cards.push({ ...card, start: round(this.now()), end: null });
|
|
100
|
+
this.save();
|
|
101
|
+
}
|
|
102
|
+
cardEnd() {
|
|
103
|
+
const last = this.timeline.cards[this.timeline.cards.length - 1];
|
|
104
|
+
if (last && last.end === null) {
|
|
105
|
+
last.end = round(this.now());
|
|
106
|
+
this.save();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
lowerThird(kicker, title, holdMs) {
|
|
110
|
+
const start = round(this.now());
|
|
111
|
+
this.timeline.lowerThirds.push({ kicker, title, start, end: round(start + holdMs / 1e3) });
|
|
112
|
+
this.save();
|
|
113
|
+
}
|
|
114
|
+
captionStart(text) {
|
|
115
|
+
this.captionEnd();
|
|
116
|
+
this.timeline.captions.push({ text, start: round(this.now()), end: null });
|
|
117
|
+
this.save();
|
|
118
|
+
}
|
|
119
|
+
captionEnd() {
|
|
120
|
+
const last = this.timeline.captions[this.timeline.captions.length - 1];
|
|
121
|
+
if (last && last.end === null) {
|
|
122
|
+
last.end = round(this.now());
|
|
123
|
+
this.save();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
save() {
|
|
127
|
+
const { zoom, maxZoom, pip } = this.options;
|
|
128
|
+
fs.writeFileSync(this.file, JSON.stringify({ t0: this.t0, waits: this.waits }, null, 1));
|
|
129
|
+
fs.writeFileSync(
|
|
130
|
+
this.focusFile,
|
|
131
|
+
JSON.stringify(
|
|
132
|
+
{ t0: this.t0, config: { zoom, maxZoom, pip }, brand: this.brand, ...this.timeline },
|
|
133
|
+
null,
|
|
134
|
+
1
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
4
139
|
var DEFAULTS = {
|
|
5
140
|
displayFont: "ui-serif, Georgia, serif",
|
|
6
141
|
sansFont: "Inter, ui-sans-serif, system-ui, sans-serif",
|
|
@@ -11,9 +146,8 @@ var DEFAULTS = {
|
|
|
11
146
|
ink: "#0e1b2d",
|
|
12
147
|
coverTitle: "#f4f6f8"
|
|
13
148
|
};
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
const skin = {
|
|
149
|
+
function cinematicSkin(b) {
|
|
150
|
+
return {
|
|
17
151
|
firmLabel: b.firmLabel,
|
|
18
152
|
displayFont: b.displayFont ?? DEFAULTS.displayFont,
|
|
19
153
|
sansFont: b.sansFont ?? DEFAULTS.sansFont,
|
|
@@ -25,8 +159,13 @@ function createCinematic(config) {
|
|
|
25
159
|
coverTo: b.cover?.to ?? DEFAULTS.cover.to,
|
|
26
160
|
accent: b.accent ?? DEFAULTS.accent,
|
|
27
161
|
ink: b.ink ?? DEFAULTS.ink,
|
|
28
|
-
coverTitle: b.coverTitle ?? DEFAULTS.coverTitle
|
|
162
|
+
coverTitle: b.coverTitle ?? DEFAULTS.coverTitle,
|
|
163
|
+
fontFiles: b.fontFiles ?? []
|
|
29
164
|
};
|
|
165
|
+
}
|
|
166
|
+
function createCinematic(config) {
|
|
167
|
+
const b = config.brand;
|
|
168
|
+
const skin = cinematicSkin(b);
|
|
30
169
|
const loginPath = config.loginPath ?? "/app/login";
|
|
31
170
|
const appUrlPattern = config.appUrlPattern ?? /\/app$/;
|
|
32
171
|
const ids = {
|
|
@@ -35,113 +174,207 @@ function createCinematic(config) {
|
|
|
35
174
|
submit: config.testIds?.submit ?? "auth-login-submit"
|
|
36
175
|
};
|
|
37
176
|
const resolve = (page, t) => typeof t === "string" ? page.getByTestId(t) : t;
|
|
177
|
+
async function boxOf(page, loc) {
|
|
178
|
+
const box = await loc.boundingBox().catch(() => null);
|
|
179
|
+
const vp = page.viewportSize();
|
|
180
|
+
if (!box || !vp) return box;
|
|
181
|
+
const x = Math.max(box.x, 0);
|
|
182
|
+
const y = Math.max(box.y, 0);
|
|
183
|
+
const width = Math.min(box.x + box.width, vp.width) - x;
|
|
184
|
+
const height = Math.min(box.y + box.height, vp.height) - y;
|
|
185
|
+
return width > 0 && height > 0 ? { x: round(x), y: round(y), width: round(width), height: round(height) } : null;
|
|
186
|
+
}
|
|
187
|
+
async function glide(page, target) {
|
|
188
|
+
const loc = resolve(page, target).first();
|
|
189
|
+
await loc.scrollIntoViewIfNeeded().catch(() => {
|
|
190
|
+
});
|
|
191
|
+
const box = await boxOf(page, loc);
|
|
192
|
+
if (box) {
|
|
193
|
+
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2, { steps: 26 });
|
|
194
|
+
await page.waitForTimeout(180);
|
|
195
|
+
}
|
|
196
|
+
return { loc, box };
|
|
197
|
+
}
|
|
198
|
+
async function take(page, options) {
|
|
199
|
+
return new Take(page, options, b);
|
|
200
|
+
}
|
|
38
201
|
async function installStage(page) {
|
|
39
|
-
await page.addInitScript(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
202
|
+
await page.addInitScript(
|
|
203
|
+
({ s, t0, TC }) => {
|
|
204
|
+
const boot = () => {
|
|
205
|
+
if (document.getElementById("__cine_cursor")) return;
|
|
206
|
+
const cursor = document.createElement("div");
|
|
207
|
+
cursor.id = "__cine_cursor";
|
|
208
|
+
cursor.style.cssText = `position:fixed;left:0;top:0;z-index:2147483647;width:22px;height:22px;margin:-11px 0 0 -11px;border-radius:50%;pointer-events:none;transition:transform .09s ease-out;background:radial-gradient(circle at 35% 35%, ${s.cursorFrom}, ${s.cursorTo});box-shadow:0 0 0 3px rgba(255,255,255,.6),0 2px 10px rgba(0,0,0,.4);`;
|
|
209
|
+
document.body.appendChild(cursor);
|
|
210
|
+
window.addEventListener(
|
|
211
|
+
"mousemove",
|
|
212
|
+
(e) => {
|
|
213
|
+
cursor.style.transform = `translate(${e.clientX}px,${e.clientY}px)`;
|
|
214
|
+
},
|
|
215
|
+
true
|
|
216
|
+
);
|
|
217
|
+
window.addEventListener(
|
|
218
|
+
"mousedown",
|
|
219
|
+
(e) => {
|
|
220
|
+
const m = e;
|
|
221
|
+
const r = document.createElement("div");
|
|
222
|
+
r.style.cssText = `position:fixed;left:${m.clientX}px;top:${m.clientY}px;z-index:2147483646;width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;pointer-events:none;border:2px solid ${s.ripple};animation:__cine_ripple .55s ease-out forwards;`;
|
|
223
|
+
document.body.appendChild(r);
|
|
224
|
+
setTimeout(() => r.remove(), 600);
|
|
225
|
+
},
|
|
226
|
+
true
|
|
227
|
+
);
|
|
228
|
+
const cap = document.createElement("div");
|
|
229
|
+
cap.id = "__cine_cap";
|
|
230
|
+
cap.style.cssText = `position:fixed;left:50%;bottom:34px;transform:translateX(-50%) translateY(8px);z-index:2147483646;max-width:72%;padding:13px 24px;border-radius:13px;font:500 17px/1.45 ${s.sansFont};color:#fff;letter-spacing:.01em;background:${s.ink}e0;backdrop-filter:blur(7px);box-shadow:0 10px 34px rgba(0,0,0,.4);text-align:center;opacity:0;transition:opacity .35s,transform .35s;`;
|
|
231
|
+
document.body.appendChild(cap);
|
|
232
|
+
const style = document.createElement("style");
|
|
233
|
+
style.textContent = "@keyframes __cine_ripple{to{width:46px;height:46px;margin:-23px 0 0 -23px;opacity:0}}";
|
|
234
|
+
document.head.appendChild(style);
|
|
235
|
+
window.__cine_cap = (t) => {
|
|
236
|
+
cap.textContent = t;
|
|
237
|
+
cap.style.opacity = t ? "1" : "0";
|
|
238
|
+
cap.style.transform = `translateX(-50%) translateY(${t ? 0 : 8}px)`;
|
|
239
|
+
};
|
|
240
|
+
if (t0 !== null) {
|
|
241
|
+
const strip = document.createElement("div");
|
|
242
|
+
strip.id = "__cine_timecode";
|
|
243
|
+
strip.style.cssText = `position:fixed;right:0;bottom:0;z-index:2147483647;display:flex;pointer-events:none;height:${TC}px`;
|
|
244
|
+
const cells = Array.from({ length: 18 }, (_, i) => {
|
|
245
|
+
const cell = document.createElement("div");
|
|
246
|
+
cell.style.cssText = `width:${TC}px;height:${TC}px;background:${i === 0 ? "#fff" : "#000"}`;
|
|
247
|
+
strip.appendChild(cell);
|
|
248
|
+
return cell;
|
|
249
|
+
});
|
|
250
|
+
document.body.appendChild(strip);
|
|
251
|
+
const tick = () => {
|
|
252
|
+
const ds = Math.max(0, Math.round((Date.now() - t0) / 100)) & 65535;
|
|
253
|
+
for (let bit = 0; bit < 16; bit += 1)
|
|
254
|
+
cells[bit + 2].style.background = ds >> 15 - bit & 1 ? "#fff" : "#000";
|
|
255
|
+
requestAnimationFrame(tick);
|
|
256
|
+
};
|
|
257
|
+
tick();
|
|
258
|
+
}
|
|
75
259
|
};
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
260
|
+
if (document.body) boot();
|
|
261
|
+
else document.addEventListener("DOMContentLoaded", boot);
|
|
262
|
+
},
|
|
263
|
+
{ s: skin, t0: Take.on(page)?.t0 ?? null, TC: TIMECODE_CELL }
|
|
264
|
+
);
|
|
80
265
|
}
|
|
81
266
|
async function cover(page, { kicker, title, subtitle }, holdMs = 2600) {
|
|
267
|
+
const running = Take.on(page);
|
|
268
|
+
running?.cardStart({ kicker, title, subtitle });
|
|
82
269
|
await page.evaluate(
|
|
83
|
-
({ kicker: kicker2, title: title2, subtitle: subtitle2, s }) => {
|
|
270
|
+
({ kicker: kicker2, title: title2, subtitle: subtitle2, s, instant }) => {
|
|
84
271
|
document.getElementById("__cine_cover")?.remove();
|
|
85
272
|
const el = document.createElement("div");
|
|
86
273
|
el.id = "__cine_cover";
|
|
87
|
-
el.style.cssText = `position:fixed;inset:0;z-index:2147483647;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:0 8%;background:linear-gradient(135deg,${s.coverFrom} 0%,${s.coverMid} 48%,${s.coverTo} 165%);opacity:0;transition:opacity .
|
|
274
|
+
el.style.cssText = `position:fixed;inset:0;z-index:2147483647;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:0 8%;background:linear-gradient(135deg,${s.coverFrom} 0%,${s.coverMid} 48%,${s.coverTo} 165%);opacity:${instant ? 1 : 0};transition:opacity ${instant ? 0 : 0.5}s ease;font-family:${s.sansFont};`;
|
|
88
275
|
el.innerHTML = `<div style="text-transform:uppercase;letter-spacing:.26em;font-size:13px;font-weight:600;color:${s.accent};margin-bottom:22px">${kicker2}</div><div style="font-family:${s.displayFont};font-weight:600;font-size:52px;line-height:1.08;letter-spacing:-.02em;color:${s.coverTitle};max-width:16ch">${title2}</div>` + (subtitle2 ? `<div style="margin-top:22px;font-size:19px;line-height:1.5;color:${s.coverTitle}b8;max-width:46ch">${subtitle2}</div>` : "") + `<div style="margin-top:44px;display:flex;align-items:center;gap:10px;color:${s.coverTitle}80;font-size:13px;letter-spacing:.02em"><span style="width:26px;height:1px;background:${s.accent}"></span>${s.firmLabel}</div>`;
|
|
89
276
|
document.body.appendChild(el);
|
|
90
277
|
requestAnimationFrame(() => el.style.opacity = "1");
|
|
91
278
|
},
|
|
92
|
-
{ kicker, title, subtitle: subtitle ?? "", s: skin }
|
|
279
|
+
{ kicker, title, subtitle: subtitle ?? "", s: skin, instant: !!running }
|
|
93
280
|
);
|
|
94
281
|
await page.waitForTimeout(holdMs);
|
|
95
282
|
}
|
|
96
|
-
async function
|
|
283
|
+
async function chapter(page, card, holdMs) {
|
|
284
|
+
await cover(page, card, holdMs);
|
|
97
285
|
await page.evaluate(() => {
|
|
286
|
+
const el = document.getElementById("__cine_cover");
|
|
287
|
+
if (el) el.style.pointerEvents = "none";
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
async function uncover(page) {
|
|
291
|
+
const running = Take.on(page);
|
|
292
|
+
await page.evaluate((instant) => {
|
|
98
293
|
const el = document.getElementById("__cine_cover");
|
|
99
294
|
if (!el) return;
|
|
295
|
+
if (instant) return el.remove();
|
|
100
296
|
el.style.opacity = "0";
|
|
101
297
|
setTimeout(() => el.remove(), 520);
|
|
102
|
-
});
|
|
298
|
+
}, !!running);
|
|
299
|
+
running?.cardEnd();
|
|
103
300
|
await page.waitForTimeout(560);
|
|
104
301
|
}
|
|
302
|
+
function lowerThird(page, kicker, title, holdMs = 3200) {
|
|
303
|
+
Take.on(page)?.lowerThird(kicker, title, holdMs);
|
|
304
|
+
}
|
|
105
305
|
async function caption(page, text, holdMs) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
306
|
+
const running = Take.on(page);
|
|
307
|
+
if (running) running.captionStart(text);
|
|
308
|
+
else
|
|
309
|
+
await page.evaluate(
|
|
310
|
+
(t) => window.__cine_cap?.(t),
|
|
311
|
+
text
|
|
312
|
+
);
|
|
110
313
|
const hold = holdMs ?? Math.min(4200, 900 + text.length * 45);
|
|
111
314
|
await page.waitForTimeout(hold);
|
|
112
315
|
}
|
|
113
316
|
async function clearCaption(page) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
317
|
+
const running = Take.on(page);
|
|
318
|
+
if (running) running.captionEnd();
|
|
319
|
+
else
|
|
320
|
+
await page.evaluate(
|
|
321
|
+
() => window.__cine_cap?.("")
|
|
322
|
+
);
|
|
117
323
|
}
|
|
118
324
|
async function beat(page, ms = 650) {
|
|
119
325
|
await page.waitForTimeout(ms);
|
|
120
326
|
}
|
|
121
327
|
async function glideTo(page, target) {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
if (box) {
|
|
127
|
-
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2, { steps: 26 });
|
|
128
|
-
await page.waitForTimeout(180);
|
|
129
|
-
}
|
|
328
|
+
const running = Take.on(page);
|
|
329
|
+
const start = running?.now() ?? 0;
|
|
330
|
+
const { loc, box } = await glide(page, target);
|
|
331
|
+
if (running && box) running.record({ kind: "point", start, box });
|
|
130
332
|
return loc;
|
|
131
333
|
}
|
|
132
334
|
async function click(page, target) {
|
|
133
|
-
const
|
|
335
|
+
const running = Take.on(page);
|
|
336
|
+
const start = running?.now() ?? 0;
|
|
337
|
+
const { loc, box } = await glide(page, target);
|
|
134
338
|
await loc.click();
|
|
135
339
|
await page.waitForTimeout(260);
|
|
340
|
+
if (running && box) running.record({ kind: "click", start, end: running.now(), box });
|
|
136
341
|
}
|
|
137
342
|
async function type(page, target, text) {
|
|
138
|
-
const
|
|
343
|
+
const running = Take.on(page);
|
|
344
|
+
const start = running?.now() ?? 0;
|
|
345
|
+
const { loc, box } = await glide(page, target);
|
|
139
346
|
await loc.click();
|
|
140
347
|
await loc.fill("");
|
|
141
348
|
await loc.pressSequentially(text, { delay: 42 });
|
|
142
349
|
await page.waitForTimeout(240);
|
|
350
|
+
if (running && box) running.record({ kind: "type", start, end: running.now(), box });
|
|
351
|
+
}
|
|
352
|
+
async function focusOn(page, target, label, {
|
|
353
|
+
holdMs = 2200,
|
|
354
|
+
callout = true,
|
|
355
|
+
mode
|
|
356
|
+
} = {}) {
|
|
357
|
+
const running = Take.on(page);
|
|
358
|
+
const start = running?.now() ?? 0;
|
|
359
|
+
const { box } = await glide(page, target);
|
|
360
|
+
await page.waitForTimeout(holdMs);
|
|
361
|
+
if (running && box)
|
|
362
|
+
running.record({ kind: "focus", label, start, end: running.now(), box, callout, mode });
|
|
363
|
+
}
|
|
364
|
+
async function readDown(page, target, scrolls = 3, pauseMs = 1600) {
|
|
365
|
+
const running = Take.on(page);
|
|
366
|
+
const start = running?.now() ?? 0;
|
|
367
|
+
const { box } = await glide(page, target);
|
|
368
|
+
for (let i = 0; i < scrolls; i += 1) {
|
|
369
|
+
await page.mouse.wheel(0, 320);
|
|
370
|
+
await beat(page, pauseMs);
|
|
371
|
+
}
|
|
372
|
+
await page.mouse.wheel(0, -320 * scrolls);
|
|
373
|
+
await beat(page, 500);
|
|
374
|
+
if (running && box) running.record({ kind: "read", start, end: running.now(), box });
|
|
143
375
|
}
|
|
144
376
|
async function login(page, opts = {}) {
|
|
377
|
+
if (!config.creds) throw new Error("createCinematic: pass creds to sign in");
|
|
145
378
|
await page.goto(loginPath);
|
|
146
379
|
if (opts.show === false) {
|
|
147
380
|
await page.getByTestId(ids.email).fill(config.creds.email);
|
|
@@ -158,19 +391,27 @@ function createCinematic(config) {
|
|
|
158
391
|
await beat(page, 800);
|
|
159
392
|
}
|
|
160
393
|
return {
|
|
394
|
+
take,
|
|
161
395
|
installStage,
|
|
162
396
|
cover,
|
|
397
|
+
chapter,
|
|
163
398
|
uncover,
|
|
399
|
+
lowerThird,
|
|
164
400
|
caption,
|
|
165
401
|
clearCaption,
|
|
166
402
|
beat,
|
|
167
403
|
glideTo,
|
|
168
404
|
click,
|
|
169
405
|
type,
|
|
406
|
+
focusOn,
|
|
407
|
+
readDown,
|
|
170
408
|
login
|
|
171
409
|
};
|
|
172
410
|
}
|
|
173
411
|
|
|
412
|
+
exports.TIMECODE_CELL = TIMECODE_CELL;
|
|
413
|
+
exports.Take = Take;
|
|
414
|
+
exports.cinematicSkin = cinematicSkin;
|
|
174
415
|
exports.createCinematic = createCinematic;
|
|
175
416
|
//# sourceMappingURL=index.cjs.map
|
|
176
417
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/record/index.ts"],"names":["kicker","title","subtitle"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Cinematic recording harness — host-agnostic.\n *\n * Turns a Playwright run into a narrated product demo: a visible cursor that\n * glides between targets, a click ripple, a caption bar that narrates each step,\n * full-screen chapter \"cover\" cards, and human-speed pacing. Every host app gets\n * the same polished demo capability from one factory — brand colours, fonts,\n * credentials and the login flow arrive as config, so nothing here names a host.\n *\n * Pair with a Playwright project that records video (see the host's\n * `playwright.record.config.ts`: video on, a large viewport, some slowMo).\n *\n * Usage in a `*.record.ts` spec:\n * const cine = createCinematic({ brand, creds })\n * await cine.installStage(page) // before the first navigation\n * await cine.cover(page, { kicker, title, subtitle })\n * await cine.login(page)\n * await cine.uncover(page)\n * await cine.caption(page, \"Opening the flagship matter…\")\n * await cine.click(page, \"matters-row-…\")\n *\n * `@playwright/test` is an optional peer used for TYPES only (no runtime import), so\n * importing this entry never loads Playwright.\n */\nimport type { Page, Locator } from '@playwright/test'\n\n/** Brand skin for the on-screen chrome. All optional — sensible neutral defaults. */\nexport interface CinematicBrand {\n /** Footer line on chapter cards, e.g. \"Meridian · AI-native counsel\". */\n firmLabel: string\n /** Serif display font for cover titles (CSS font-family value). */\n displayFont?: string\n /** Sans font for captions + cover body. */\n sansFont?: string\n /** Cursor dot radial-gradient stops. */\n cursor?: { from: string; to: string }\n /** Click-ripple ring colour. */\n ripple?: string\n /** Chapter-card background gradient stops. */\n cover?: { from: string; mid: string; to: string }\n /** Accent (kicker text + rule) on chapter cards. */\n accent?: string\n /** Caption bar background base colour. */\n ink?: string\n /** Cover title text colour. */\n coverTitle?: string\n}\n\nexport interface CinematicCreds {\n email: string\n password: string\n}\n\nexport interface CinematicConfig {\n brand: CinematicBrand\n creds: CinematicCreds\n /** Login route (default \"/app/login\"). */\n loginPath?: string\n /** URL the app lands on after auth (default /\\/app$/). */\n appUrlPattern?: RegExp\n /** Login form testids (defaults match the shared AppShell/login convention). */\n testIds?: { email?: string; password?: string; submit?: string }\n}\n\nexport interface Cinematic {\n installStage(page: Page): Promise<void>\n cover(\n page: Page,\n opts: { kicker: string; title: string; subtitle?: string },\n holdMs?: number\n ): Promise<void>\n uncover(page: Page): Promise<void>\n caption(page: Page, text: string, holdMs?: number): Promise<void>\n clearCaption(page: Page): Promise<void>\n beat(page: Page, ms?: number): Promise<void>\n glideTo(page: Page, target: string | Locator): Promise<Locator>\n click(page: Page, target: string | Locator): Promise<void>\n type(page: Page, target: string | Locator, text: string): Promise<void>\n /** Sign in. `{ show: false }` authenticates fast + silent (no animation/caption). */\n login(page: Page, opts?: { show?: boolean; caption?: string }): Promise<void>\n}\n\nconst DEFAULTS = {\n displayFont: 'ui-serif, Georgia, serif',\n sansFont: 'Inter, ui-sans-serif, system-ui, sans-serif',\n cursor: { from: 'rgba(31,111,235,.98)', to: 'rgba(11,42,74,.92)' },\n ripple: 'rgba(11,42,74,.85)',\n cover: { from: '#0b1622', mid: '#0e1b2c', to: '#1f6feb' },\n accent: '#c9a24b',\n ink: '#0e1b2d',\n coverTitle: '#f4f6f8',\n}\n\nexport function createCinematic(config: CinematicConfig): Cinematic {\n const b = config.brand\n const skin = {\n firmLabel: b.firmLabel,\n displayFont: b.displayFont ?? DEFAULTS.displayFont,\n sansFont: b.sansFont ?? DEFAULTS.sansFont,\n cursorFrom: b.cursor?.from ?? DEFAULTS.cursor.from,\n cursorTo: b.cursor?.to ?? DEFAULTS.cursor.to,\n ripple: b.ripple ?? DEFAULTS.ripple,\n coverFrom: b.cover?.from ?? DEFAULTS.cover.from,\n coverMid: b.cover?.mid ?? DEFAULTS.cover.mid,\n coverTo: b.cover?.to ?? DEFAULTS.cover.to,\n accent: b.accent ?? DEFAULTS.accent,\n ink: b.ink ?? DEFAULTS.ink,\n coverTitle: b.coverTitle ?? DEFAULTS.coverTitle,\n }\n const loginPath = config.loginPath ?? '/app/login'\n const appUrlPattern = config.appUrlPattern ?? /\\/app$/\n const ids = {\n email: config.testIds?.email ?? 'auth-email',\n password: config.testIds?.password ?? 'auth-password',\n submit: config.testIds?.submit ?? 'auth-login-submit',\n }\n\n const resolve = (page: Page, t: string | Locator): Locator =>\n typeof t === 'string' ? page.getByTestId(t) : t\n\n async function installStage(page: Page): Promise<void> {\n await page.addInitScript((s: typeof skin) => {\n const boot = () => {\n if (document.getElementById('__cine_cursor')) return\n\n const cursor = document.createElement('div')\n cursor.id = '__cine_cursor'\n cursor.style.cssText =\n 'position:fixed;left:0;top:0;z-index:2147483647;width:22px;height:22px;' +\n 'margin:-11px 0 0 -11px;border-radius:50%;pointer-events:none;' +\n 'transition:transform .09s ease-out;' +\n `background:radial-gradient(circle at 35% 35%, ${s.cursorFrom}, ${s.cursorTo});` +\n 'box-shadow:0 0 0 3px rgba(255,255,255,.6),0 2px 10px rgba(0,0,0,.4);'\n document.body.appendChild(cursor)\n\n window.addEventListener(\n 'mousemove',\n (e) => {\n cursor.style.transform = `translate(${(e as MouseEvent).clientX}px,${(e as MouseEvent).clientY}px)`\n },\n true\n )\n window.addEventListener(\n 'mousedown',\n (e) => {\n const m = e as MouseEvent\n const r = document.createElement('div')\n r.style.cssText =\n `position:fixed;left:${m.clientX}px;top:${m.clientY}px;z-index:2147483646;` +\n 'width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;pointer-events:none;' +\n `border:2px solid ${s.ripple};animation:__cine_ripple .55s ease-out forwards;`\n document.body.appendChild(r)\n setTimeout(() => r.remove(), 600)\n },\n true\n )\n\n const cap = document.createElement('div')\n cap.id = '__cine_cap'\n cap.style.cssText =\n 'position:fixed;left:50%;bottom:34px;transform:translateX(-50%) translateY(8px);' +\n 'z-index:2147483646;max-width:72%;padding:13px 24px;border-radius:13px;' +\n `font:500 17px/1.45 ${s.sansFont};color:#fff;letter-spacing:.01em;` +\n `background:${s.ink}e0;backdrop-filter:blur(7px);` +\n 'box-shadow:0 10px 34px rgba(0,0,0,.4);text-align:center;opacity:0;transition:opacity .35s,transform .35s;'\n document.body.appendChild(cap)\n\n const style = document.createElement('style')\n style.textContent =\n '@keyframes __cine_ripple{to{width:46px;height:46px;margin:-23px 0 0 -23px;opacity:0}}'\n document.head.appendChild(style)\n\n ;(window as unknown as { __cine_cap: (t: string) => void }).__cine_cap = (t: string) => {\n cap.textContent = t\n cap.style.opacity = t ? '1' : '0'\n cap.style.transform = `translateX(-50%) translateY(${t ? 0 : 8}px)`\n }\n }\n if (document.body) boot()\n else document.addEventListener('DOMContentLoaded', boot)\n }, skin)\n }\n\n async function cover(\n page: Page,\n { kicker, title, subtitle }: { kicker: string; title: string; subtitle?: string },\n holdMs = 2600\n ): Promise<void> {\n await page.evaluate(\n ({ kicker, title, subtitle, s }) => {\n document.getElementById('__cine_cover')?.remove()\n const el = document.createElement('div')\n el.id = '__cine_cover'\n el.style.cssText =\n 'position:fixed;inset:0;z-index:2147483647;display:flex;flex-direction:column;' +\n 'align-items:center;justify-content:center;text-align:center;padding:0 8%;' +\n `background:linear-gradient(135deg,${s.coverFrom} 0%,${s.coverMid} 48%,${s.coverTo} 165%);` +\n `opacity:0;transition:opacity .5s ease;font-family:${s.sansFont};`\n el.innerHTML =\n `<div style=\"text-transform:uppercase;letter-spacing:.26em;font-size:13px;font-weight:600;color:${s.accent};margin-bottom:22px\">${kicker}</div>` +\n `<div style=\"font-family:${s.displayFont};font-weight:600;font-size:52px;line-height:1.08;letter-spacing:-.02em;color:${s.coverTitle};max-width:16ch\">${title}</div>` +\n (subtitle\n ? `<div style=\"margin-top:22px;font-size:19px;line-height:1.5;color:${s.coverTitle}b8;max-width:46ch\">${subtitle}</div>`\n : '') +\n `<div style=\"margin-top:44px;display:flex;align-items:center;gap:10px;color:${s.coverTitle}80;font-size:13px;letter-spacing:.02em\">` +\n `<span style=\"width:26px;height:1px;background:${s.accent}\"></span>${s.firmLabel}</div>`\n document.body.appendChild(el)\n requestAnimationFrame(() => (el.style.opacity = '1'))\n },\n { kicker, title, subtitle: subtitle ?? '', s: skin }\n )\n await page.waitForTimeout(holdMs)\n }\n\n async function uncover(page: Page): Promise<void> {\n await page.evaluate(() => {\n const el = document.getElementById('__cine_cover')\n if (!el) return\n el.style.opacity = '0'\n setTimeout(() => el.remove(), 520)\n })\n await page.waitForTimeout(560)\n }\n\n async function caption(page: Page, text: string, holdMs?: number): Promise<void> {\n await page.evaluate(\n (t) => (window as unknown as { __cine_cap?: (s: string) => void }).__cine_cap?.(t),\n text\n )\n const hold = holdMs ?? Math.min(4200, 900 + text.length * 45)\n await page.waitForTimeout(hold)\n }\n\n async function clearCaption(page: Page): Promise<void> {\n await page.evaluate(() =>\n (window as unknown as { __cine_cap?: (s: string) => void }).__cine_cap?.('')\n )\n }\n\n async function beat(page: Page, ms = 650): Promise<void> {\n await page.waitForTimeout(ms)\n }\n\n async function glideTo(page: Page, target: string | Locator): Promise<Locator> {\n const loc = resolve(page, target).first()\n await loc.scrollIntoViewIfNeeded().catch(() => {})\n const box = await loc.boundingBox()\n if (box) {\n await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2, { steps: 26 })\n await page.waitForTimeout(180)\n }\n return loc\n }\n\n async function click(page: Page, target: string | Locator): Promise<void> {\n const loc = await glideTo(page, target)\n await loc.click()\n await page.waitForTimeout(260)\n }\n\n async function type(page: Page, target: string | Locator, text: string): Promise<void> {\n const loc = await glideTo(page, target)\n await loc.click()\n await loc.fill('')\n await loc.pressSequentially(text, { delay: 42 })\n await page.waitForTimeout(240)\n }\n\n async function login(page: Page, opts: { show?: boolean; caption?: string } = {}): Promise<void> {\n await page.goto(loginPath)\n if (opts.show === false) {\n await page.getByTestId(ids.email).fill(config.creds.email)\n await page.getByTestId(ids.password).fill(config.creds.password)\n await page.getByTestId(ids.submit).click()\n await page.waitForURL(appUrlPattern, { timeout: 45_000 })\n return\n }\n await caption(page, opts.caption ?? `${b.firmLabel} — signing in.`, 1600)\n await type(page, ids.email, config.creds.email)\n await type(page, ids.password, config.creds.password)\n await click(page, ids.submit)\n await page.waitForURL(appUrlPattern, { timeout: 45_000 })\n await beat(page, 800)\n }\n\n return {\n installStage,\n cover,\n uncover,\n caption,\n clearCaption,\n beat,\n glideTo,\n click,\n type,\n login,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/record/index.ts"],"names":["path","mkdirSync","writeFileSync","kicker","title","subtitle"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Cinematic recording harness — host-agnostic.\n *\n * Turns a Playwright run into a narrated product demo: a visible cursor that glides between\n * targets, a click ripple, captions, full-screen chapter cards, lower-thirds and human-speed\n * pacing. Every host app gets the same demo capability from one factory: brand colours, fonts,\n * credentials and the login flow arrive as config, so nothing here names a host.\n *\n * With a take running (`cine.take`), the run is also logged for the edit, in seconds from the\n * start of the video:\n * - every wait (the AI working, a file uploading) to `<dir>/<name>.waits.json`, so the edit can\n * cut the middle of each long one;\n * - the focus timeline to `<dir>/<name>.focus.json`: each click, type and read with its target's\n * box on screen, the key moments `focusOn` marks, the cards, lower-thirds and captions, the\n * take's config (zoom, max zoom, picture-in-picture) and the brand.\n * Captions, cards and lower-thirds are then drawn by the edit (brand PNGs over the video, outside\n * any zoom), not in the page, and a timecode strip in the corner lines the two clocks up.\n * `arbidocs-render-take` (this package's bin) renders the cut, zoomed, titled video from them.\n *\n * Usage in a recording script:\n * const cine = createCinematic({ brand, creds })\n * const take = await cine.take(page, { name: 'reply-with-arbi', dir: 'recordings' })\n * await cine.installStage(page) // after the take, before the first navigation\n * await take.markSync()\n * await page.goto('/')\n * await cine.chapter(page, { kicker, title, subtitle })\n * await cine.login(page, { show: false })\n * await cine.uncover(page)\n * await cine.click(page, 'sidebar-mail-button')\n * await take.wait('ARBI drafting', () => expect(reply).toBeVisible())\n * await cine.focusOn(page, reply, 'ARBI’s reply, as tracked changes')\n *\n * `@playwright/test` is an optional peer used for TYPES only (no runtime import), so importing\n * this entry never loads Playwright.\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport path from 'node:path'\nimport type { Page, Locator } from '@playwright/test'\n\n/** Brand skin for the on-screen chrome. All optional — sensible neutral defaults. */\nexport interface CinematicBrand {\n /** Footer line on chapter cards, e.g. \"Meridian · AI-native counsel\". */\n firmLabel: string\n /** Serif display font for cover titles (CSS font-family value). */\n displayFont?: string\n /** Sans font for captions + cover body. */\n sansFont?: string\n /** Cursor dot radial-gradient stops. */\n cursor?: { from: string; to: string }\n /** Click-ripple ring colour. */\n ripple?: string\n /** Chapter-card background gradient stops. */\n cover?: { from: string; mid: string; to: string }\n /** Accent (kicker text + rule) on chapter cards, callouts and lower-thirds. */\n accent?: string\n /** Caption bar background base colour. */\n ink?: string\n /** Cover title text colour. */\n coverTitle?: string\n /**\n * Font files for the edit's overlays (cards, captions), when the display or sans font is not\n * installed where the video is rendered: each a family name and a `file://` or `https://` URL.\n */\n fontFiles?: { family: string; url: string; weight?: string; unicodeRange?: string }[]\n}\n\nexport interface CinematicCreds {\n email: string\n password: string\n}\n\nexport interface CinematicConfig {\n brand: CinematicBrand\n /** For `login`. */\n creds?: CinematicCreds\n /** Login route (default \"/app/login\"). */\n loginPath?: string\n /** URL the app lands on after auth (default /\\/app$/). */\n appUrlPattern?: RegExp\n /** Login form testids (defaults match the shared AppShell/login convention). */\n testIds?: { email?: string; password?: string; submit?: string }\n}\n\n/** A box on screen, in page pixels. */\nexport interface Box {\n x: number\n y: number\n width: number\n height: number\n}\n\n/**\n * A moment the edit may frame: a click, typing, reading down a result, a glide-and-look (`point`,\n * which lasts until the next gesture), or a key moment marked with `focusOn`.\n */\nexport interface FocusEvent {\n kind: 'click' | 'type' | 'read' | 'point' | 'focus'\n label?: string\n start: number\n end?: number\n box: Box\n /** Draw a highlight (and the label as its tag) round the box. */\n callout?: boolean\n /** How to frame it: zoom in, a picture-in-picture inset, or not at all (default: the edit decides). */\n mode?: 'zoom' | 'pip' | 'none'\n}\n\n/** A take's say in its edit. */\nexport interface TakeOptions {\n /** The take's name: its files are `<dir>/<name>.waits.json` and `<dir>/<name>.focus.json`. */\n name: string\n /** Where the take's files go (default `recordings`). */\n dir?: string\n /** Zoom and pan onto the action (default true). */\n zoom?: boolean\n /** At most this much (default 1.8). */\n maxZoom?: number\n /** A picture-in-picture inset for long typing (default true). */\n pip?: boolean\n}\n\nexport interface Wait {\n label: string\n start: number\n end: number\n}\n\ninterface Card {\n kicker: string\n title: string\n subtitle?: string\n start: number\n end: number | null\n}\n\n/** The timecode's square, in page pixels (the renderer reads it at this size). */\nexport const TIMECODE_CELL = 8\n\nconst round = (n: number) => Math.round(n * 100) / 100\n\n/**\n * One recorded take: its clock, its waits and its focus timeline. Start it first thing (the video\n * starts with the page, a moment before; `markSync` lines the two clocks up exactly).\n */\nexport class Take {\n /** The take running now (one at a time: recordings run one after another). */\n private static active: Take | null = null\n\n readonly t0 = Date.now()\n readonly waits: Wait[] = []\n /** The brand the edit paints the cards, captions and callouts in. */\n private readonly brand: object\n readonly file: string\n readonly focusFile: string\n private readonly timeline = {\n sync: null as number | null,\n viewport: null as { width: number; height: number } | null,\n focus: [] as FocusEvent[],\n cards: [] as Card[],\n lowerThirds: [] as { kicker: string; title: string; start: number; end: number }[],\n captions: [] as { text: string; start: number; end: number | null }[],\n }\n\n constructor(\n readonly page: Page,\n private readonly options: TakeOptions,\n brand?: CinematicBrand\n ) {\n this.brand = brand ? cinematicSkin(brand) : {}\n const dir = path.resolve(options.dir ?? 'recordings')\n this.file = path.join(dir, `${options.name}.waits.json`)\n this.focusFile = path.join(dir, `${options.name}.focus.json`)\n this.timeline.viewport = page.viewportSize()\n mkdirSync(dir, { recursive: true })\n Take.active = this\n this.save()\n }\n\n /** The take running on `page`, if any. */\n static on(page: Page): Take | null {\n return Take.active?.page === page ? Take.active : null\n }\n\n /** Seconds since the take started. */\n now(): number {\n return (Date.now() - this.t0) / 1000\n }\n\n /** Log a wait (written at once, so a take that fails part-way still has its cut list). */\n log(label: string, start: number, end = this.now()): void {\n if (end - start < 1) return\n this.waits.push({ label, start: round(start), end: round(end) })\n this.save()\n }\n\n /** Wait for `until` (a UI state), logged as a wait the edit may cut. */\n async wait<T>(label: string, until: () => Promise<T>): Promise<T> {\n const start = this.now()\n try {\n return await until()\n } finally {\n this.log(label, start)\n }\n }\n\n /**\n * Paint the sync marker: a magenta frame for a moment, at a logged time. The edit finds it in the\n * video and lines the take's clock up with the video's. Call it before the first navigation.\n */\n async markSync(): Promise<void> {\n await this.page.evaluate(\n () =>\n new Promise<void>((done) => {\n document.documentElement.style.background = '#ff00ff'\n if (document.body) document.body.style.background = '#ff00ff'\n requestAnimationFrame(() => requestAnimationFrame(() => done()))\n })\n )\n this.timeline.sync = round(this.now())\n await this.page.waitForTimeout(400)\n this.save()\n }\n\n /** Log a focus event (a `point` with no end lasts until the next event). */\n record(event: Omit<FocusEvent, 'start' | 'end'> & { start: number; end?: number }): void {\n const { focus } = this.timeline\n const open = focus[focus.length - 1]\n if (open && open.kind === 'point' && open.end === undefined) open.end = round(event.start)\n focus.push({\n ...event,\n start: round(event.start),\n end: event.end === undefined ? undefined : round(event.end),\n })\n this.save()\n }\n\n /** @internal The stage's cards, lower-thirds and captions (drawn by the edit). */\n cardStart(card: Omit<Card, 'start' | 'end'>): void {\n this.cardEnd()\n this.captionEnd()\n this.timeline.cards.push({ ...card, start: round(this.now()), end: null })\n this.save()\n }\n\n cardEnd(): void {\n const last = this.timeline.cards[this.timeline.cards.length - 1]\n if (last && last.end === null) {\n last.end = round(this.now())\n this.save()\n }\n }\n\n lowerThird(kicker: string, title: string, holdMs: number): void {\n const start = round(this.now())\n this.timeline.lowerThirds.push({ kicker, title, start, end: round(start + holdMs / 1000) })\n this.save()\n }\n\n captionStart(text: string): void {\n this.captionEnd()\n this.timeline.captions.push({ text, start: round(this.now()), end: null })\n this.save()\n }\n\n captionEnd(): void {\n const last = this.timeline.captions[this.timeline.captions.length - 1]\n if (last && last.end === null) {\n last.end = round(this.now())\n this.save()\n }\n }\n\n private save(): void {\n const { zoom, maxZoom, pip } = this.options\n writeFileSync(this.file, JSON.stringify({ t0: this.t0, waits: this.waits }, null, 1))\n writeFileSync(\n this.focusFile,\n JSON.stringify(\n { t0: this.t0, config: { zoom, maxZoom, pip }, brand: this.brand, ...this.timeline },\n null,\n 1\n )\n )\n }\n}\n\nexport interface Cinematic {\n /** Start a take on `page` (before `installStage`, so the stage paints its timecode). */\n take(page: Page, options: TakeOptions): Promise<Take>\n installStage(page: Page): Promise<void>\n cover(\n page: Page,\n opts: { kicker: string; title: string; subtitle?: string },\n holdMs?: number\n ): Promise<void>\n /** A cover the work can go on behind (clicks pass through it) until `uncover`. */\n chapter(\n page: Page,\n opts: { kicker: string; title: string; subtitle?: string },\n holdMs?: number\n ): Promise<void>\n uncover(page: Page): Promise<void>\n /** A section's name over the bottom left while the work goes on (drawn by the edit). */\n lowerThird(page: Page, kicker: string, title: string, holdMs?: number): void\n caption(page: Page, text: string, holdMs?: number): Promise<void>\n clearCaption(page: Page): Promise<void>\n beat(page: Page, ms?: number): Promise<void>\n glideTo(page: Page, target: string | Locator): Promise<Locator>\n click(page: Page, target: string | Locator): Promise<void>\n type(page: Page, target: string | Locator, text: string): Promise<void>\n /** A key moment: glide to it and hold; the edit zooms onto it and draws a callout with `label`. */\n focusOn(\n page: Page,\n target: string | Locator,\n label?: string,\n opts?: { holdMs?: number; callout?: boolean; mode?: FocusEvent['mode'] }\n ): Promise<void>\n /** Read down a result at a reader's pace, then back to the top. */\n readDown(page: Page, target: string | Locator, scrolls?: number, pauseMs?: number): Promise<void>\n /** Sign in. `{ show: false }` authenticates fast + silent (no animation/caption). */\n login(page: Page, opts?: { show?: boolean; caption?: string }): Promise<void>\n}\n\nconst DEFAULTS = {\n displayFont: 'ui-serif, Georgia, serif',\n sansFont: 'Inter, ui-sans-serif, system-ui, sans-serif',\n cursor: { from: 'rgba(31,111,235,.98)', to: 'rgba(11,42,74,.92)' },\n ripple: 'rgba(11,42,74,.85)',\n cover: { from: '#0b1622', mid: '#0e1b2c', to: '#1f6feb' },\n accent: '#c9a24b',\n ink: '#0e1b2d',\n coverTitle: '#f4f6f8',\n}\n\n/** A brand with every default filled in: what the stage paints and the take hands the edit. */\nexport function cinematicSkin(b: CinematicBrand) {\n return {\n firmLabel: b.firmLabel,\n displayFont: b.displayFont ?? DEFAULTS.displayFont,\n sansFont: b.sansFont ?? DEFAULTS.sansFont,\n cursorFrom: b.cursor?.from ?? DEFAULTS.cursor.from,\n cursorTo: b.cursor?.to ?? DEFAULTS.cursor.to,\n ripple: b.ripple ?? DEFAULTS.ripple,\n coverFrom: b.cover?.from ?? DEFAULTS.cover.from,\n coverMid: b.cover?.mid ?? DEFAULTS.cover.mid,\n coverTo: b.cover?.to ?? DEFAULTS.cover.to,\n accent: b.accent ?? DEFAULTS.accent,\n ink: b.ink ?? DEFAULTS.ink,\n coverTitle: b.coverTitle ?? DEFAULTS.coverTitle,\n fontFiles: b.fontFiles ?? [],\n }\n}\n\nexport function createCinematic(config: CinematicConfig): Cinematic {\n const b = config.brand\n const skin = cinematicSkin(b)\n const loginPath = config.loginPath ?? '/app/login'\n const appUrlPattern = config.appUrlPattern ?? /\\/app$/\n const ids = {\n email: config.testIds?.email ?? 'auth-email',\n password: config.testIds?.password ?? 'auth-password',\n submit: config.testIds?.submit ?? 'auth-login-submit',\n }\n\n const resolve = (page: Page, t: string | Locator): Locator =>\n typeof t === 'string' ? page.getByTestId(t) : t\n\n /** The target's box on screen (clipped to the viewport), or null when it is not on screen. */\n async function boxOf(page: Page, loc: Locator): Promise<Box | null> {\n const box = await loc.boundingBox().catch(() => null)\n const vp = page.viewportSize()\n if (!box || !vp) return box\n const x = Math.max(box.x, 0)\n const y = Math.max(box.y, 0)\n const width = Math.min(box.x + box.width, vp.width) - x\n const height = Math.min(box.y + box.height, vp.height) - y\n return width > 0 && height > 0\n ? { x: round(x), y: round(y), width: round(width), height: round(height) }\n : null\n }\n\n /** Move the cursor to the centre of a target, smoothly; its box once there. */\n async function glide(\n page: Page,\n target: string | Locator\n ): Promise<{ loc: Locator; box: Box | null }> {\n const loc = resolve(page, target).first()\n await loc.scrollIntoViewIfNeeded().catch(() => {})\n const box = await boxOf(page, loc)\n if (box) {\n await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2, { steps: 26 })\n await page.waitForTimeout(180)\n }\n return { loc, box }\n }\n\n async function take(page: Page, options: TakeOptions): Promise<Take> {\n return new Take(page, options, b)\n }\n\n async function installStage(page: Page): Promise<void> {\n await page.addInitScript(\n ({ s, t0, TC }: { s: typeof skin; t0: number | null; TC: number }) => {\n const boot = () => {\n if (document.getElementById('__cine_cursor')) return\n\n const cursor = document.createElement('div')\n cursor.id = '__cine_cursor'\n cursor.style.cssText =\n 'position:fixed;left:0;top:0;z-index:2147483647;width:22px;height:22px;' +\n 'margin:-11px 0 0 -11px;border-radius:50%;pointer-events:none;' +\n 'transition:transform .09s ease-out;' +\n `background:radial-gradient(circle at 35% 35%, ${s.cursorFrom}, ${s.cursorTo});` +\n 'box-shadow:0 0 0 3px rgba(255,255,255,.6),0 2px 10px rgba(0,0,0,.4);'\n document.body.appendChild(cursor)\n\n window.addEventListener(\n 'mousemove',\n (e) => {\n cursor.style.transform = `translate(${(e as MouseEvent).clientX}px,${(e as MouseEvent).clientY}px)`\n },\n true\n )\n window.addEventListener(\n 'mousedown',\n (e) => {\n const m = e as MouseEvent\n const r = document.createElement('div')\n r.style.cssText =\n `position:fixed;left:${m.clientX}px;top:${m.clientY}px;z-index:2147483646;` +\n 'width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;pointer-events:none;' +\n `border:2px solid ${s.ripple};animation:__cine_ripple .55s ease-out forwards;`\n document.body.appendChild(r)\n setTimeout(() => r.remove(), 600)\n },\n true\n )\n\n const cap = document.createElement('div')\n cap.id = '__cine_cap'\n cap.style.cssText =\n 'position:fixed;left:50%;bottom:34px;transform:translateX(-50%) translateY(8px);' +\n 'z-index:2147483646;max-width:72%;padding:13px 24px;border-radius:13px;' +\n `font:500 17px/1.45 ${s.sansFont};color:#fff;letter-spacing:.01em;` +\n `background:${s.ink}e0;backdrop-filter:blur(7px);` +\n 'box-shadow:0 10px 34px rgba(0,0,0,.4);text-align:center;opacity:0;transition:opacity .35s,transform .35s;'\n document.body.appendChild(cap)\n\n const style = document.createElement('style')\n style.textContent =\n '@keyframes __cine_ripple{to{width:46px;height:46px;margin:-23px 0 0 -23px;opacity:0}}'\n document.head.appendChild(style)\n\n ;(window as unknown as { __cine_cap: (t: string) => void }).__cine_cap = (t: string) => {\n cap.textContent = t\n cap.style.opacity = t ? '1' : '0'\n cap.style.transform = `translateX(-50%) translateY(${t ? 0 : 8}px)`\n }\n\n // The timecode: with a take running, the take's clock in tenths of a second as 16 squares\n // (white = 1, most significant first) after a white and a black guard, in the bottom right\n // corner. The edit reads it from every frame to line the timeline up with the video (the\n // video's clock drifts from the wall clock over a long take), and paints it out.\n if (t0 !== null) {\n const strip = document.createElement('div')\n strip.id = '__cine_timecode'\n strip.style.cssText = `position:fixed;right:0;bottom:0;z-index:2147483647;display:flex;pointer-events:none;height:${TC}px`\n const cells = Array.from({ length: 18 }, (_, i) => {\n const cell = document.createElement('div')\n cell.style.cssText = `width:${TC}px;height:${TC}px;background:${i === 0 ? '#fff' : '#000'}`\n strip.appendChild(cell)\n return cell\n })\n document.body.appendChild(strip)\n const tick = () => {\n const ds = Math.max(0, Math.round((Date.now() - t0) / 100)) & 0xffff\n for (let bit = 0; bit < 16; bit += 1)\n cells[bit + 2].style.background = (ds >> (15 - bit)) & 1 ? '#fff' : '#000'\n requestAnimationFrame(tick)\n }\n tick()\n }\n }\n if (document.body) boot()\n else document.addEventListener('DOMContentLoaded', boot)\n },\n { s: skin, t0: Take.on(page)?.t0 ?? null, TC: TIMECODE_CELL }\n )\n }\n\n async function cover(\n page: Page,\n { kicker, title, subtitle }: { kicker: string; title: string; subtitle?: string },\n holdMs = 2600\n ): Promise<void> {\n // With a take running, the edit draws the card over this one from the brand PNG (crisp, cut to\n // length) and does the fades, so in the page it shows and goes at once.\n const running = Take.on(page)\n running?.cardStart({ kicker, title, subtitle })\n await page.evaluate(\n ({ kicker, title, subtitle, s, instant }) => {\n document.getElementById('__cine_cover')?.remove()\n const el = document.createElement('div')\n el.id = '__cine_cover'\n el.style.cssText =\n 'position:fixed;inset:0;z-index:2147483647;display:flex;flex-direction:column;' +\n 'align-items:center;justify-content:center;text-align:center;padding:0 8%;' +\n `background:linear-gradient(135deg,${s.coverFrom} 0%,${s.coverMid} 48%,${s.coverTo} 165%);` +\n `opacity:${instant ? 1 : 0};transition:opacity ${instant ? 0 : 0.5}s ease;font-family:${s.sansFont};`\n el.innerHTML =\n `<div style=\"text-transform:uppercase;letter-spacing:.26em;font-size:13px;font-weight:600;color:${s.accent};margin-bottom:22px\">${kicker}</div>` +\n `<div style=\"font-family:${s.displayFont};font-weight:600;font-size:52px;line-height:1.08;letter-spacing:-.02em;color:${s.coverTitle};max-width:16ch\">${title}</div>` +\n (subtitle\n ? `<div style=\"margin-top:22px;font-size:19px;line-height:1.5;color:${s.coverTitle}b8;max-width:46ch\">${subtitle}</div>`\n : '') +\n `<div style=\"margin-top:44px;display:flex;align-items:center;gap:10px;color:${s.coverTitle}80;font-size:13px;letter-spacing:.02em\">` +\n `<span style=\"width:26px;height:1px;background:${s.accent}\"></span>${s.firmLabel}</div>`\n document.body.appendChild(el)\n requestAnimationFrame(() => (el.style.opacity = '1'))\n },\n { kicker, title, subtitle: subtitle ?? '', s: skin, instant: !!running }\n )\n await page.waitForTimeout(holdMs)\n }\n\n async function chapter(\n page: Page,\n card: { kicker: string; title: string; subtitle?: string },\n holdMs?: number\n ): Promise<void> {\n await cover(page, card, holdMs)\n await page.evaluate(() => {\n const el = document.getElementById('__cine_cover')\n if (el) el.style.pointerEvents = 'none'\n })\n }\n\n async function uncover(page: Page): Promise<void> {\n const running = Take.on(page)\n await page.evaluate((instant) => {\n const el = document.getElementById('__cine_cover')\n if (!el) return\n if (instant) return el.remove()\n el.style.opacity = '0'\n setTimeout(() => el.remove(), 520)\n }, !!running)\n running?.cardEnd()\n await page.waitForTimeout(560)\n }\n\n function lowerThird(page: Page, kicker: string, title: string, holdMs = 3200): void {\n Take.on(page)?.lowerThird(kicker, title, holdMs)\n }\n\n async function caption(page: Page, text: string, holdMs?: number): Promise<void> {\n const running = Take.on(page)\n if (running) running.captionStart(text)\n else\n await page.evaluate(\n (t) => (window as unknown as { __cine_cap?: (s: string) => void }).__cine_cap?.(t),\n text\n )\n const hold = holdMs ?? Math.min(4200, 900 + text.length * 45)\n await page.waitForTimeout(hold)\n }\n\n async function clearCaption(page: Page): Promise<void> {\n const running = Take.on(page)\n if (running) running.captionEnd()\n else\n await page.evaluate(() =>\n (window as unknown as { __cine_cap?: (s: string) => void }).__cine_cap?.('')\n )\n }\n\n async function beat(page: Page, ms = 650): Promise<void> {\n await page.waitForTimeout(ms)\n }\n\n async function glideTo(page: Page, target: string | Locator): Promise<Locator> {\n const running = Take.on(page)\n const start = running?.now() ?? 0\n const { loc, box } = await glide(page, target)\n if (running && box) running.record({ kind: 'point', start, box })\n return loc\n }\n\n async function click(page: Page, target: string | Locator): Promise<void> {\n const running = Take.on(page)\n const start = running?.now() ?? 0\n const { loc, box } = await glide(page, target)\n await loc.click()\n await page.waitForTimeout(260)\n if (running && box) running.record({ kind: 'click', start, end: running.now(), box })\n }\n\n async function type(page: Page, target: string | Locator, text: string): Promise<void> {\n const running = Take.on(page)\n const start = running?.now() ?? 0\n const { loc, box } = await glide(page, target)\n await loc.click()\n await loc.fill('')\n await loc.pressSequentially(text, { delay: 42 })\n await page.waitForTimeout(240)\n if (running && box) running.record({ kind: 'type', start, end: running.now(), box })\n }\n\n async function focusOn(\n page: Page,\n target: string | Locator,\n label?: string,\n {\n holdMs = 2200,\n callout = true,\n mode,\n }: { holdMs?: number; callout?: boolean; mode?: FocusEvent['mode'] } = {}\n ): Promise<void> {\n const running = Take.on(page)\n const start = running?.now() ?? 0\n const { box } = await glide(page, target)\n await page.waitForTimeout(holdMs)\n if (running && box)\n running.record({ kind: 'focus', label, start, end: running.now(), box, callout, mode })\n }\n\n async function readDown(\n page: Page,\n target: string | Locator,\n scrolls = 3,\n pauseMs = 1600\n ): Promise<void> {\n const running = Take.on(page)\n const start = running?.now() ?? 0\n const { box } = await glide(page, target)\n for (let i = 0; i < scrolls; i += 1) {\n await page.mouse.wheel(0, 320)\n await beat(page, pauseMs)\n }\n await page.mouse.wheel(0, -320 * scrolls)\n await beat(page, 500)\n if (running && box) running.record({ kind: 'read', start, end: running.now(), box })\n }\n\n async function login(page: Page, opts: { show?: boolean; caption?: string } = {}): Promise<void> {\n if (!config.creds) throw new Error('createCinematic: pass creds to sign in')\n await page.goto(loginPath)\n if (opts.show === false) {\n await page.getByTestId(ids.email).fill(config.creds.email)\n await page.getByTestId(ids.password).fill(config.creds.password)\n await page.getByTestId(ids.submit).click()\n await page.waitForURL(appUrlPattern, { timeout: 45_000 })\n return\n }\n await caption(page, opts.caption ?? `${b.firmLabel} — signing in.`, 1600)\n await type(page, ids.email, config.creds.email)\n await type(page, ids.password, config.creds.password)\n await click(page, ids.submit)\n await page.waitForURL(appUrlPattern, { timeout: 45_000 })\n await beat(page, 800)\n }\n\n return {\n take,\n installStage,\n cover,\n chapter,\n uncover,\n lowerThird,\n caption,\n clearCaption,\n beat,\n glideTo,\n click,\n type,\n focusOn,\n readDown,\n login,\n }\n}\n"]}
|