@neatico/visual-core 0.14.3 → 0.14.64

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.
Files changed (68) hide show
  1. package/dist/candidateRanking.d.ts +31 -0
  2. package/dist/candidateRanking.js +55 -0
  3. package/dist/cjs/candidateRanking.js +61 -0
  4. package/dist/cjs/composition.js +62 -36
  5. package/dist/cjs/compositionNumbers.js +111 -0
  6. package/dist/cjs/compositionScenes.js +91 -38
  7. package/dist/cjs/compositionUseCases.js +145 -0
  8. package/dist/cjs/content.js +574 -120
  9. package/dist/cjs/contentBrief.js +82 -0
  10. package/dist/cjs/designBlueprint.js +94 -19
  11. package/dist/cjs/designSystem.js +536 -77
  12. package/dist/cjs/editorial.js +76 -20
  13. package/dist/cjs/fontCatalog.js +81 -23
  14. package/dist/cjs/formalCompositions.js +120 -0
  15. package/dist/cjs/index.js +13 -0
  16. package/dist/cjs/layoutContracts.js +57 -11
  17. package/dist/cjs/layouts.js +5 -92
  18. package/dist/cjs/nativeSocialParameters.js +145 -0
  19. package/dist/cjs/pagination.js +27 -7
  20. package/dist/cjs/parameterDefaults.js +20 -0
  21. package/dist/cjs/recipeParameters.js +304 -0
  22. package/dist/cjs/socialLayouts.js +127 -387
  23. package/dist/cjs/styleManifest.js +107 -0
  24. package/dist/cjs/text.js +12 -2
  25. package/dist/cjs/textPresentation.js +68 -0
  26. package/dist/composition.d.ts +4 -4
  27. package/dist/composition.js +62 -36
  28. package/dist/compositionNumbers.d.ts +4 -0
  29. package/dist/compositionNumbers.js +108 -0
  30. package/dist/compositionScenes.d.ts +2 -2
  31. package/dist/compositionScenes.js +91 -38
  32. package/dist/compositionUseCases.d.ts +1 -0
  33. package/dist/compositionUseCases.js +142 -0
  34. package/dist/content.d.ts +65 -20
  35. package/dist/content.js +575 -121
  36. package/dist/contentBrief.d.ts +16 -0
  37. package/dist/contentBrief.js +78 -0
  38. package/dist/designBlueprint.d.ts +4 -4
  39. package/dist/designBlueprint.js +95 -20
  40. package/dist/designSystem.d.ts +11 -7
  41. package/dist/designSystem.js +537 -79
  42. package/dist/editorial.d.ts +1 -1
  43. package/dist/editorial.js +77 -21
  44. package/dist/fontCatalog.d.ts +1 -1
  45. package/dist/fontCatalog.js +81 -23
  46. package/dist/formalCompositions.d.ts +26 -0
  47. package/dist/formalCompositions.js +116 -0
  48. package/dist/index.d.ts +10 -0
  49. package/dist/index.js +10 -0
  50. package/dist/layoutContracts.d.ts +3 -3
  51. package/dist/layoutContracts.js +58 -12
  52. package/dist/layouts.d.ts +2 -2
  53. package/dist/layouts.js +5 -92
  54. package/dist/nativeSocialParameters.d.ts +38 -0
  55. package/dist/nativeSocialParameters.js +139 -0
  56. package/dist/pagination.js +27 -7
  57. package/dist/parameterDefaults.d.ts +2 -0
  58. package/dist/parameterDefaults.js +17 -0
  59. package/dist/recipeParameters.d.ts +34 -0
  60. package/dist/recipeParameters.js +300 -0
  61. package/dist/socialLayouts.d.ts +40 -232
  62. package/dist/socialLayouts.js +127 -387
  63. package/dist/styleManifest.d.ts +20 -0
  64. package/dist/styleManifest.js +103 -0
  65. package/dist/text.js +12 -2
  66. package/dist/textPresentation.d.ts +29 -0
  67. package/dist/textPresentation.js +64 -0
  68. package/package.json +1 -1
