@vectoriox/iox-ui 5.78.0 → 5.79.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/fesm2022/vectoriox-iox-ui-generation-core.mjs +307 -7
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-harness-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-media-core.mjs +23 -1
- package/fesm2022/vectoriox-iox-ui-media-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-scene-core.mjs +3 -6
- package/fesm2022/vectoriox-iox-ui-scene-core.mjs.map +1 -1
- package/generation-core/index.d.ts +178 -5
- package/harness-core/index.d.ts +3 -0
- package/media-core/index.d.ts +19 -1
- package/package.json +1 -1
- package/scene-core/index.d.ts +1 -4
- package/src/generation-core/compose-site.ts +13 -0
- package/src/generation-core/film.ts +91 -0
- package/src/generation-core/patterns.ts +5 -1
- package/src/generation-core/plan-wire.ts +4 -2
- package/src/generation-core/public-api.ts +1 -0
- package/src/generation-core/showcase.ts +16 -2
- package/src/generation-core/site-plan.model.ts +8 -0
- package/src/generation-core/site-spec.generated.ts +161 -1
- package/src/generation-core/validate-site-plan.ts +33 -0
- package/src/harness-core/generation-view.ts +3 -1
- package/src/media-core/frames.ts +23 -0
- package/src/scene-core/scene-edit.ts +3 -5
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { FrameSequence } from '@vectoriox/iox-ui/media-core';
|
|
1
2
|
import { AnimateId, DesignChoices, DesignTokenLike } from '@vectoriox/iox-ui/design-core';
|
|
2
3
|
import { SeoRawDoc } from '@vectoriox/iox-ui/seo-core';
|
|
3
4
|
import { ContentFieldLike } from '@vectoriox/iox-ui/composite-core';
|
|
@@ -13,6 +14,10 @@ declare const SPEC_SITE_PLAN_SHAPE: {
|
|
|
13
14
|
readonly dataSources: "(cmsDataSource | relativeDataSource)[] — merged by alias into the org library";
|
|
14
15
|
readonly pages: "page[]";
|
|
15
16
|
readonly globals: "globals";
|
|
17
|
+
readonly "film?": "film — the owner's film as pictures (SC6b), set by the build and placed by placeFilm; never a model's";
|
|
18
|
+
};
|
|
19
|
+
readonly film: {
|
|
20
|
+
readonly sequence: "object — a media-core FrameSequence: where the numbered pictures live, how many, their size";
|
|
16
21
|
};
|
|
17
22
|
readonly sourceTemplate: {
|
|
18
23
|
readonly kind: "'template'";
|
|
@@ -399,6 +404,104 @@ declare const SPEC_SITE_PATTERNS: {
|
|
|
399
404
|
}];
|
|
400
405
|
};
|
|
401
406
|
};
|
|
407
|
+
readonly "hero.scene-object": {
|
|
408
|
+
readonly family: "hero";
|
|
409
|
+
readonly scene: true;
|
|
410
|
+
readonly film: true;
|
|
411
|
+
readonly label: "Hero — your film plays as you scroll";
|
|
412
|
+
readonly intent: "The studio's own film plays forward and back with the scroll behind the headline while the page holds still.";
|
|
413
|
+
readonly node: {
|
|
414
|
+
readonly t: "Section";
|
|
415
|
+
readonly es: "section";
|
|
416
|
+
readonly scheme: "inverse";
|
|
417
|
+
readonly role: "scene";
|
|
418
|
+
readonly lay: {
|
|
419
|
+
readonly position: "relative";
|
|
420
|
+
readonly display: "block";
|
|
421
|
+
readonly width: "100%";
|
|
422
|
+
readonly height: "300vh";
|
|
423
|
+
readonly padding: "0px";
|
|
424
|
+
};
|
|
425
|
+
readonly c: readonly [{
|
|
426
|
+
readonly t: "Container";
|
|
427
|
+
readonly role: "scene.stage";
|
|
428
|
+
readonly lay: {
|
|
429
|
+
readonly position: "sticky";
|
|
430
|
+
readonly top: "0px";
|
|
431
|
+
readonly display: "block";
|
|
432
|
+
readonly width: "100%";
|
|
433
|
+
readonly height: "100svh";
|
|
434
|
+
readonly overflow: "hidden";
|
|
435
|
+
readonly padding: "0px";
|
|
436
|
+
};
|
|
437
|
+
readonly c: readonly [{
|
|
438
|
+
readonly t: "Video";
|
|
439
|
+
readonly es: "media";
|
|
440
|
+
readonly film: true;
|
|
441
|
+
readonly lay: {
|
|
442
|
+
readonly position: "absolute";
|
|
443
|
+
readonly top: "0px";
|
|
444
|
+
readonly left: "0px";
|
|
445
|
+
readonly width: "100%";
|
|
446
|
+
readonly height: "100%";
|
|
447
|
+
readonly aspectRatio: "auto";
|
|
448
|
+
readonly borderRadius: "0px";
|
|
449
|
+
};
|
|
450
|
+
readonly tracks: readonly [{
|
|
451
|
+
readonly prop: "play";
|
|
452
|
+
readonly keys: readonly [readonly [0, 0], readonly [1, 100]];
|
|
453
|
+
}];
|
|
454
|
+
}, {
|
|
455
|
+
readonly t: "Container";
|
|
456
|
+
readonly es: "media-scrim";
|
|
457
|
+
readonly lay: {
|
|
458
|
+
readonly display: "flex";
|
|
459
|
+
readonly flexDirection: "column";
|
|
460
|
+
readonly gap: "14px";
|
|
461
|
+
readonly position: "absolute";
|
|
462
|
+
readonly left: "0px";
|
|
463
|
+
readonly bottom: "0px";
|
|
464
|
+
readonly width: "100%";
|
|
465
|
+
readonly padding: "48px 32px 56px 32px";
|
|
466
|
+
};
|
|
467
|
+
readonly c: readonly [{
|
|
468
|
+
readonly t: "Heading";
|
|
469
|
+
readonly es: "display";
|
|
470
|
+
readonly level: "h1";
|
|
471
|
+
readonly slot: "headline";
|
|
472
|
+
readonly max: 56;
|
|
473
|
+
readonly fromBusiness: "name";
|
|
474
|
+
readonly tracks: readonly [{
|
|
475
|
+
readonly prop: "y";
|
|
476
|
+
readonly keys: readonly [readonly [0, 0], readonly [1, -6]];
|
|
477
|
+
}];
|
|
478
|
+
}, {
|
|
479
|
+
readonly t: "Text";
|
|
480
|
+
readonly es: "lead";
|
|
481
|
+
readonly slot: "lead";
|
|
482
|
+
readonly max: 180;
|
|
483
|
+
readonly fromBusiness: "tagline";
|
|
484
|
+
readonly ph: "copy";
|
|
485
|
+
readonly tracks: readonly [{
|
|
486
|
+
readonly prop: "opacity";
|
|
487
|
+
readonly keys: readonly [readonly [0.3, 0], readonly [0.45, 1]];
|
|
488
|
+
}];
|
|
489
|
+
}, {
|
|
490
|
+
readonly t: "ButtonBlock";
|
|
491
|
+
readonly es: "button-primary";
|
|
492
|
+
readonly href: "/contact";
|
|
493
|
+
readonly slot: "cta";
|
|
494
|
+
readonly max: 24;
|
|
495
|
+
readonly text: "Get in touch";
|
|
496
|
+
readonly tracks: readonly [{
|
|
497
|
+
readonly prop: "opacity";
|
|
498
|
+
readonly keys: readonly [readonly [0.35, 0], readonly [0.5, 1]];
|
|
499
|
+
}];
|
|
500
|
+
}];
|
|
501
|
+
}];
|
|
502
|
+
}];
|
|
503
|
+
};
|
|
504
|
+
};
|
|
402
505
|
readonly "story.scene-chapters": {
|
|
403
506
|
readonly family: "story";
|
|
404
507
|
readonly scene: true;
|
|
@@ -4523,6 +4626,10 @@ declare const SPEC_SITE_LIBRARY: readonly [{
|
|
|
4523
4626
|
readonly id: "hero.scene-depth";
|
|
4524
4627
|
readonly family: "hero";
|
|
4525
4628
|
readonly composed: true;
|
|
4629
|
+
}, {
|
|
4630
|
+
readonly id: "hero.scene-object";
|
|
4631
|
+
readonly family: "hero";
|
|
4632
|
+
readonly composed: true;
|
|
4526
4633
|
}, {
|
|
4527
4634
|
readonly id: "proof.logo-strip";
|
|
4528
4635
|
readonly family: "proof";
|
|
@@ -4887,6 +4994,12 @@ interface SitePlan {
|
|
|
4887
4994
|
readonly dataSources: ReadonlyArray<DataSourcePlan>;
|
|
4888
4995
|
readonly pages: ReadonlyArray<PagePlan>;
|
|
4889
4996
|
readonly globals: Readonly<Record<`${GlobalSlot}`, string>>;
|
|
4997
|
+
/** SC6b: the owner's film as pictures, set by the build and placed by `placeFilm` — never a model's. */
|
|
4998
|
+
readonly film?: PlanFilm;
|
|
4999
|
+
}
|
|
5000
|
+
/** SC6b: the owner's film — the numbered pictures the wizard's browser made of their video (media-core). */
|
|
5001
|
+
interface PlanFilm {
|
|
5002
|
+
readonly sequence: FrameSequence;
|
|
4890
5003
|
}
|
|
4891
5004
|
|
|
4892
5005
|
/**
|
|
@@ -5098,6 +5211,8 @@ interface PatternNode {
|
|
|
5098
5211
|
/** SC6: a Scene layer's scene-core tracks, written to the node's `sceneTracks` (and `scenePhoneTracks`). */
|
|
5099
5212
|
readonly tracks?: ReadonlyArray<PatternTrack>;
|
|
5100
5213
|
readonly phoneTracks?: ReadonlyArray<PatternTrack>;
|
|
5214
|
+
/** SC6b: the Video a film pattern plays the owner's film in (its `frames`). */
|
|
5215
|
+
readonly film?: boolean;
|
|
5101
5216
|
}
|
|
5102
5217
|
/**
|
|
5103
5218
|
* SC6: one scene-core track as the contract writes it — `{ prop, keys: [[progress, value]], from? }`. Typed here, not
|
|
@@ -5149,6 +5264,8 @@ interface SitePattern {
|
|
|
5149
5264
|
/** SC6: a Scene section — held while the page scrolls, moved by the scroll. Only at How animated Expressive, at
|
|
5150
5265
|
* most one per page and on at most two pages (`validateSitePlan`); it never takes the look's entrances. */
|
|
5151
5266
|
readonly scene?: boolean;
|
|
5267
|
+
/** SC6b: a Scene that plays the owner's film. Placed by `placeFilm`, never chosen: no manifest or wire lists it. */
|
|
5268
|
+
readonly film?: boolean;
|
|
5152
5269
|
readonly node: PatternNode;
|
|
5153
5270
|
}
|
|
5154
5271
|
declare const SITE_PATTERNS: Readonly<Record<string, SitePattern>>;
|
|
@@ -5513,7 +5630,10 @@ declare enum SitePlanIssueCode {
|
|
|
5513
5630
|
ReservedPageKey = "reserved-page-key",
|
|
5514
5631
|
/** SC6: a Scene below How animated Expressive, a second Scene on a page, or Scenes on more than the home page and
|
|
5515
5632
|
* one other — the pages answer by choosing another pattern. */
|
|
5516
|
-
SceneBudget = "scene-budget"
|
|
5633
|
+
SceneBudget = "scene-budget",
|
|
5634
|
+
/** SC6b: the owner's film — pictures that cannot play, too few to play smoothly, or a film's pattern on a plan with
|
|
5635
|
+
* no film (or twice). Set by the build, never by a model. */
|
|
5636
|
+
Film = "film"
|
|
5517
5637
|
}
|
|
5518
5638
|
type SitePlanIssue = PathIssue<SitePlanIssueCode>;
|
|
5519
5639
|
interface SitePlanValidation {
|
|
@@ -5920,7 +6040,11 @@ interface ShowcaseInput {
|
|
|
5920
6040
|
business: SiteBusiness;
|
|
5921
6041
|
design: DesignChoices;
|
|
5922
6042
|
locale?: `${SiteLocale}`;
|
|
6043
|
+
/** SC6b: the film the film's Scene plays — a render-parity run serves its own; absent, `SHOWCASE_FILM`. */
|
|
6044
|
+
film?: FrameSequence;
|
|
5923
6045
|
}
|
|
6046
|
+
/** SC6b: a film's description for the showcase — as many pictures as the build prepares; nothing is fetched to compose it. */
|
|
6047
|
+
declare const SHOWCASE_FILM: FrameSequence;
|
|
5924
6048
|
/** The showcase's pages: Home (the heroes), one page per other family in library order, and the item page. */
|
|
5925
6049
|
declare function showcasePages(): PagePlan[];
|
|
5926
6050
|
/** Every header and footer pattern, in contract order. */
|
|
@@ -5933,7 +6057,7 @@ declare function showcaseScenes(): string[];
|
|
|
5933
6057
|
/**
|
|
5934
6058
|
* The showcase as Site Plans — as many as it takes for every header and every footer to be composed once, then one per
|
|
5935
6059
|
* Scene pattern (SC6): its home page holds that Scene and nothing else, at How animated Expressive, the only level a
|
|
5936
|
-
* Scene is composed at.
|
|
6060
|
+
* Scene is composed at; the film's Scene with a film (SC6b).
|
|
5937
6061
|
*/
|
|
5938
6062
|
declare function showcasePlans(input: ShowcaseInput): SitePlan[];
|
|
5939
6063
|
|
|
@@ -6226,7 +6350,7 @@ declare function planPartOfPath(path: string): PlanPart;
|
|
|
6226
6350
|
declare function planWireGaps(): string[];
|
|
6227
6351
|
declare class PlanWireShapeError extends Error {
|
|
6228
6352
|
}
|
|
6229
|
-
/** The patterns a page section may use (every non-global one), in library order. */
|
|
6353
|
+
/** The patterns a page section may use (every non-global one but a film's, which `placeFilm` places), in library order. */
|
|
6230
6354
|
declare function sectionPatternIds(): string[];
|
|
6231
6355
|
declare function wireFieldJsonSchema(): JsonSchema;
|
|
6232
6356
|
/** What an object of the wire travels without when its children are written as their own entries (a plan edit's). */
|
|
@@ -7177,5 +7301,54 @@ declare function stockCreditNode(index: number, credit: StockLink): SerializedNo
|
|
|
7177
7301
|
/** Append the credit lines to the footer root (once each). Returns how many it added. */
|
|
7178
7302
|
declare function addStockCredits(footer: SerializedNode, credits: ReadonlyArray<StockLink>): number;
|
|
7179
7303
|
|
|
7180
|
-
|
|
7181
|
-
|
|
7304
|
+
/**
|
|
7305
|
+
* The owner's film on a built site (premium sites SC6b). The owner gives a video in Analysis; the wizard's browser makes
|
|
7306
|
+
* it pictures (cms-client `FramesPrepareService`); the build places it. A model never picks the film's pattern — the
|
|
7307
|
+
* manifest and the plan wire leave it out — so ONE pure placement decides where it goes, run by the wizard to draw the
|
|
7308
|
+
* Plan and by the server to build: they cannot disagree.
|
|
7309
|
+
*/
|
|
7310
|
+
/** The pattern a film plays in: the one whose Video is marked `film` in the contract. */
|
|
7311
|
+
declare const FILM_PATTERN: string;
|
|
7312
|
+
/** Why a film stays off the site. Each is said to the owner on the Plan step. */
|
|
7313
|
+
declare enum FilmUnplaced {
|
|
7314
|
+
/** How animated is below Expressive: no section holds the page there. */
|
|
7315
|
+
NotExpressive = "notExpressive",
|
|
7316
|
+
/** The home page does not open with a hero to play it in. */
|
|
7317
|
+
NoHero = "noHero",
|
|
7318
|
+
/** The home page already holds the page elsewhere (one Scene per page). */
|
|
7319
|
+
AnotherScene = "anotherScene",
|
|
7320
|
+
/** Too few pictures to play smoothly over the shortest hold (media-core `FILM_MIN_PICTURES`). */
|
|
7321
|
+
TooShort = "tooShort"
|
|
7322
|
+
}
|
|
7323
|
+
/** Where the film plays: the home page's first section when it is a hero. */
|
|
7324
|
+
interface FilmTarget {
|
|
7325
|
+
readonly page: number;
|
|
7326
|
+
readonly section: number;
|
|
7327
|
+
}
|
|
7328
|
+
type FilmPlacement = {
|
|
7329
|
+
readonly target: FilmTarget;
|
|
7330
|
+
readonly unplaced?: undefined;
|
|
7331
|
+
} | {
|
|
7332
|
+
readonly target?: undefined;
|
|
7333
|
+
readonly unplaced: FilmUnplaced;
|
|
7334
|
+
};
|
|
7335
|
+
/** Where a film WOULD play on this plan (the Plan step asks before the pictures exist). */
|
|
7336
|
+
declare function filmPlacement(plan: Pick<SitePlan, 'design' | 'pages'>): FilmPlacement;
|
|
7337
|
+
interface PlacedFilm {
|
|
7338
|
+
readonly plan: SitePlan;
|
|
7339
|
+
readonly unplaced?: FilmUnplaced;
|
|
7340
|
+
}
|
|
7341
|
+
/**
|
|
7342
|
+
* The plan with the owner's film in it: `film` set, and the home page's hero becomes the film's pattern, keeping the
|
|
7343
|
+
* hero's words and links that the film's pattern has. A film that cannot play (unreadable, too few pictures) or a plan
|
|
7344
|
+
* with no place for it leaves the plan as it was — the hero keeps its picture, and the builder can add the film later.
|
|
7345
|
+
*/
|
|
7346
|
+
declare function placeFilm(plan: SitePlan, sequence: unknown): PlacedFilm;
|
|
7347
|
+
/** The film's pictures as the composer stamps them, and the height its Scene holds the page for. */
|
|
7348
|
+
declare function filmOfPlan(plan: Pick<SitePlan, 'film'>): {
|
|
7349
|
+
sequence: FrameSequence;
|
|
7350
|
+
heightVh: number;
|
|
7351
|
+
} | null;
|
|
7352
|
+
|
|
7353
|
+
export { ACTIVE_BUILD_STATUSES, AI_REFUSAL_NEXT, AI_REFUSAL_STATUS, AI_STEPS, AI_STEP_LABELS, AI_STEP_NEEDS, AI_STEP_PART_TOKENS, AI_STEP_TYPICAL_TOKENS, AiCallStatus, AiCapability, AiFeature, AiGenerationStage, AiKeyMode, AiLimit, AiNextKind, AiProviderId, AiRefusalCode, AiStep, BAR_ITEMS_MAX, BAR_ITEMS_MIN, BASELINE_ROLES, BUILD_STEPS, BaselineRole, BindScope, BuildNoticeCode, BuildStep, CONTENT_ROLE_MEANINGS, CREDITS_PER_USD, CardBindTarget, CheckSeverity, ComposeError, ComposeIssueCode, ContentFieldControl, ContentFieldType, ContentRole, ContentTypeAction, CreatedKind, DANGLING_LINK_CODES, DEFAULT_PHONE_MENU_BREAKPOINT, DEFAULT_SITE_LOCALE, ENTRANCE_EASING, ENTRANCE_ORIGIN_LOOK, ENTRANCE_TRIGGER, EntrancePart, EntranceSide, FACT_KEYS, FIELD_TYPE_OF_CONTROL, FILM_PATTERN, FINAL_GENERATION_STAGES, FINDING_SEVERITY, FilmUnplaced, GRAMMAR_TOO_LARGE_MESSAGE, GlobalSlot, HEBREW_PREFIXES, JSON_SCHEMA_BANNED_KEYWORDS, JsonSchemaShapeError, KeptReason, NAV_PART_LABELS, NAV_SHAPE_COPY, NEUTRAL_STYLE_PROPS, NODE_BASELINES, NO_TOKENS, NavPagesSource, NavRole, NavShape, NavShapeError, PAGE_ARCHETYPES, PLAN_EDITS_ANSWER_SHAPES, PLAN_EDITS_PART_SCHEMA_NAMES, PLAN_EDIT_OP_PART, PLAN_EDIT_SHAPE, PLAN_EDIT_WIRE_KEYS, PLAN_PARTS, PLAN_PART_KEYS, PLAN_WIRE_DERIVED, PLAN_WIRE_PART_SCHEMA_NAMES, PLAN_WIRE_SHAPE, PRICING_PATTERN, PUBLISH_BLOCKING_PLACEHOLDERS, PageDataKind, PathIssueCollector, PatternDirective, PatternGlobalPosition, PatternOpens, PatternPlaceholder, PatternRecipe, PhoneMenuBreakpoint, PlaceholderKind, PlanChangeAction, PlanChangeKind, PlanDataSourceMode, PlanDataSourceType, PlanEditIssueCode, PlanEditOp, PlanEditsOutcome, PlanPart, PlanWireEntry, PlanWireShapeError, PlanWordIssueCode, PreflightRefusalCode, PublishRefusalCode, REQUIRED_CONTENT_ROLES, RelativeOp, SAMPLE_IMAGE_REF, SCENE_LEVEL, SCENE_OTHER_PAGES, SHOWCASE_FILM, SITE_CHECKS, SITE_FACT_LABELS, SITE_HEADER_PATTERN, SITE_LIBRARY, SITE_LOCALES, SITE_NEED_IDS, SITE_PATTERNS, SITE_PLAN_VERSION, SITE_TEMPLATES, SPEC_SITE_ARCHETYPES, SPEC_SITE_COPY_LENGTHS, SPEC_SITE_DENSITY_COPY, SPEC_SITE_FACTS, SPEC_SITE_LIBRARY, SPEC_SITE_LOCALES, SPEC_SITE_NEED_IDS, SPEC_SITE_PATTERNS, SPEC_SITE_PLAN_SHAPE, SPEC_SITE_REQUIRED_ROLES, SPEC_SITE_ROLES, SPEC_SITE_TEMPLATES, STOCK_FAMILIES, STOCK_FAMILY_INTENTS, STOCK_INTENT_ORDER, STOCK_INTENT_SUBJECTS, STOCK_ITEM_ASPECT, STOCK_MIN_KEPT, STOCK_PROVIDER_TERMS, STOCK_SUBJECT_WORDS, STRICT_SCHEMA_BUDGET, STRICT_SCHEMA_LIMITS, STUDIO_TEMPLATE, SiteBuildKind, SiteBuildStatus, SiteCheckId, SiteFindingCode, SiteLocale, SitePlanError, SitePlanIssueCode, SitePlanSourceKind, SiteTemplateError, SiteTemplateId, StepState, StockIntent, StockOrientation, StockProviderId, StockReviewFlag, StockReviewVerdict, StockSlotKind, StockSubject, addBarItem, addStockCredits, aiStepParts, applyOwnPhotoGalleries, applyPlanEdits, applyStockItemPhotos, applyStockPhotos, archetypeIssues, aspectRatioOf, assertStyleSlots, assertValidSitePlan, auditSite, barIconForRoute, blocksPublish, buildKeys, buildStepFacts, builtHomePageId, composeNavHeader, composeSection, composeSite, contentTypePreviewFields, contentTypeToWire, copyLengthOf, costUsd, createSerializedNode, creditsOfUsd, dataSourceToWire, derivedDataSources, describePlanData, describeShapeKey, entranceAction, entranceInteraction, estimateStepCredits, expandPlanWire, expandWireContentType, expandWireDataSource, expandWireEdit, expandWireField, expandWirePage, expandWireSection, failedBuildStep, fieldToWire, filmOfPlan, filmPlacement, findNavRoot, isActiveBuild, isNonEmptyString, isPlainObject, isRtlLocale, jsonAnyOf, jsonBoolean, jsonClosedObject, jsonInteger, jsonListOf, jsonOneOf, jsonSchemaKeywords, jsonSchemaObjects, jsonShapedObject, jsonText, modelCanDo, moveBarItem, navPages, navShapeBreakpoint, navShapeOf, nextSourceOf, nodeBindPaths, orientationOfRatio, pageToWire, parsePatternPath, parseSampleImageRef, pathAt, patternById, patternHasForm, patternLinkSlots, patternListGap, patternManifest, patternNeedsBinding, patternNodes, patternOptionalParts, patternRoleNeeds, patternScopes, patternSlotBudgets, patternSlots, patternTakesBinding, phoneMenuPages, placeFilm, planEditOps, planEditToWire, planEditWireGaps, planEditWireKeys, planEditWireOps, planEditWireShape, planEditsFromWire, planEditsJsonSchema, planEditsToWire, planEntrances, planFromTemplate, planNavShape, planOwnPhotos, planPartOfPath, planPartToWire, planStockPhotos, planToWire, planWireGaps, planWirePartJsonSchema, planWirePartShape, planWordIssues, publishRefusal, publishVerdict, recipeListBinds, releasedLayoutDefaults, removeBarItem, requiredAcknowledgements, requiredShapeKeys, roleField, routeMatches, routeParams, sampleImageRef, scoreStockPhoto, sectionEntrances, sectionPatternIds, sectionToWire, setStyleProps, shapeKeys, showcaseGlobals, showcasePages, showcasePlans, showcaseScenes, siteNavPages, slotBudget, stockCopyKey, stockCreditLine, stockCreditLines, stockCreditNode, stockCreditNodeId, stockFits, stockGroupOf, stockItemSlots, stockKept, stockPhotoRatio, stockPhotoSubject, stockPhotoUsable, stockPhotoWords, stockSlots, stockWord, stockWords, strictSchemaComplexity, strictSchemaRefusal, typicalStepTokens, validatePlanEdits, validateSitePlan, walkSerialized, wireContentTypeJsonSchema, wireDataSourceJsonSchema, wireFieldJsonSchema, wirePageJsonSchema, wireSectionJsonSchema, withDerivedSources, wordPattern, writtenTexts };
|
|
7354
|
+
export type { AddBarItemResult, AiEntitlementsView, AiMeter, AiModelEntry, AiRefusal, AiTokenCounts, AiTokenPrice, AuditPage, AuditPlaceholder, BarItemsEditResult, BuildNotice, BuildStepError, BuildStepFacts, BuildStepRecord, CmsDataSourcePlan, ComposeContext, ComposeIssue, ComposedDataSource, ComposedItem, ComposedNavHeader, ComposedPage, ComposedPlaceholder, ComposedRoute, ComposedSection, ComposedSite, ContentFieldPlan, ContentRoles, ContentSeedPlan, ContentTypePlan, CreateNodeOptions, CreatedRecord, DataSourcePlan, DynamicKeysAsList, EntranceAction, EntranceActionOptions, EntranceInteraction, EntranceMark, EntranceSpec, EntranceStamp, FactKey, FilmPlacement, FilmTarget, JsonSchema, NavHeaderInput, NavHeaderOptions, NavPage, NavShapeOptions, NavShapeResult, NodeBaseline, OwnPhotoPlacement, PageArchetype, PageArchetypeId, PageArchetypeSlot, PageData, PageDataLine, PagePlan, PageSectionPlan, PageSeoPlan, PathIssue, PatternManifestEntry, PatternManifestOptions, PatternNode, PatternPath, PatternRoleNeed, PatternTrack, PlacedFilm, PlainObject, PlanChange, PlanEdit, PlanEditIssue, PlanEditResult, PlanEditsAnswer, PlanEntrancesInput, PlanFilm, PlanWireContext, PlanWireParts, PlanWordContext, PlanWordIssue, PreflightRefusal, PublishRefusal, RecipeListBinds, RelativeDataSourcePlan, SectionEntrances, SectionInput, SectionOptions, SerializedBinding, SerializedNode, SerializedResponsive, ShapeEntry, ShapeIssueCodes, ShowcaseInput, SiteAudit, SiteAuditOptions, SiteAuditSnapshot, SiteBuildRun, SiteBusiness, SiteCheck, SiteFinding, SiteNeedId, SitePageRef, SitePattern, SitePlan, SitePlanIssue, SitePlanSource, SitePlanValidation, SiteTemplate, StockCredit, StockItemSlot, StockLink, StockNeed, StockPhoto, StockPhotoTraits, StockPlacement, StockPlanOptions, StockProviderTerms, StockReview, StockSlot, StockTarget, StrictSchemaComplexity, StrictSchemaRefusal, TemplatePlanInput, UndoKept, UndoPreview, UndoRecord, WireOptions, WrittenText };
|
package/harness-core/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MotionId, MoodId, TintId, DensityId, DesignMotion, DesignChoices, DesignMode, StylePreset, ShapeId, AnimateId } from '@vectoriox/iox-ui/design-core';
|
|
2
2
|
import { FactKey, PathIssue, PlainObject, JsonSchema, SiteTemplate, ShapeEntry, AiGenerationStage, AiStep, SitePlan, PlanEdit, PlanChange, SiteAudit } from '@vectoriox/iox-ui/generation-core';
|
|
3
3
|
export { JsonSchema } from '@vectoriox/iox-ui/generation-core';
|
|
4
|
+
import { FrameSequence } from '@vectoriox/iox-ui/media-core';
|
|
4
5
|
|
|
5
6
|
declare const SPEC_HARNESS_SOURCE: {
|
|
6
7
|
readonly repo: "nextlevelbuilder/ui-ux-pro-max-skill";
|
|
@@ -2948,11 +2949,13 @@ interface AiGenerationView {
|
|
|
2948
2949
|
stage: `${AiGenerationStage}`;
|
|
2949
2950
|
/** The model step the runner is working on; null = the owner's move. */
|
|
2950
2951
|
task: `${AiStep}` | null;
|
|
2952
|
+
/** `film`: the owner's film as pictures (SC6b), told by the wizard at Build — `placeFilm` places it. */
|
|
2951
2953
|
intake: {
|
|
2952
2954
|
prompt: string;
|
|
2953
2955
|
files: GenerationFileView[];
|
|
2954
2956
|
addresses: string[];
|
|
2955
2957
|
auto: boolean;
|
|
2958
|
+
film?: FrameSequence;
|
|
2956
2959
|
};
|
|
2957
2960
|
readers: GenerationReadersView;
|
|
2958
2961
|
reads: {
|
package/media-core/index.d.ts
CHANGED
|
@@ -111,6 +111,24 @@ declare const PHONE_LONG_SIDE = 1100;
|
|
|
111
111
|
declare function fittedFrameSize(width: number, height: number, longSide: number): FrameSizes;
|
|
112
112
|
/** How many pictures a video of `seconds` becomes. */
|
|
113
113
|
declare function videoFrameCount(seconds: number): number;
|
|
114
|
+
/**
|
|
115
|
+
* Pictures per screen of scrolling at which a played film stays smooth as a glide slows to a stop. Measured on Doron's
|
|
116
|
+
* iPhone (2026-11-05): Studio Alma's film at about 11 a screen stepped, at about 55 it did not.
|
|
117
|
+
*/
|
|
118
|
+
declare const FILM_SMOOTH_PER_SCREEN = 40;
|
|
119
|
+
/** The fewest and most screens a film the build places holds the page for (SC6b): long enough to feel, short enough to pass. */
|
|
120
|
+
declare const FILM_MIN_SCREENS = 1;
|
|
121
|
+
declare const FILM_MAX_SCREENS = 4;
|
|
122
|
+
/** What the build prepares a film to: about 60 pictures a screen at the longest hold — denser than smooth, never wasted. */
|
|
123
|
+
declare const FILM_PREPARED_PICTURES: number;
|
|
124
|
+
/** The fewest pictures a placed film may have: smooth over the shortest hold. */
|
|
125
|
+
declare const FILM_MIN_PICTURES: number;
|
|
126
|
+
/**
|
|
127
|
+
* The screens a film of `count` pictures holds the page for (SC6b, the composer's density rule): the stretches between
|
|
128
|
+
* pictures are what scroll, so `(count − 1) ÷ 40`, rounded DOWN to a tenth (150 pictures over 3.75 screens measure 39.7 a
|
|
129
|
+
* screen, thin), within the hold's limits. Null: too few pictures to play smoothly over the shortest hold.
|
|
130
|
+
*/
|
|
131
|
+
declare function filmScreensFor(count: number): number | null;
|
|
114
132
|
/** Which of `sourceCount` pictures make a set of `count`, spread evenly, first and last always in. */
|
|
115
133
|
declare function sampledFrameIndexes(sourceCount: number, count: number): number[];
|
|
116
134
|
/** Rendered frames in their real order: `frame2` before `frame10`. */
|
|
@@ -473,5 +491,5 @@ declare function attachVideos(container: ParentNode, options?: VideoRuntimeOptio
|
|
|
473
491
|
/** The runtime already running at `el`, if any. */
|
|
474
492
|
declare function videoRuntimeOf(el: Element | null | undefined): VideoRuntime | null;
|
|
475
493
|
|
|
476
|
-
export { CONSENT_GRANT_EVENT, CONSENT_PREFERENCES_EVENT, FRAMES_PHONE_MAX_WIDTH, FRAMES_SHOWING_ATTRIBUTE, FRAMES_UNPACKED_BYTES, FRAME_BLEND_STEPS, FRAME_SEQUENCE_ID, FrameExtension, FramePlayer, FrameSet, FramesClass, MAX_FRAMES, MAX_FRAME_BYTES, PHONE_LONG_SIDE, VIDEO_EMBED_ORIGINS, VIDEO_NODE_TYPE, VIDEO_PROVIDER_COMPANY, VIDEO_PROVIDER_LABEL, VIDEO_WORDS, VideoAttribute, VideoClass, VideoIcon, VideoKind, VideoMode, VideoRuntime, VideoSource, VideoTrait, WIDE_LONG_SIDE, attachVideoAt, attachVideos, documentConsentTransport, fittedFrameSize, frameBlendAt, frameFileName, frameIndexAt, frameLoadOrder, framePosition, frameSetFor, frameSummary, frameUrl, framesToHold, isThirdPartyPoster, nearestLoadedFrame, normalizeFrameSequence, parseVideoUrl, phoneFrameSrcset, planVideo, readConsentRecord, sampledFrameIndexes, serializeVideoAttributes, sortFrameFiles, unpackedFrameCount, videoConsentCategory, videoEmbedUrl, videoFrameCount, videoInnerHtml, videoPlayLabel, videoPosterFileName, videoProp, videoRefOf, videoRootAttributes, videoRuntimeOf, videoSourceOf, videoThumbnailRequest, videoWords };
|
|
494
|
+
export { CONSENT_GRANT_EVENT, CONSENT_PREFERENCES_EVENT, FILM_MAX_SCREENS, FILM_MIN_PICTURES, FILM_MIN_SCREENS, FILM_PREPARED_PICTURES, FILM_SMOOTH_PER_SCREEN, FRAMES_PHONE_MAX_WIDTH, FRAMES_SHOWING_ATTRIBUTE, FRAMES_UNPACKED_BYTES, FRAME_BLEND_STEPS, FRAME_SEQUENCE_ID, FrameExtension, FramePlayer, FrameSet, FramesClass, MAX_FRAMES, MAX_FRAME_BYTES, PHONE_LONG_SIDE, VIDEO_EMBED_ORIGINS, VIDEO_NODE_TYPE, VIDEO_PROVIDER_COMPANY, VIDEO_PROVIDER_LABEL, VIDEO_WORDS, VideoAttribute, VideoClass, VideoIcon, VideoKind, VideoMode, VideoRuntime, VideoSource, VideoTrait, WIDE_LONG_SIDE, attachVideoAt, attachVideos, documentConsentTransport, filmScreensFor, fittedFrameSize, frameBlendAt, frameFileName, frameIndexAt, frameLoadOrder, framePosition, frameSetFor, frameSummary, frameUrl, framesToHold, isThirdPartyPoster, nearestLoadedFrame, normalizeFrameSequence, parseVideoUrl, phoneFrameSrcset, planVideo, readConsentRecord, sampledFrameIndexes, serializeVideoAttributes, sortFrameFiles, unpackedFrameCount, videoConsentCategory, videoEmbedUrl, videoFrameCount, videoInnerHtml, videoPlayLabel, videoPosterFileName, videoProp, videoRefOf, videoRootAttributes, videoRuntimeOf, videoSourceOf, videoThumbnailRequest, videoWords };
|
|
477
495
|
export type { ConsentGrantDetail, ConsentTransport, FrameBlend, FramePlayerOptions, FrameSequence, FrameSetInfo, FrameSizes, VideoMarkupOptions, VideoNodeLike, VideoPlan, VideoRef, VideoRuntimeOptions, VideoThumbnailRequest, VideoWords };
|
package/package.json
CHANGED
package/scene-core/index.d.ts
CHANGED
|
@@ -218,10 +218,7 @@ declare const SCENE_MAX_SCREENS = 20;
|
|
|
218
218
|
*/
|
|
219
219
|
declare function sceneScreensOf(height: string | null | undefined): number | null;
|
|
220
220
|
declare function sceneHeightForScreens(screens: number): string;
|
|
221
|
-
/**
|
|
222
|
-
* Pictures per screen of scrolling at which a played film stays smooth as a glide slows to a stop. Measured on Doron's
|
|
223
|
-
* iPhone (2026-11-05): Studio Alma's film at about 11 a screen stepped, at about 55 it did not.
|
|
224
|
-
*/
|
|
221
|
+
/** Pictures per screen of scrolling at which a played film stays smooth (media-core's, which the composer sizes by). */
|
|
225
222
|
declare const SCENE_FILM_SMOOTH = 40;
|
|
226
223
|
interface SceneFilmDensity {
|
|
227
224
|
/** Pictures per screen of scrolling over most of the play: half its scroll holds at least this many. */
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from '@vectoriox/iox-ui/composite-core';
|
|
11
11
|
|
|
12
12
|
import { EntranceMark, EntrancePart, planEntrances } from './entrances';
|
|
13
|
+
import { filmOfPlan } from './film';
|
|
13
14
|
import { NODE_BASELINES } from './node-baselines.generated';
|
|
14
15
|
import {
|
|
15
16
|
BindScope, CardBindTarget, parsePatternPath, PatternDirective, PatternNode, PatternOpens, PatternPlaceholder, PatternRecipe, PatternTrack, SitePattern, patternById,
|
|
@@ -206,6 +207,8 @@ const IMAGE = 'Image';
|
|
|
206
207
|
const VIDEO = 'Video';
|
|
207
208
|
/** A Video's source prop (media-core `VideoTrait.Source` — not `source`, which names a data source). */
|
|
208
209
|
const VIDEO_SOURCE_PROP = 'videoSource';
|
|
210
|
+
/** A Video's pictures the scroll plays (media-core `VideoTrait.Frames`). */
|
|
211
|
+
const VIDEO_FRAMES_PROP = 'frames';
|
|
209
212
|
const DIALOG = 'Dialog';
|
|
210
213
|
const SUBMIT_BUTTON = 'SubmitButton';
|
|
211
214
|
const FORM_SUCCESS = 'FormSuccess';
|
|
@@ -602,6 +605,13 @@ function composeNode(given: PatternNode, id: string, repeater: RepeaterScope | n
|
|
|
602
605
|
setProp(node, VIDEO_SOURCE_PROP, 'file');
|
|
603
606
|
setProp(node, 'mode', pn.video);
|
|
604
607
|
}
|
|
608
|
+
// SC6b: a film pattern's Video plays the owner's pictures (the build places the pattern only with a film).
|
|
609
|
+
if (pn.film) {
|
|
610
|
+
if (type !== VIDEO) throw new ComposeError(`${id}: "film" belongs on a Video`);
|
|
611
|
+
const film = filmOfPlan(ctx.plan);
|
|
612
|
+
if (!film) throw new ComposeError(`${id}: a film's pattern on a plan with no film`);
|
|
613
|
+
setProp(node, VIDEO_FRAMES_PROP, film.sequence);
|
|
614
|
+
}
|
|
605
615
|
if (pn.ph === PatternPlaceholder.Video) {
|
|
606
616
|
setProp(node, 'src', '');
|
|
607
617
|
ctx.placeholders.push({ nodeId: id, owner: ctx.owner, kind: PlaceholderKind.Video, text: '' });
|
|
@@ -1013,6 +1023,9 @@ function composePattern(pattern: SitePattern, id: string, ctx: Ctx, motion: Sect
|
|
|
1013
1023
|
wireShownWhen(node, own.shownWhen ?? []);
|
|
1014
1024
|
// A Scene moves by the scroll alone: the look's entrances would fade its pinned stage in on arrival (SC6).
|
|
1015
1025
|
if (motion && !pattern.global && !pattern.scene) stampEntrances(node, pattern.family, own.entrances ?? [], motion);
|
|
1026
|
+
// SC6b, the density rule: a film's Scene holds the page as long as its pictures stay smooth, and no longer.
|
|
1027
|
+
const film = pattern.film ? filmOfPlan(ctx.plan) : null;
|
|
1028
|
+
if (film) setStyleProps(node, { height: `${film.heightVh}vh` });
|
|
1016
1029
|
node.label = pattern.label;
|
|
1017
1030
|
return node;
|
|
1018
1031
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { filmScreensFor, FrameSequence, normalizeFrameSequence } from '@vectoriox/iox-ui/media-core';
|
|
2
|
+
|
|
3
|
+
import { patternById, patternLinkSlots, patternSlots, SCENE_LEVEL, SITE_PATTERNS } from './patterns';
|
|
4
|
+
import { PageSectionPlan, SitePlan } from './site-plan.model';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The owner's film on a built site (premium sites SC6b). The owner gives a video in Analysis; the wizard's browser makes
|
|
8
|
+
* it pictures (cms-client `FramesPrepareService`); the build places it. A model never picks the film's pattern — the
|
|
9
|
+
* manifest and the plan wire leave it out — so ONE pure placement decides where it goes, run by the wizard to draw the
|
|
10
|
+
* Plan and by the server to build: they cannot disagree.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** The pattern a film plays in: the one whose Video is marked `film` in the contract. */
|
|
14
|
+
export const FILM_PATTERN: string = Object.entries(SITE_PATTERNS).find(([, p]) => p.film)?.[0] ?? '';
|
|
15
|
+
|
|
16
|
+
/** Why a film stays off the site. Each is said to the owner on the Plan step. */
|
|
17
|
+
export enum FilmUnplaced {
|
|
18
|
+
/** How animated is below Expressive: no section holds the page there. */
|
|
19
|
+
NotExpressive = 'notExpressive',
|
|
20
|
+
/** The home page does not open with a hero to play it in. */
|
|
21
|
+
NoHero = 'noHero',
|
|
22
|
+
/** The home page already holds the page elsewhere (one Scene per page). */
|
|
23
|
+
AnotherScene = 'anotherScene',
|
|
24
|
+
/** Too few pictures to play smoothly over the shortest hold (media-core `FILM_MIN_PICTURES`). */
|
|
25
|
+
TooShort = 'tooShort',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Where the film plays: the home page's first section when it is a hero. */
|
|
29
|
+
export interface FilmTarget {
|
|
30
|
+
readonly page: number;
|
|
31
|
+
readonly section: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type FilmPlacement = { readonly target: FilmTarget; readonly unplaced?: undefined } | { readonly target?: undefined; readonly unplaced: FilmUnplaced };
|
|
35
|
+
|
|
36
|
+
/** Where a film WOULD play on this plan (the Plan step asks before the pictures exist). */
|
|
37
|
+
export function filmPlacement(plan: Pick<SitePlan, 'design' | 'pages'>): FilmPlacement {
|
|
38
|
+
if ((plan.design as { animate?: string }).animate !== SCENE_LEVEL) return { unplaced: FilmUnplaced.NotExpressive };
|
|
39
|
+
const page = plan.pages.findIndex(p => p.isHome);
|
|
40
|
+
const sections = page >= 0 ? plan.pages[page].sections : [];
|
|
41
|
+
const first = patternById(sections[0]?.pattern);
|
|
42
|
+
if (!first || first.family !== FILM_FAMILY) return { unplaced: FilmUnplaced.NoHero };
|
|
43
|
+
if (sections.slice(1).some(s => patternById(s.pattern)?.scene)) return { unplaced: FilmUnplaced.AnotherScene };
|
|
44
|
+
return { target: { page, section: 0 } };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const FILM_FAMILY = SITE_PATTERNS[FILM_PATTERN]?.family ?? 'hero';
|
|
48
|
+
|
|
49
|
+
export interface PlacedFilm {
|
|
50
|
+
readonly plan: SitePlan;
|
|
51
|
+
readonly unplaced?: FilmUnplaced;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The plan with the owner's film in it: `film` set, and the home page's hero becomes the film's pattern, keeping the
|
|
56
|
+
* hero's words and links that the film's pattern has. A film that cannot play (unreadable, too few pictures) or a plan
|
|
57
|
+
* with no place for it leaves the plan as it was — the hero keeps its picture, and the builder can add the film later.
|
|
58
|
+
*/
|
|
59
|
+
export function placeFilm(plan: SitePlan, sequence: unknown): PlacedFilm {
|
|
60
|
+
const film = normalizeFrameSequence(sequence);
|
|
61
|
+
if (!film || filmScreensFor(film.wide.count) === null) return { plan, unplaced: FilmUnplaced.TooShort };
|
|
62
|
+
const placement = filmPlacement(plan);
|
|
63
|
+
if (!placement.target) return { plan, unplaced: placement.unplaced };
|
|
64
|
+
const { page, section } = placement.target;
|
|
65
|
+
const pages = plan.pages.map((p, i) => i !== page ? p : {
|
|
66
|
+
...p,
|
|
67
|
+
sections: p.sections.map((s, j) => (j === section ? filmSection(s) : s)),
|
|
68
|
+
});
|
|
69
|
+
return { plan: { ...plan, pages, film: { sequence: film } } };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function filmSection(hero: PageSectionPlan): PageSectionPlan {
|
|
73
|
+
const pattern = SITE_PATTERNS[FILM_PATTERN];
|
|
74
|
+
const slots = new Set(patternSlots(pattern));
|
|
75
|
+
const links = new Set(patternLinkSlots(pattern));
|
|
76
|
+
const keep = (values: Readonly<Record<string, string>> | undefined, allowed: Set<string>) => {
|
|
77
|
+
const kept = Object.entries(values ?? {}).filter(([key]) => allowed.has(key));
|
|
78
|
+
return kept.length ? Object.fromEntries(kept) : undefined;
|
|
79
|
+
};
|
|
80
|
+
const keptSlots = keep(hero.slots, slots);
|
|
81
|
+
const keptLinks = keep(hero.links, links);
|
|
82
|
+
return { pattern: FILM_PATTERN, ...(keptSlots ? { slots: keptSlots } : {}), ...(keptLinks ? { links: keptLinks } : {}) };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The film's pictures as the composer stamps them, and the height its Scene holds the page for. */
|
|
86
|
+
export function filmOfPlan(plan: Pick<SitePlan, 'film'>): { sequence: FrameSequence; heightVh: number } | null {
|
|
87
|
+
const sequence = normalizeFrameSequence(plan.film?.sequence);
|
|
88
|
+
const screens = sequence ? filmScreensFor(sequence.wide.count) : null;
|
|
89
|
+
// A Scene's root holds the page for its height less the one screen its stage fills.
|
|
90
|
+
return sequence && screens !== null ? { sequence, heightVh: Math.round((screens + 1) * 100) } : null;
|
|
91
|
+
}
|
|
@@ -93,6 +93,8 @@ export interface PatternNode {
|
|
|
93
93
|
/** SC6: a Scene layer's scene-core tracks, written to the node's `sceneTracks` (and `scenePhoneTracks`). */
|
|
94
94
|
readonly tracks?: ReadonlyArray<PatternTrack>;
|
|
95
95
|
readonly phoneTracks?: ReadonlyArray<PatternTrack>;
|
|
96
|
+
/** SC6b: the Video a film pattern plays the owner's film in (its `frames`). */
|
|
97
|
+
readonly film?: boolean;
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
/**
|
|
@@ -154,6 +156,8 @@ export interface SitePattern {
|
|
|
154
156
|
/** SC6: a Scene section — held while the page scrolls, moved by the scroll. Only at How animated Expressive, at
|
|
155
157
|
* most one per page and on at most two pages (`validateSitePlan`); it never takes the look's entrances. */
|
|
156
158
|
readonly scene?: boolean;
|
|
159
|
+
/** SC6b: a Scene that plays the owner's film. Placed by `placeFilm`, never chosen: no manifest or wire lists it. */
|
|
160
|
+
readonly film?: boolean;
|
|
157
161
|
readonly node: PatternNode;
|
|
158
162
|
}
|
|
159
163
|
|
|
@@ -352,7 +356,7 @@ export interface PatternManifestOptions {
|
|
|
352
356
|
*/
|
|
353
357
|
export function patternManifest(density?: string | null, options: PatternManifestOptions = {}): PatternManifestEntry[] {
|
|
354
358
|
const scenes = !('animate' in options) || options.animate === SCENE_LEVEL;
|
|
355
|
-
return Object.entries(SITE_PATTERNS).filter(([, p]) => scenes || !p.scene).map(([id, p]) => ({
|
|
359
|
+
return Object.entries(SITE_PATTERNS).filter(([, p]) => !p.film && (scenes || !p.scene)).map(([id, p]) => ({
|
|
356
360
|
id, family: p.family, label: p.label, intent: p.intent, ...(p.global ? { global: p.global } : {}),
|
|
357
361
|
slots: Object.fromEntries(Object.keys(patternSlotBudgets(p)).map(slot => [slot, slotBudget(p, slot, density) as number])),
|
|
358
362
|
links: patternLinkSlots(p),
|
|
@@ -196,6 +196,8 @@ export const PLAN_WIRE_DERIVED: Readonly<Record<string, string>> = {
|
|
|
196
196
|
sourceTemplate: 'the AI never writes a template plan',
|
|
197
197
|
sourceAi: 'this run (the context)',
|
|
198
198
|
design: "the owner's pick (the context)",
|
|
199
|
+
'plan.film': "the owner's film, set by the build (SC6b)",
|
|
200
|
+
film: "the owner's film, set by the build (SC6b)",
|
|
199
201
|
};
|
|
200
202
|
|
|
201
203
|
const wireText = (spec: WireKey): string => {
|
|
@@ -252,9 +254,9 @@ const orNone = (values: ReadonlyArray<string>): JsonSchema => jsonOneOf([NONE, .
|
|
|
252
254
|
const closedOrText = (values: ReadonlyArray<string>): JsonSchema => (values.length ? jsonOneOf(values) : jsonText());
|
|
253
255
|
const shaped = (entry: `${PlanWireEntry}`, properties: Record<string, JsonSchema>) => jsonShapedObject(PLAN_WIRE_SHAPE[entry], properties, `wire ${entry}`);
|
|
254
256
|
|
|
255
|
-
/** The patterns a page section may use (every non-global one), in library order. */
|
|
257
|
+
/** The patterns a page section may use (every non-global one but a film's, which `placeFilm` places), in library order. */
|
|
256
258
|
export function sectionPatternIds(): string[] {
|
|
257
|
-
return Object.entries(SITE_PATTERNS).filter(([, p]) => !p.global).map(([id]) => id);
|
|
259
|
+
return Object.entries(SITE_PATTERNS).filter(([, p]) => !p.global && !p.film).map(([id]) => id);
|
|
258
260
|
}
|
|
259
261
|
|
|
260
262
|
const sectionPatterns = () => sectionPatternIds().map(id => SITE_PATTERNS[id]);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DesignChoices } from '@vectoriox/iox-ui/design-core';
|
|
2
|
+
import { FILM_PREPARED_PICTURES, FrameExtension, FrameSequence } from '@vectoriox/iox-ui/media-core';
|
|
2
3
|
|
|
3
4
|
import { BindScope, patternNeedsBinding, PatternGlobalPosition, patternScopes, SCENE_LEVEL, SITE_PATTERNS } from './patterns';
|
|
4
5
|
import { GlobalSlot, PagePlan, PageSectionPlan, SiteBusiness, SiteLocale, SitePlan, SitePlanSourceKind, SITE_PLAN_VERSION } from './site-plan.model';
|
|
@@ -15,8 +16,17 @@ export interface ShowcaseInput {
|
|
|
15
16
|
business: SiteBusiness;
|
|
16
17
|
design: DesignChoices;
|
|
17
18
|
locale?: `${SiteLocale}`;
|
|
19
|
+
/** SC6b: the film the film's Scene plays — a render-parity run serves its own; absent, `SHOWCASE_FILM`. */
|
|
20
|
+
film?: FrameSequence;
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
/** SC6b: a film's description for the showcase — as many pictures as the build prepares; nothing is fetched to compose it. */
|
|
24
|
+
export const SHOWCASE_FILM: FrameSequence = {
|
|
25
|
+
base: 'https://showcase.iox.invalid/film', ext: FrameExtension.Webp,
|
|
26
|
+
wide: { count: FILM_PREPARED_PICTURES, width: 1600, height: 900 },
|
|
27
|
+
phone: { count: FILM_PREPARED_PICTURES, width: 1100, height: 619 },
|
|
28
|
+
};
|
|
29
|
+
|
|
20
30
|
const ITEM_ROUTE = '/work/:slug';
|
|
21
31
|
const LIST_SOURCE = 'projects';
|
|
22
32
|
|
|
@@ -70,7 +80,7 @@ export function showcaseScenes(): string[] {
|
|
|
70
80
|
/**
|
|
71
81
|
* The showcase as Site Plans — as many as it takes for every header and every footer to be composed once, then one per
|
|
72
82
|
* Scene pattern (SC6): its home page holds that Scene and nothing else, at How animated Expressive, the only level a
|
|
73
|
-
* Scene is composed at.
|
|
83
|
+
* Scene is composed at; the film's Scene with a film (SC6b).
|
|
74
84
|
*/
|
|
75
85
|
export function showcasePlans(input: ShowcaseInput): SitePlan[] {
|
|
76
86
|
const { headers, footers } = showcaseGlobals();
|
|
@@ -87,6 +97,10 @@ export function showcasePlans(input: ShowcaseInput): SitePlan[] {
|
|
|
87
97
|
pages: JSON.parse(JSON.stringify(planPages)),
|
|
88
98
|
globals: { [GlobalSlot.Header]: headers[i % headers.length], [GlobalSlot.Footer]: footers[i % footers.length] } as SitePlan['globals'],
|
|
89
99
|
});
|
|
90
|
-
const scenes = showcaseScenes().map((id, i) =>
|
|
100
|
+
const scenes = showcaseScenes().map((id, i) => {
|
|
101
|
+
const scene = plan(i, [{ key: 'home', name: 'Home', route: '/', isHome: true, inNav: false, sections: [sectionFor(id)] }], { ...input.design, animate: SCENE_LEVEL });
|
|
102
|
+
// A film's Scene plays a film (SC6b): the plan carries one, as the build's would.
|
|
103
|
+
return SITE_PATTERNS[id].film ? { ...scene, film: { sequence: JSON.parse(JSON.stringify(input.film ?? SHOWCASE_FILM)) } } : scene;
|
|
104
|
+
});
|
|
91
105
|
return [...Array.from({ length: count }, (_, i) => plan(i, pages, input.design)), ...scenes];
|
|
92
106
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FrameSequence } from '@vectoriox/iox-ui/media-core';
|
|
1
2
|
import type { AnimateId, DesignChoices } from '@vectoriox/iox-ui/design-core';
|
|
2
3
|
|
|
3
4
|
import { SPEC_SITE_ARCHETYPES, SPEC_SITE_FACTS, SPEC_SITE_LOCALES, SPEC_SITE_NEED_IDS, SPEC_SITE_REQUIRED_ROLES, SPEC_SITE_ROLES } from './site-spec.generated';
|
|
@@ -246,4 +247,11 @@ export interface SitePlan {
|
|
|
246
247
|
readonly dataSources: ReadonlyArray<DataSourcePlan>;
|
|
247
248
|
readonly pages: ReadonlyArray<PagePlan>;
|
|
248
249
|
readonly globals: Readonly<Record<`${GlobalSlot}`, string>>;
|
|
250
|
+
/** SC6b: the owner's film as pictures, set by the build and placed by `placeFilm` — never a model's. */
|
|
251
|
+
readonly film?: PlanFilm;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** SC6b: the owner's film — the numbered pictures the wizard's browser made of their video (media-core). */
|
|
255
|
+
export interface PlanFilm {
|
|
256
|
+
readonly sequence: FrameSequence;
|
|
249
257
|
}
|