@neta-art/cohub 3.0.0 → 3.2.0
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/README.md +33 -2
- package/dist/{board.d.ts → board/animation.d.ts} +4 -2
- package/dist/{chunks/board.js → board/animation.js} +5 -44
- package/dist/board/codec.d.ts +25 -0
- package/dist/board/codec.js +252 -0
- package/dist/board/core/bindings.d.ts +45 -0
- package/dist/board/core/bindings.js +162 -0
- package/dist/board/core/draw-geometry.d.ts +31 -0
- package/dist/board/core/draw-geometry.js +183 -0
- package/dist/board/core/export-assets.d.ts +14 -0
- package/dist/board/core/export-assets.js +22 -0
- package/dist/board/core/export-plan.d.ts +84 -0
- package/dist/board/core/export-plan.js +128 -0
- package/dist/board/core/file-preview.d.ts +176 -0
- package/dist/board/core/file-preview.js +271 -0
- package/dist/board/core/palette.d.ts +42 -0
- package/dist/board/core/palette.js +138 -0
- package/dist/board/core/shape-definition.d.ts +35 -0
- package/dist/board/core/shape-definition.js +64 -0
- package/dist/board/core/shape-types.d.ts +144 -0
- package/dist/board/core/shape-types.js +27 -0
- package/dist/board/core/text-metrics.d.ts +18 -0
- package/dist/board/core/text-metrics.js +43 -0
- package/dist/board/export/index.d.ts +56 -0
- package/dist/board/export/index.js +86 -0
- package/dist/board/export/scene.d.ts +35 -0
- package/dist/board/export/scene.js +69 -0
- package/dist/board/geometry.d.ts +131 -0
- package/dist/board/geometry.js +468 -0
- package/dist/board/headless/index.d.ts +69 -0
- package/dist/board/headless/index.js +150 -0
- package/dist/board/image-key.d.ts +19 -0
- package/dist/board/image-key.js +34 -0
- package/dist/board/index.d.ts +16 -0
- package/dist/board/index.js +16 -0
- package/dist/board/render/index.d.ts +6 -0
- package/dist/board/render/index.js +6 -0
- package/dist/board/render/palette.d.ts +5 -0
- package/dist/board/render/palette.js +30 -0
- package/dist/board/render/renderers/arrow-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/arrow-card-renderer.js +157 -0
- package/dist/board/render/renderers/base-card-renderer.d.ts +46 -0
- package/dist/board/render/renderers/base-card-renderer.js +153 -0
- package/dist/board/render/renderers/board-renderer-registry.d.ts +85 -0
- package/dist/board/render/renderers/board-renderer-registry.js +43 -0
- package/dist/board/render/renderers/draw-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/draw-card-renderer.js +82 -0
- package/dist/board/render/renderers/far-plate.d.ts +39 -0
- package/dist/board/render/renderers/far-plate.js +92 -0
- package/dist/board/render/renderers/file-card-renderer.d.ts +33 -0
- package/dist/board/render/renderers/file-card-renderer.js +371 -0
- package/dist/board/render/renderers/frame-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/frame-card-renderer.js +99 -0
- package/dist/board/render/renderers/geo-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/geo-card-renderer.js +128 -0
- package/dist/board/render/renderers/image-card-renderer.d.ts +8 -0
- package/dist/board/render/renderers/image-card-renderer.js +138 -0
- package/dist/board/render/renderers/note-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/note-card-renderer.js +112 -0
- package/dist/board/render/renderers/text-card-renderer.d.ts +7 -0
- package/dist/board/render/renderers/text-card-renderer.js +94 -0
- package/dist/board/render/renderers/unknown-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/unknown-card-renderer.js +102 -0
- package/dist/board/render/renderers/video-card-renderer.d.ts +7 -0
- package/dist/board/render/renderers/video-card-renderer.js +146 -0
- package/dist/board/render/text-measurement.d.ts +30 -0
- package/dist/board/render/text-measurement.js +57 -0
- package/dist/board/render/text-resolution.d.ts +16 -0
- package/dist/board/render/text-resolution.js +43 -0
- package/dist/board/render/themes/board-theme-registry.d.ts +20 -0
- package/dist/board/render/themes/board-theme-registry.js +13 -0
- package/dist/board/render/themes/clean-theme.d.ts +5 -0
- package/dist/board/render/themes/clean-theme.js +102 -0
- package/dist/chunks/http.d.ts +10 -40
- package/dist/chunks/http.js +26 -4
- package/dist/chunks/transport.js +4 -2
- package/dist/chunks/websocket.d.ts +832 -21
- package/dist/chunks/websocket.js +19 -2
- package/dist/http.d.ts +2 -3
- package/dist/index.d.ts +100 -5
- package/dist/index.js +391 -1
- package/dist/protocol/dist/board-constants.d.ts +23 -0
- package/dist/protocol/dist/board-constants.js +60 -0
- package/dist/protocol/dist/board-document.d.ts +1124 -0
- package/dist/protocol/dist/board-document.js +331 -0
- package/dist/protocol/dist/board.d.ts +186 -0
- package/dist/protocol/dist/board.js +207 -0
- package/dist/protocol/dist/index.d.ts +5 -0
- package/dist/protocol/dist/index.js +5 -0
- package/dist/protocol/dist/provenance.js +12 -0
- package/dist/protocol/dist/realtime/board-awareness.d.ts +1 -0
- package/dist/protocol/dist/realtime/board-awareness.js +117 -0
- package/dist/protocol/dist/realtime/types.d.ts +2 -0
- package/package.json +39 -4
- package/dist/board.js +0 -2
- package/dist/chunks/board.d.ts +0 -2589
package/dist/index.js
CHANGED
|
@@ -3,7 +3,6 @@ import { a as COHUB_SOURCE_HEADER, c as hasRequestSourceIdentity, d as mergeRequ
|
|
|
3
3
|
import { a as resolveApiBaseUrl, c as resolveWebsocketUrl, i as normalizeWebsocketUrl, n as normalizeBaseUrl, o as resolveCohubEnvironment, r as normalizeVoiceInputWebsocketUrl, s as resolveVoiceInputWebsocketUrl, t as COHUB_ENVIRONMENTS } from "./chunks/environment.js";
|
|
4
4
|
import { a as extractBillingPayload, c as isFeatureNotEntitledError, i as FEATURE_NOT_ENTITLED_ERROR_CODE, l as isHttpErrorCode, n as createWebsocketClient, o as isBillingAccessBlockedCode, r as BILLING_ACCESS_BLOCKED_ERROR_CODE, s as isBillingAccessBlockedError, t as WebsocketClient } from "./chunks/websocket.js";
|
|
5
5
|
import { VoiceApi, VoiceInputClient, createVoiceInputClient } from "./voice-input.js";
|
|
6
|
-
import { a as createBoardExtensionRegistry, i as compileSequence, n as DEFAULT_BOARD_LIMITS, o as timeline, r as clip, t as BoardExtensionRegistry } from "./chunks/board.js";
|
|
7
6
|
//#region src/apis/billing.ts
|
|
8
7
|
var BillingApi = class {
|
|
9
8
|
transport;
|
|
@@ -1267,4 +1266,395 @@ function filterGenerationDeclarationsByPolicy(declarations, policy) {
|
|
|
1267
1266
|
});
|
|
1268
1267
|
}
|
|
1269
1268
|
//#endregion
|
|
1269
|
+
//#region ../protocol/dist/board-constants.js
|
|
1270
|
+
const DEFAULT_BOARD_RENDER_LIMITS = {
|
|
1271
|
+
particles: 2e4,
|
|
1272
|
+
vertices: 5e5,
|
|
1273
|
+
dynamicVertices: 15e4,
|
|
1274
|
+
drawCalls: 400,
|
|
1275
|
+
filterPasses: 24,
|
|
1276
|
+
renderTexturePixels: 16777216,
|
|
1277
|
+
textureBytes: 512 * 1024 * 1024,
|
|
1278
|
+
bufferBytes: 256 * 1024 * 1024,
|
|
1279
|
+
simulationSteps: 1e5
|
|
1280
|
+
};
|
|
1281
|
+
const BOARD_BUILTIN_CLIP_KINDS = [
|
|
1282
|
+
"motion.keyframes",
|
|
1283
|
+
"motion.path",
|
|
1284
|
+
"draw.reveal",
|
|
1285
|
+
"draw.handwrite",
|
|
1286
|
+
"text.reveal",
|
|
1287
|
+
"effects.particles",
|
|
1288
|
+
"effects.trail",
|
|
1289
|
+
"effects.impact",
|
|
1290
|
+
"effects.flash",
|
|
1291
|
+
"effects.color",
|
|
1292
|
+
"camera.pan",
|
|
1293
|
+
"camera.zoom",
|
|
1294
|
+
"camera.shake"
|
|
1295
|
+
];
|
|
1296
|
+
const BOARD_BUILTIN_EFFECT_KINDS = ["effects.pulse", "effects.float"];
|
|
1297
|
+
const BOARD_BUILTIN_CAPABILITIES = [...BOARD_BUILTIN_CLIP_KINDS.map((id) => ({
|
|
1298
|
+
kind: "clip",
|
|
1299
|
+
id,
|
|
1300
|
+
version: 1,
|
|
1301
|
+
renderers: ["webgpu", "webgl"]
|
|
1302
|
+
})), ...BOARD_BUILTIN_EFFECT_KINDS.map((id) => ({
|
|
1303
|
+
kind: "effect",
|
|
1304
|
+
id,
|
|
1305
|
+
version: 1,
|
|
1306
|
+
renderers: ["webgpu", "webgl"]
|
|
1307
|
+
}))];
|
|
1308
|
+
//#endregion
|
|
1309
|
+
//#region src/board/animation.ts
|
|
1310
|
+
const ZERO_COST = {
|
|
1311
|
+
particles: 0,
|
|
1312
|
+
vertices: 0,
|
|
1313
|
+
dynamicVertices: 0,
|
|
1314
|
+
drawCalls: 0,
|
|
1315
|
+
filterPasses: 0,
|
|
1316
|
+
renderTexturePixels: 0,
|
|
1317
|
+
textureBytes: 0,
|
|
1318
|
+
bufferBytes: 0,
|
|
1319
|
+
simulationSteps: 0
|
|
1320
|
+
};
|
|
1321
|
+
const DEFAULT_BOARD_LIMITS = DEFAULT_BOARD_RENDER_LIMITS;
|
|
1322
|
+
const BUILTIN_CAPABILITIES = BOARD_BUILTIN_CAPABILITIES;
|
|
1323
|
+
function numericParam(params, key, fallback) {
|
|
1324
|
+
const value = params[key];
|
|
1325
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
1326
|
+
}
|
|
1327
|
+
function builtinDefinition(capability) {
|
|
1328
|
+
return {
|
|
1329
|
+
...capability,
|
|
1330
|
+
validate(params) {
|
|
1331
|
+
const diagnostics = [];
|
|
1332
|
+
if (capability.id === "effects.particles") {
|
|
1333
|
+
const count = params.count;
|
|
1334
|
+
const bounds = params.bounds;
|
|
1335
|
+
if (!Number.isSafeInteger(count) || count < 1 || count > DEFAULT_BOARD_LIMITS.particles) diagnostics.push({
|
|
1336
|
+
severity: "error",
|
|
1337
|
+
code: "INVALID_PARTICLE_COUNT",
|
|
1338
|
+
message: `count must be an integer between 1 and ${DEFAULT_BOARD_LIMITS.particles}`,
|
|
1339
|
+
path: "params.count"
|
|
1340
|
+
});
|
|
1341
|
+
if (!bounds || typeof bounds !== "object" || Array.isArray(bounds)) diagnostics.push({
|
|
1342
|
+
severity: "error",
|
|
1343
|
+
code: "PARTICLE_BOUNDS_REQUIRED",
|
|
1344
|
+
message: "particles require finite bounds",
|
|
1345
|
+
path: "params.bounds"
|
|
1346
|
+
});
|
|
1347
|
+
else {
|
|
1348
|
+
const value = bounds;
|
|
1349
|
+
if (![
|
|
1350
|
+
value.x,
|
|
1351
|
+
value.y,
|
|
1352
|
+
value.width,
|
|
1353
|
+
value.height
|
|
1354
|
+
].every((item) => typeof item === "number" && Number.isFinite(item)) || value.width <= 0 || value.height <= 0) diagnostics.push({
|
|
1355
|
+
severity: "error",
|
|
1356
|
+
code: "INVALID_PARTICLE_BOUNDS",
|
|
1357
|
+
message: "particle bounds must have a positive finite size",
|
|
1358
|
+
path: "params.bounds"
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
if (capability.id === "motion.path") {
|
|
1363
|
+
const points = params.points;
|
|
1364
|
+
if (!Array.isArray(points) || points.length < 2 || points.length > 1e4) diagnostics.push({
|
|
1365
|
+
severity: "error",
|
|
1366
|
+
code: "INVALID_MOTION_PATH",
|
|
1367
|
+
message: "motion path must contain 2 to 10000 points",
|
|
1368
|
+
path: "params.points"
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
return diagnostics;
|
|
1372
|
+
},
|
|
1373
|
+
getBounds(params) {
|
|
1374
|
+
const bounds = params.bounds;
|
|
1375
|
+
if (!bounds || typeof bounds !== "object" || Array.isArray(bounds)) return null;
|
|
1376
|
+
const value = bounds;
|
|
1377
|
+
return [
|
|
1378
|
+
value.x,
|
|
1379
|
+
value.y,
|
|
1380
|
+
value.width,
|
|
1381
|
+
value.height
|
|
1382
|
+
].every((item) => typeof item === "number" && Number.isFinite(item)) ? value : null;
|
|
1383
|
+
},
|
|
1384
|
+
estimateCost(params) {
|
|
1385
|
+
switch (capability.id) {
|
|
1386
|
+
case "effects.particles": {
|
|
1387
|
+
const particles = Math.max(0, Math.floor(numericParam(params, "count", 0)));
|
|
1388
|
+
return {
|
|
1389
|
+
particles,
|
|
1390
|
+
vertices: particles * 4,
|
|
1391
|
+
dynamicVertices: particles * 4,
|
|
1392
|
+
drawCalls: 1,
|
|
1393
|
+
bufferBytes: particles * 48,
|
|
1394
|
+
simulationSteps: particles
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
case "effects.trail": return {
|
|
1398
|
+
vertices: 32,
|
|
1399
|
+
dynamicVertices: 32,
|
|
1400
|
+
drawCalls: 1,
|
|
1401
|
+
bufferBytes: 1024,
|
|
1402
|
+
simulationSteps: 16
|
|
1403
|
+
};
|
|
1404
|
+
case "effects.impact":
|
|
1405
|
+
case "effects.flash": return {
|
|
1406
|
+
vertices: 64,
|
|
1407
|
+
drawCalls: 1
|
|
1408
|
+
};
|
|
1409
|
+
case "effects.color": return {
|
|
1410
|
+
drawCalls: 1,
|
|
1411
|
+
filterPasses: 1
|
|
1412
|
+
};
|
|
1413
|
+
case "draw.reveal":
|
|
1414
|
+
case "draw.handwrite": return {
|
|
1415
|
+
drawCalls: 1,
|
|
1416
|
+
dynamicVertices: 1
|
|
1417
|
+
};
|
|
1418
|
+
default: return {};
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
function stableHash(value) {
|
|
1424
|
+
let hash = 2166136261;
|
|
1425
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
1426
|
+
hash ^= value.charCodeAt(index);
|
|
1427
|
+
hash = Math.imul(hash, 16777619);
|
|
1428
|
+
}
|
|
1429
|
+
return (hash >>> 0).toString(36).padStart(7, "0");
|
|
1430
|
+
}
|
|
1431
|
+
function stableId(prefix, seed, path) {
|
|
1432
|
+
return `${prefix}_${stableHash(`${seed}:${path}`)}`;
|
|
1433
|
+
}
|
|
1434
|
+
function assertDuration(value, field) {
|
|
1435
|
+
if (!Number.isFinite(value) || value < 0) throw new TypeError(`${field} must be a finite non-negative number`);
|
|
1436
|
+
}
|
|
1437
|
+
const timeline = {
|
|
1438
|
+
clip(clip) {
|
|
1439
|
+
return {
|
|
1440
|
+
type: "clip",
|
|
1441
|
+
clip
|
|
1442
|
+
};
|
|
1443
|
+
},
|
|
1444
|
+
parallel(...children) {
|
|
1445
|
+
return {
|
|
1446
|
+
type: "parallel",
|
|
1447
|
+
children
|
|
1448
|
+
};
|
|
1449
|
+
},
|
|
1450
|
+
sequence(...children) {
|
|
1451
|
+
return {
|
|
1452
|
+
type: "sequence",
|
|
1453
|
+
children
|
|
1454
|
+
};
|
|
1455
|
+
},
|
|
1456
|
+
stagger(each, ...children) {
|
|
1457
|
+
assertDuration(each, "stagger each");
|
|
1458
|
+
return {
|
|
1459
|
+
type: "stagger",
|
|
1460
|
+
each,
|
|
1461
|
+
children
|
|
1462
|
+
};
|
|
1463
|
+
},
|
|
1464
|
+
delay(duration, child) {
|
|
1465
|
+
assertDuration(duration, "delay duration");
|
|
1466
|
+
return {
|
|
1467
|
+
type: "delay",
|
|
1468
|
+
duration,
|
|
1469
|
+
child
|
|
1470
|
+
};
|
|
1471
|
+
},
|
|
1472
|
+
repeat(count, child) {
|
|
1473
|
+
if (!Number.isSafeInteger(count) || count < 1 || count > 1e3) throw new TypeError("repeat count must be an integer between 1 and 1000");
|
|
1474
|
+
return {
|
|
1475
|
+
type: "repeat",
|
|
1476
|
+
count,
|
|
1477
|
+
child
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
};
|
|
1481
|
+
function clip(input) {
|
|
1482
|
+
assertDuration(input.duration, "clip duration");
|
|
1483
|
+
if (input.duration === 0) throw new TypeError("clip duration must be greater than zero");
|
|
1484
|
+
return timeline.clip({
|
|
1485
|
+
id: input.id,
|
|
1486
|
+
kind: input.kind,
|
|
1487
|
+
kindVersion: input.kindVersion ?? 1,
|
|
1488
|
+
target: input.target,
|
|
1489
|
+
duration: input.duration,
|
|
1490
|
+
layer: input.layer ?? "content",
|
|
1491
|
+
fill: input.fill ?? "none",
|
|
1492
|
+
easing: input.easing ?? "linear",
|
|
1493
|
+
params: input.params ?? {},
|
|
1494
|
+
keyframes: input.keyframes ?? [],
|
|
1495
|
+
assetRefs: input.assetRefs ?? [],
|
|
1496
|
+
seed: input.seed,
|
|
1497
|
+
metadata: input.metadata ?? {}
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
function flatten(input, offset, sequenceSeed, path) {
|
|
1501
|
+
if (input.type === "clip") {
|
|
1502
|
+
const clipSeed = input.clip.seed ?? `${sequenceSeed}:${path}`;
|
|
1503
|
+
return {
|
|
1504
|
+
duration: input.clip.duration,
|
|
1505
|
+
clips: [{
|
|
1506
|
+
...input.clip,
|
|
1507
|
+
id: input.clip.id ?? stableId("clip", sequenceSeed, path),
|
|
1508
|
+
start: offset,
|
|
1509
|
+
seed: clipSeed
|
|
1510
|
+
}]
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
if (input.type === "delay") {
|
|
1514
|
+
const nested = flatten(input.child, offset + input.duration, sequenceSeed, `${path}.child`);
|
|
1515
|
+
return {
|
|
1516
|
+
duration: input.duration + nested.duration,
|
|
1517
|
+
clips: nested.clips
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
if (input.type === "repeat") {
|
|
1521
|
+
const clips = [];
|
|
1522
|
+
let cursor = offset;
|
|
1523
|
+
let total = 0;
|
|
1524
|
+
for (let index = 0; index < input.count; index += 1) {
|
|
1525
|
+
const nested = flatten(input.child, cursor, sequenceSeed, `${path}.${index}`);
|
|
1526
|
+
clips.push(...nested.clips);
|
|
1527
|
+
cursor += nested.duration;
|
|
1528
|
+
total += nested.duration;
|
|
1529
|
+
}
|
|
1530
|
+
return {
|
|
1531
|
+
duration: total,
|
|
1532
|
+
clips
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
const clips = [];
|
|
1536
|
+
let duration = 0;
|
|
1537
|
+
for (const [index, child] of input.children.entries()) {
|
|
1538
|
+
const childOffset = input.type === "sequence" ? duration : input.type === "stagger" ? input.each * index : 0;
|
|
1539
|
+
const nested = flatten(child, offset + childOffset, sequenceSeed, `${path}.${index}`);
|
|
1540
|
+
clips.push(...nested.clips);
|
|
1541
|
+
duration = input.type === "sequence" ? duration + nested.duration : Math.max(duration, childOffset + nested.duration);
|
|
1542
|
+
}
|
|
1543
|
+
return {
|
|
1544
|
+
duration,
|
|
1545
|
+
clips
|
|
1546
|
+
};
|
|
1547
|
+
}
|
|
1548
|
+
function compileSequence(input) {
|
|
1549
|
+
const flattened = flatten(input.timeline, 0, input.seed, "root");
|
|
1550
|
+
flattened.clips.sort((left, right) => left.start - right.start || left.id.localeCompare(right.id));
|
|
1551
|
+
const refs = /* @__PURE__ */ new Map();
|
|
1552
|
+
for (const item of flattened.clips) for (const ref of item.assetRefs) refs.set(`${ref.type}:${ref.ref}:${ref.digest ?? ""}`, ref);
|
|
1553
|
+
return {
|
|
1554
|
+
sequence: {
|
|
1555
|
+
id: input.id,
|
|
1556
|
+
name: input.name,
|
|
1557
|
+
duration: flattened.duration,
|
|
1558
|
+
seed: input.seed,
|
|
1559
|
+
restPose: input.restPose ?? {},
|
|
1560
|
+
metadata: input.metadata ?? {}
|
|
1561
|
+
},
|
|
1562
|
+
clips: flattened.clips,
|
|
1563
|
+
assetRefs: [...refs.values()]
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
function addCost(target, source) {
|
|
1567
|
+
for (const key of Object.keys(target)) target[key] += source[key] ?? 0;
|
|
1568
|
+
}
|
|
1569
|
+
var BoardExtensionRegistry = class {
|
|
1570
|
+
#extensions = /* @__PURE__ */ new Map();
|
|
1571
|
+
#presets = /* @__PURE__ */ new Map();
|
|
1572
|
+
register(definition) {
|
|
1573
|
+
const key = `${definition.kind}:${definition.id}@${definition.version}`;
|
|
1574
|
+
const target = definition.kind === "preset" ? this.#presets : this.#extensions;
|
|
1575
|
+
if (target.has(key)) throw new Error(`Board extension is already registered: ${key}`);
|
|
1576
|
+
target.set(key, definition);
|
|
1577
|
+
return this;
|
|
1578
|
+
}
|
|
1579
|
+
capabilities() {
|
|
1580
|
+
const extensions = [...this.#extensions.values()].map(({ validate: _validate, getBounds: _bounds, getAssetRefs: _refs, estimateCost: _cost, ...definition }) => definition);
|
|
1581
|
+
const presets = [...this.#presets.values()].map(({ compile: _compile, ...definition }) => definition);
|
|
1582
|
+
return [...extensions, ...presets];
|
|
1583
|
+
}
|
|
1584
|
+
compilePreset(id, version, params) {
|
|
1585
|
+
const preset = this.#presets.get(`preset:${id}@${version}`);
|
|
1586
|
+
if (!preset) throw new Error(`Unknown Board preset: ${id}@${version}`);
|
|
1587
|
+
return preset.compile(params);
|
|
1588
|
+
}
|
|
1589
|
+
validate(input) {
|
|
1590
|
+
const diagnostics = [];
|
|
1591
|
+
const events = [];
|
|
1592
|
+
const profile = input.profile ?? "high";
|
|
1593
|
+
const persistentCost = { ...ZERO_COST };
|
|
1594
|
+
for (const [index, effect] of (input.effects ?? []).entries()) {
|
|
1595
|
+
const definition = this.#extensions.get(`effect:${effect.kind}@${effect.kindVersion}`);
|
|
1596
|
+
if (!definition) {
|
|
1597
|
+
diagnostics.push({
|
|
1598
|
+
severity: "warning",
|
|
1599
|
+
code: "UNKNOWN_EFFECT",
|
|
1600
|
+
message: `No renderer is registered for ${effect.kind}@${effect.kindVersion}`,
|
|
1601
|
+
path: `effects.${index}`
|
|
1602
|
+
});
|
|
1603
|
+
continue;
|
|
1604
|
+
}
|
|
1605
|
+
diagnostics.push(...definition.validate?.(effect.params) ?? []);
|
|
1606
|
+
addCost(persistentCost, definition.estimateCost(effect.params, profile));
|
|
1607
|
+
}
|
|
1608
|
+
for (const [index, clip] of input.clips.entries()) {
|
|
1609
|
+
const definition = this.#extensions.get(`clip:${clip.kind}@${clip.kindVersion}`);
|
|
1610
|
+
if (!definition) {
|
|
1611
|
+
diagnostics.push({
|
|
1612
|
+
severity: "warning",
|
|
1613
|
+
code: "UNKNOWN_CLIP",
|
|
1614
|
+
message: `No renderer is registered for ${clip.kind}@${clip.kindVersion}`,
|
|
1615
|
+
path: `clips.${index}`
|
|
1616
|
+
});
|
|
1617
|
+
continue;
|
|
1618
|
+
}
|
|
1619
|
+
diagnostics.push(...definition.validate?.(clip.params) ?? []);
|
|
1620
|
+
const cost = { ...ZERO_COST };
|
|
1621
|
+
addCost(cost, definition.estimateCost(clip.params, profile));
|
|
1622
|
+
events.push({
|
|
1623
|
+
at: clip.start,
|
|
1624
|
+
direction: 1,
|
|
1625
|
+
cost
|
|
1626
|
+
}, {
|
|
1627
|
+
at: clip.start + clip.duration,
|
|
1628
|
+
direction: -1,
|
|
1629
|
+
cost
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1632
|
+
events.sort((left, right) => left.at - right.at || left.direction - right.direction);
|
|
1633
|
+
const current = { ...persistentCost };
|
|
1634
|
+
const peak = { ...persistentCost };
|
|
1635
|
+
for (const event of events) for (const key of Object.keys(current)) {
|
|
1636
|
+
current[key] += event.cost[key] * event.direction;
|
|
1637
|
+
peak[key] = Math.max(peak[key], current[key]);
|
|
1638
|
+
}
|
|
1639
|
+
const limits = input.limits ?? DEFAULT_BOARD_LIMITS;
|
|
1640
|
+
for (const key of Object.keys(limits)) if (peak[key] > limits[key]) diagnostics.push({
|
|
1641
|
+
severity: "warning",
|
|
1642
|
+
code: "RENDER_BUDGET_EXCEEDED",
|
|
1643
|
+
message: `${key} peaks at ${peak[key]}, above ${limits[key]}`,
|
|
1644
|
+
path: key,
|
|
1645
|
+
adaptation: { quality: "lower" }
|
|
1646
|
+
});
|
|
1647
|
+
return {
|
|
1648
|
+
valid: !diagnostics.some((item) => item.severity === "error"),
|
|
1649
|
+
diagnostics,
|
|
1650
|
+
peakCost: peak
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1653
|
+
};
|
|
1654
|
+
function createBoardExtensionRegistry(input = {}) {
|
|
1655
|
+
const registry = new BoardExtensionRegistry();
|
|
1656
|
+
if (input.builtins !== false) for (const capability of BUILTIN_CAPABILITIES) registry.register(builtinDefinition(capability));
|
|
1657
|
+
return registry;
|
|
1658
|
+
}
|
|
1659
|
+
//#endregion
|
|
1270
1660
|
export { BILLING_ACCESS_BLOCKED_ERROR_CODE, BillingApi, BoardClient, BoardExtensionRegistry, BoardTransactionError, COHUB_ENVIRONMENTS, COHUB_SOURCE_HEADER, COHUB_SOURCE_HEADER_NAMES, CohubClient, CohubHttpClient, DEFAULT_BOARD_LIMITS, FEATURE_NOT_ENTITLED_ERROR_CODE, GenerationPolicyError, HttpError, ParentBridgeTransport, PopupBrokerTransport, REQUEST_SOURCE_VIA_MAX_LENGTH, ReferencesApi, ReferralsApi, SessionGenerationStreamClient, SessionPatchReducer, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRuntimeApi, WorksApi, assertGenerationRequestAllowedByPolicy, clearGrantedWorkScopes, clip, compileSequence, createBoardExtensionRegistry, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, createWorkBridgeCore, createWorkRuntime, decodeGenerationPolicy, encodeGenerationPolicy, extractBillingPayload, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, getAllowedGenerationModelIds, hasGrantedWorkScopes, hasRequestSourceIdentity, isBillingAccessBlockedCode, isBillingAccessBlockedError, isFeatureNotEntitledError, isHttpErrorCode, isRequestSourceEmpty, isRequestSourceUuid, joinApiUrl, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAssistantMessageCommit, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveCohubEnvironment, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, resolveWorkTransport, sanitizeAccessToken, setGrantedWorkScopes, timeline };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region ../protocol/dist/board-constants.d.ts
|
|
2
|
+
type BoardRenderCost = {
|
|
3
|
+
particles: number;
|
|
4
|
+
vertices: number;
|
|
5
|
+
dynamicVertices: number;
|
|
6
|
+
drawCalls: number;
|
|
7
|
+
filterPasses: number;
|
|
8
|
+
renderTexturePixels: number;
|
|
9
|
+
textureBytes: number;
|
|
10
|
+
bufferBytes: number;
|
|
11
|
+
simulationSteps: number;
|
|
12
|
+
};
|
|
13
|
+
type BoardCapability = {
|
|
14
|
+
kind: "preset" | "clip" | "effect" | "shader";
|
|
15
|
+
id: string;
|
|
16
|
+
version: number;
|
|
17
|
+
digest?: string;
|
|
18
|
+
renderers?: Array<"webgpu" | "webgl">;
|
|
19
|
+
fallbackId?: string;
|
|
20
|
+
schema?: Record<string, unknown>;
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { BoardCapability, BoardRenderCost };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
//#region ../protocol/dist/board-constants.js
|
|
2
|
+
const DEFAULT_BOARD_RENDER_LIMITS = {
|
|
3
|
+
particles: 2e4,
|
|
4
|
+
vertices: 5e5,
|
|
5
|
+
dynamicVertices: 15e4,
|
|
6
|
+
drawCalls: 400,
|
|
7
|
+
filterPasses: 24,
|
|
8
|
+
renderTexturePixels: 16777216,
|
|
9
|
+
textureBytes: 512 * 1024 * 1024,
|
|
10
|
+
bufferBytes: 256 * 1024 * 1024,
|
|
11
|
+
simulationSteps: 1e5
|
|
12
|
+
};
|
|
13
|
+
const BOARD_BUILTIN_CLIP_KINDS = [
|
|
14
|
+
"motion.keyframes",
|
|
15
|
+
"motion.path",
|
|
16
|
+
"draw.reveal",
|
|
17
|
+
"draw.handwrite",
|
|
18
|
+
"text.reveal",
|
|
19
|
+
"effects.particles",
|
|
20
|
+
"effects.trail",
|
|
21
|
+
"effects.impact",
|
|
22
|
+
"effects.flash",
|
|
23
|
+
"effects.color",
|
|
24
|
+
"camera.pan",
|
|
25
|
+
"camera.zoom",
|
|
26
|
+
"camera.shake"
|
|
27
|
+
];
|
|
28
|
+
const BOARD_BUILTIN_EFFECT_KINDS = ["effects.pulse", "effects.float"];
|
|
29
|
+
/**
|
|
30
|
+
* World-space typography for board text.
|
|
31
|
+
*
|
|
32
|
+
* These live here rather than beside the renderer because the document schema
|
|
33
|
+
* constrains persisted font sizes with them, and the schema must not depend on
|
|
34
|
+
* anything that draws.
|
|
35
|
+
*/
|
|
36
|
+
const BOARD_TEXT_FONT_FAMILY = "Geist";
|
|
37
|
+
/**
|
|
38
|
+
* Font stacks used by every board renderer.
|
|
39
|
+
*
|
|
40
|
+
* A bare "Geist" would render CJK (and anything else outside the Latin subset)
|
|
41
|
+
* as missing-glyph boxes, because the shipped webfont is Latin-only. The stack
|
|
42
|
+
* mirrors the web `--font-sans` / `--font-mono` tokens and adds the common CJK
|
|
43
|
+
* families, so both the browser and a headless export fall back to a real face
|
|
44
|
+
* instead of tofu.
|
|
45
|
+
*/
|
|
46
|
+
const BOARD_FONT_STACK = "\"Geist\", system-ui, -apple-system, \"Noto Sans CJK SC\", \"Noto Sans SC\", \"PingFang SC\", \"Microsoft YaHei\", sans-serif";
|
|
47
|
+
const BOARD_MONO_FONT_STACK = "\"Geist Mono\", \"Fira Code\", ui-monospace, \"Noto Sans Mono CJK SC\", monospace";
|
|
48
|
+
const BOARD_BUILTIN_CAPABILITIES = [...BOARD_BUILTIN_CLIP_KINDS.map((id) => ({
|
|
49
|
+
kind: "clip",
|
|
50
|
+
id,
|
|
51
|
+
version: 1,
|
|
52
|
+
renderers: ["webgpu", "webgl"]
|
|
53
|
+
})), ...BOARD_BUILTIN_EFFECT_KINDS.map((id) => ({
|
|
54
|
+
kind: "effect",
|
|
55
|
+
id,
|
|
56
|
+
version: 1,
|
|
57
|
+
renderers: ["webgpu", "webgl"]
|
|
58
|
+
}))];
|
|
59
|
+
//#endregion
|
|
60
|
+
export { BOARD_BUILTIN_CAPABILITIES, BOARD_BUILTIN_CLIP_KINDS, BOARD_BUILTIN_EFFECT_KINDS, BOARD_FONT_STACK, BOARD_MONO_FONT_STACK, BOARD_TEXT_FONT_FAMILY, DEFAULT_BOARD_RENDER_LIMITS };
|