@@ -0,0 +1,16 @@
1
+ import type { SourceDocument } from "./content.js";
2
+ /** Input provenance and adaptation permissions are independent of suitability scores. */
3
+ export interface ContentBrief {
4
+ version: 1;
5
+ originalInput: string;
6
+ /** Explicitly edited content; the initial submission remains immutable. */
7
+ revisedInput?: string;
8
+ revisedInputIllustrative?: boolean;
9
+ mode: "source-backed" | "creative";
10
+ language?: string;
11
+ creativeAllowed: boolean;
12
+ simulationAllowed: boolean;
13
+ sourceIds: string[];
14
+ }
15
+ export declare function createContentBrief(source: SourceDocument): ContentBrief;
16
+ export declare function validateContentBrief(value: unknown): ContentBrief;
@@ -0,0 +1,78 @@
1
+ export function createContentBrief(source) {
2
+ if (!source ||
3
+ source.version !== 1 ||
4
+ typeof source.text !== "string" ||
5
+ !source.text.trim() ||
6
+ !Array.isArray(source.segments) ||
7
+ !source.segments.length)
8
+ throw new Error("CONTENT_BRIEF_INVALID");
9
+ const provenance = source.provenance;
10
+ if (provenance &&
11
+ (!["creative-draft", "user-revision"].includes(provenance.kind) ||
12
+ typeof provenance.original !== "string" ||
13
+ !provenance.original.trim() ||
14
+ typeof provenance.disclosure !== "string" ||
15
+ !provenance.disclosure.trim() ||
16
+ (provenance.originalMode !== undefined &&
17
+ (provenance.kind !== "user-revision" ||
18
+ !["source-backed", "creative"].includes(provenance.originalMode))) ||
19
+ (provenance.illustrative !== undefined &&
20
+ (provenance.kind !== "user-revision" || typeof provenance.illustrative !== "boolean")) ||
21
+ (provenance.simulationAllowed !== undefined &&
22
+ typeof provenance.simulationAllowed !== "boolean") ||
23
+ (provenance.language !== undefined &&
24
+ (typeof provenance.language !== "string" ||
25
+ !/^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8}){0,3}$/.test(provenance.language)))))
26
+ throw new Error("CONTENT_BRIEF_INVALID");
27
+ const sourceIds = source.segments.map((segment) => segment.id);
28
+ if (sourceIds.some((id) => typeof id !== "string" || !id) ||
29
+ new Set(sourceIds).size !== sourceIds.length)
30
+ throw new Error("CONTENT_BRIEF_INVALID");
31
+ return validateContentBrief({
32
+ version: 1,
33
+ originalInput: provenance?.original || source.text,
34
+ ...(provenance?.kind === "user-revision" ? { revisedInput: source.text } : {}),
35
+ ...(provenance?.kind === "user-revision" && provenance.illustrative ? { revisedInputIllustrative: true } : {}),
36
+ mode: provenance?.kind === "user-revision" ? provenance.originalMode || "source-backed" : provenance ? "creative" : "source-backed",
37
+ ...(provenance?.language ? { language: provenance.language } : {}),
38
+ creativeAllowed: true,
39
+ simulationAllowed: true,
40
+ sourceIds,
41
+ });
42
+ }
43
+ export function validateContentBrief(value) {
44
+ const brief = value;
45
+ if (!brief ||
46
+ brief.version !== 1 ||
47
+ typeof brief.originalInput !== "string" ||
48
+ !brief.originalInput.trim() ||
49
+ brief.originalInput.length > 20000 ||
50
+ (brief.revisedInput !== undefined &&
51
+ (typeof brief.revisedInput !== "string" || !brief.revisedInput.trim() || brief.revisedInput.length > 20000)) ||
52
+ (brief.revisedInputIllustrative !== undefined &&
53
+ (typeof brief.revisedInputIllustrative !== "boolean" || brief.revisedInput === undefined)) ||
54
+ !["source-backed", "creative"].includes(brief.mode) ||
55
+ typeof brief.creativeAllowed !== "boolean" ||
56
+ typeof brief.simulationAllowed !== "boolean" ||
57
+ (brief.simulationAllowed && !brief.creativeAllowed) ||
58
+ (brief.language !== undefined &&
59
+ (typeof brief.language !== "string" ||
60
+ !/^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8}){0,3}$/.test(brief.language))) ||
61
+ !Array.isArray(brief.sourceIds) ||
62
+ !brief.sourceIds.length ||
63
+ brief.sourceIds.length > 1024 ||
64
+ new Set(brief.sourceIds).size !== brief.sourceIds.length ||
65
+ brief.sourceIds.some((id) => typeof id !== "string" || !id || id.length > 160))
66
+ throw new Error("CONTENT_BRIEF_INVALID");
67
+ return {
68
+ version: 1,
69
+ originalInput: brief.originalInput,
70
+ ...(brief.revisedInput !== undefined ? { revisedInput: brief.revisedInput } : {}),
71
+ ...(brief.revisedInputIllustrative !== undefined ? { revisedInputIllustrative: brief.revisedInputIllustrative } : {}),
72
+ mode: brief.mode,
73
+ ...(brief.language ? { language: brief.language } : {}),
74
+ creativeAllowed: brief.creativeAllowed,
75
+ simulationAllowed: brief.simulationAllowed,
76
+ sourceIds: [...brief.sourceIds],
77
+ };
78
+ }
@@ -1,4 +1,4 @@
1
- import { type ContentPage, type SemanticKind } from './content.js';
1
+ import { type ContentPage, type SemanticKind } from "./content.js";
2
2
  export interface DesignBlueprint {
3
3
  version: 2;
4
4
  id: string;
@@ -11,14 +11,14 @@ export interface DesignBlueprint {
11
11
  maxBlocks: number;
12
12
  };
13
13
  layout: {
14
- mode: 'stack' | 'split' | 'editorial';
14
+ mode: "stack" | "split" | "editorial";
15
15
  margin: number;
16
16
  gap: number;
17
17
  titleScale: number;
18
18
  bodyScale: number;
19
19
  columns: number;
20
- surface: 'none' | 'panels' | 'bands';
21
- accent: 'none' | 'rail' | 'rule';
20
+ surface: "none" | "panels" | "bands";
21
+ accent: "none" | "rail" | "rule";
22
22
  };
23
23
  }
24
24
  export declare const DESIGN_SAMPLE_LOCALES: readonly ["en-US", "zh-CH", "ja-JP", "de-DE", "fr-FR", "es-ES", "pt-PT"];
@@ -1,29 +1,104 @@
1
- import { contentBlockText } from './content.js';
2
- export const DESIGN_SAMPLE_LOCALES = ['en-US', 'zh-CH', 'ja-JP', 'de-DE', 'fr-FR', 'es-ES', 'pt-PT'];
1
+ import { contentBlockText, } from "./content.js";
2
+ export const DESIGN_SAMPLE_LOCALES = [
3
+ "en-US",
4
+ "zh-CH",
5
+ "ja-JP",
6
+ "de-DE",
7
+ "fr-FR",
8
+ "es-ES",
9
+ "pt-PT",
10
+ ];
3
11
  export function validateDesignBlueprint(raw) {
4
12
  const v = raw;
5
- if (!v || v.version !== 2 || typeof v.id !== 'string' || !/^[a-z][a-z0-9-]{0,79}$/.test(v.id))
6
- throw new Error('DESIGN_BLUEPRINT_ID');
7
- const kinds = ['paragraph', 'steps', 'features', 'comparison', 'code', 'parameters', 'quote', 'chart', 'image'];
8
- if (!Array.isArray(v.kinds) || !v.kinds.length || v.kinds.length > 9 || v.kinds.some(k => !kinds.includes(k)))
9
- throw new Error('DESIGN_BLUEPRINT_KINDS');
10
- if (!v.labels || typeof v.labels !== 'object' || Array.isArray(v.labels) || typeof v.labels.en !== 'string' || !v.labels.en.trim() || Object.entries(v.labels).some(([key, value]) => !/^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/.test(key) || typeof value !== 'string' || !value.trim() || value.length > 120))
11
- throw new Error('DESIGN_BLUEPRINT_LABELS');
12
- if (!Array.isArray(v.ratios) || !v.ratios.length || v.ratios.length > 8 || v.ratios.some(n => !Number.isFinite(n) || n < .25 || n > 4))
13
- throw new Error('DESIGN_BLUEPRINT_RATIOS');
14
- const number = (n, min, max) => { if (typeof n !== 'number' || !Number.isFinite(n) || n < min || n > max)
15
- throw new Error('DESIGN_BLUEPRINT_RANGE'); return n; };
13
+ if (!v ||
14
+ v.version !== 2 ||
15
+ typeof v.id !== "string" ||
16
+ !/^[a-z][a-z0-9-]{0,79}$/.test(v.id))
17
+ throw new Error("DESIGN_BLUEPRINT_ID");
18
+ const kinds = [
19
+ "paragraph",
20
+ "steps",
21
+ "features",
22
+ "comparison",
23
+ "code",
24
+ "parameters",
25
+ "quote",
26
+ "chart",
27
+ "image",
28
+ ];
29
+ if (!Array.isArray(v.kinds) ||
30
+ !v.kinds.length ||
31
+ v.kinds.length > 9 ||
32
+ v.kinds.some((k) => !kinds.includes(k)))
33
+ throw new Error("DESIGN_BLUEPRINT_KINDS");
34
+ if (!v.labels ||
35
+ typeof v.labels !== "object" ||
36
+ Array.isArray(v.labels) ||
37
+ typeof v.labels.en !== "string" ||
38
+ !v.labels.en.trim() ||
39
+ Object.entries(v.labels).some(([key, value]) => !/^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/.test(key) ||
40
+ typeof value !== "string" ||
41
+ !value.trim() ||
42
+ value.length > 120))
43
+ throw new Error("DESIGN_BLUEPRINT_LABELS");
44
+ if (!Array.isArray(v.ratios) ||
45
+ !v.ratios.length ||
46
+ v.ratios.length > 8 ||
47
+ v.ratios.some((n) => !Number.isFinite(n) || n < 0.25 || n > 4))
48
+ throw new Error("DESIGN_BLUEPRINT_RATIOS");
49
+ const number = (n, min, max) => {
50
+ if (typeof n !== "number" || !Number.isFinite(n) || n < min || n > max)
51
+ throw new Error("DESIGN_BLUEPRINT_RANGE");
52
+ return n;
53
+ };
16
54
  const c = v.capacity, l = v.layout;
17
55
  if (!c || !l)
18
- throw new Error('DESIGN_BLUEPRINT_MISSING');
19
- if (!['stack', 'split', 'editorial'].includes(l.mode) || !['none', 'panels', 'bands'].includes(l.surface) || !['none', 'rail', 'rule'].includes(l.accent))
20
- throw new Error('DESIGN_BLUEPRINT_LAYOUT');
56
+ throw new Error("DESIGN_BLUEPRINT_MISSING");
57
+ if (!["stack", "split", "editorial"].includes(l.mode) ||
58
+ !["none", "panels", "bands"].includes(l.surface) ||
59
+ !["none", "rail", "rule"].includes(l.accent))
60
+ throw new Error("DESIGN_BLUEPRINT_LAYOUT");
21
61
  const maxEntries = number(c.maxEntries, 1, 20), maxBlocks = number(c.maxBlocks, 1, 8), columns = number(l.columns, 1, 4);
22
62
  if (![maxEntries, maxBlocks, columns].every(Number.isInteger))
23
- throw new Error('DESIGN_BLUEPRINT_INTEGER');
24
- return { version: 2, id: v.id, labels: { ...v.labels }, kinds: [...new Set(v.kinds)], ratios: [...new Set(v.ratios)], capacity: { maxCharacters: number(c.maxCharacters, 40, 20000), maxEntries, maxBlocks }, layout: { mode: l.mode, margin: number(l.margin, 32, 80), gap: number(l.gap, 12, 40), titleScale: number(l.titleScale, .8, 1.15), bodyScale: number(l.bodyScale, .9, 1.15), columns, surface: l.surface, accent: l.accent } };
63
+ throw new Error("DESIGN_BLUEPRINT_INTEGER");
64
+ return {
65
+ version: 2,
66
+ id: v.id,
67
+ labels: { ...v.labels },
68
+ kinds: [...new Set(v.kinds)],
69
+ ratios: [...new Set(v.ratios)],
70
+ capacity: {
71
+ maxCharacters: number(c.maxCharacters, 40, 20000),
72
+ maxEntries,
73
+ maxBlocks,
74
+ },
75
+ layout: {
76
+ mode: l.mode,
77
+ margin: number(l.margin, 32, 80),
78
+ gap: number(l.gap, 12, 40),
79
+ titleScale: number(l.titleScale, 0.8, 1.15),
80
+ bodyScale: number(l.bodyScale, 0.9, 1.15),
81
+ columns,
82
+ surface: l.surface,
83
+ accent: l.accent,
84
+ },
85
+ };
25
86
  }
26
87
  export function blueprintFitsContent(blueprint, page, ratio) {
27
- const entries = page.blocks.reduce((sum, b) => sum + ('entries' in b ? b.entries.length : 'columns' in b ? b.columns.length : 'rows' in b ? b.rows.length : 'values' in b ? b.values.length : 0), 0);
28
- return blueprint.ratios.some(r => Math.abs(r - ratio) < .001) && page.blocks.length <= blueprint.capacity.maxBlocks && page.blocks.every(b => blueprint.kinds.includes(b.kind)) && page.blocks.flatMap(contentBlockText).join('').length <= blueprint.capacity.maxCharacters && entries <= blueprint.capacity.maxEntries;
88
+ const entries = page.blocks.reduce((sum, b) => sum +
89
+ ("entries" in b
90
+ ? b.entries.length
91
+ : "columns" in b
92
+ ? b.columns.length
93
+ : "rows" in b
94
+ ? b.rows.length
95
+ : "values" in b
96
+ ? b.values.length
97
+ : 0), 0);
98
+ return (blueprint.ratios.some((r) => Math.abs(r - ratio) < 0.001) &&
99
+ page.blocks.length <= blueprint.capacity.maxBlocks &&
100
+ page.blocks.every((b) => blueprint.kinds.includes(b.kind)) &&
101
+ page.blocks.flatMap(contentBlockText).join("").length <=
102
+ blueprint.capacity.maxCharacters &&
103
+ entries <= blueprint.capacity.maxEntries);
29
104
  }
@@ -1,4 +1,4 @@
1
- import { type ContentPage, type SemanticKind } from './content.js';
1
+ import { type ContentPage, type SemanticKind } from "./content.js";
2
2
  export interface DesignTheme {
3
3
  id: string;
4
4
  palette: {
@@ -18,7 +18,7 @@ export interface DesignTheme {
18
18
  geometry: {
19
19
  radius: number;
20
20
  spacing: number;
21
- rule: 'none' | 'hairline' | 'accent';
21
+ rule: "none" | "hairline" | "accent";
22
22
  };
23
23
  }
24
24
  /** Complete, deterministic token sets; decorative geometry belongs to individual compositions. */
@@ -26,8 +26,8 @@ export declare const DESIGN_THEMES: readonly DesignTheme[];
26
26
  export declare function designTheme(id: string): DesignTheme;
27
27
  export interface DesignRecipe {
28
28
  id: string;
29
- renderer: 'catalog' | 'semantic';
30
- kind: 'presentation' | 'social';
29
+ renderer: "catalog" | "semantic";
30
+ kind: "presentation" | "social";
31
31
  family: string;
32
32
  accepts: readonly SemanticKind[];
33
33
  minEntries: number;
@@ -35,12 +35,16 @@ export interface DesignRecipe {
35
35
  requiresImage: boolean;
36
36
  /** Unmodelled domain-specific catalogs remain manual-only until their required evidence is expressible. */
37
37
  automatic?: boolean;
38
+ scenes?: readonly string[];
39
+ manualReason?: string;
38
40
  }
39
- /** Existing authored catalogs remain first-class candidates, rather than being discarded. */
40
- export declare const DESIGN_RECIPES: readonly DesignRecipe[];
41
+ export declare const MANUAL_COMPOSITION_REASONS: Readonly<Record<string, string>>;
42
+ /** Stable aliases keep saved documents readable while excluding duplicate candidates. */
43
+ export declare function canonicalRecipeId(id: string, kind: DesignRecipe["kind"]): string;
44
+ export declare const DESIGN_RECIPES: DesignRecipe[];
41
45
  export declare function pageEntryCount(page: ContentPage): number;
42
46
  export interface CandidateContext {
43
- kind: DesignRecipe['kind'];
47
+ kind: DesignRecipe["kind"];
44
48
  ratio: number;
45
49
  previousFamilies?: readonly string[];
46
50
  excluded?: readonly string[];