@viewscript/renderer 0.1.0-202605140639
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/dist/ast/types.d.ts +403 -0
- package/dist/ast/types.js +33 -0
- package/dist/compiler/chunk-splitter.d.ts +98 -0
- package/dist/compiler/chunk-splitter.js +361 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +17 -0
- package/dist/rasterizer/__tests__/error-distribution.test.d.ts +7 -0
- package/dist/rasterizer/__tests__/error-distribution.test.js +322 -0
- package/dist/rasterizer/canvas-mapper.d.ts +280 -0
- package/dist/rasterizer/canvas-mapper.js +414 -0
- package/dist/rasterizer/error-distribution.d.ts +143 -0
- package/dist/rasterizer/error-distribution.js +231 -0
- package/dist/rasterizer/gradient-mapper.d.ts +223 -0
- package/dist/rasterizer/gradient-mapper.js +352 -0
- package/dist/rasterizer/topology-rounding.d.ts +151 -0
- package/dist/rasterizer/topology-rounding.js +347 -0
- package/dist/runtime/__tests__/event-backpressure.test.d.ts +10 -0
- package/dist/runtime/__tests__/event-backpressure.test.js +190 -0
- package/dist/runtime/event-backpressure.d.ts +393 -0
- package/dist/runtime/event-backpressure.js +458 -0
- package/dist/runtime/render-loop.d.ts +277 -0
- package/dist/runtime/render-loop.js +435 -0
- package/dist/runtime/wasm-resource-manager.d.ts +122 -0
- package/dist/runtime/wasm-resource-manager.js +253 -0
- package/dist/runtime/wgpu-renderer-adapter.d.ts +168 -0
- package/dist/runtime/wgpu-renderer-adapter.js +230 -0
- package/dist/semantic/__tests__/semantic-translator.test.d.ts +4 -0
- package/dist/semantic/__tests__/semantic-translator.test.js +203 -0
- package/dist/semantic/semantic-translator.d.ts +229 -0
- package/dist/semantic/semantic-translator.js +398 -0
- package/package.json +28 -0
- package/playwright-report/data/0bafe4e0863f0e244bba68a838f73241f8f2efaa.md +226 -0
- package/playwright-report/data/9281aca8abfb06c6cecb35d5ddd13d61f8c752d8.md +226 -0
- package/playwright-report/index.html +90 -0
- package/playwright.config.ts +160 -0
- package/screenshot-chrome.png +0 -0
- package/screenshots/visual-demo-verification.png +0 -0
- package/screenshots/visual-demo.png +0 -0
- package/src/ast/types.ts +473 -0
- package/src/compiler/chunk-splitter.ts +534 -0
- package/src/index.ts +62 -0
- package/src/rasterizer/__tests__/error-distribution.test.ts +382 -0
- package/src/rasterizer/canvas-mapper.ts +677 -0
- package/src/rasterizer/error-distribution.ts +344 -0
- package/src/rasterizer/gradient-mapper.ts +563 -0
- package/src/rasterizer/topology-rounding.ts +499 -0
- package/src/runtime/__tests__/event-backpressure.test.ts +254 -0
- package/src/runtime/event-backpressure.ts +622 -0
- package/src/runtime/render-loop.ts +660 -0
- package/src/runtime/wasm-resource-manager.ts +349 -0
- package/src/runtime/wgpu-renderer-adapter.ts +318 -0
- package/src/semantic/__tests__/semantic-translator.test.ts +263 -0
- package/src/semantic/semantic-translator.ts +637 -0
- package/test-results/.last-run.json +4 -0
- package/tests/e2e/async-race.spec.ts +612 -0
- package/tests/e2e/bilayer-sync.spec.ts +405 -0
- package/tests/e2e/failures/.gitkeep +0 -0
- package/tests/e2e/fullstack.spec.ts +681 -0
- package/tests/e2e/g1-continuity.spec.ts +703 -0
- package/tests/e2e/golden/.gitkeep +0 -0
- package/tests/e2e/golden/conic-color-wheel.raw +0 -0
- package/tests/e2e/golden/conic-color-wheel.sha256 +1 -0
- package/tests/e2e/golden/conic-rotated.raw +0 -0
- package/tests/e2e/golden/conic-rotated.sha256 +1 -0
- package/tests/e2e/golden/linear-45deg.raw +0 -0
- package/tests/e2e/golden/linear-45deg.sha256 +1 -0
- package/tests/e2e/golden/linear-horizontal.raw +0 -0
- package/tests/e2e/golden/linear-horizontal.sha256 +1 -0
- package/tests/e2e/golden/linear-multi-stop.raw +0 -0
- package/tests/e2e/golden/linear-multi-stop.sha256 +1 -0
- package/tests/e2e/golden/radial-circle-center.raw +0 -0
- package/tests/e2e/golden/radial-circle-center.sha256 +1 -0
- package/tests/e2e/golden/radial-offset.raw +0 -0
- package/tests/e2e/golden/radial-offset.sha256 +1 -0
- package/tests/e2e/golden/tile-mirror.raw +0 -0
- package/tests/e2e/golden/tile-mirror.sha256 +1 -0
- package/tests/e2e/golden/tile-repeat.raw +0 -0
- package/tests/e2e/golden/tile-repeat.sha256 +1 -0
- package/tests/e2e/gradient-animation.spec.ts +606 -0
- package/tests/e2e/memory-stability.spec.ts +396 -0
- package/tests/e2e/path-topology.spec.ts +674 -0
- package/tests/e2e/performance-profile.spec.ts +501 -0
- package/tests/e2e/screenshot.spec.ts +60 -0
- package/tests/e2e/test-harness.html +1005 -0
- package/tests/e2e/text-layout.spec.ts +451 -0
- package/tests/e2e/visual-demo.html +340 -0
- package/tests/e2e/visual-regression.spec.ts +335 -0
- package/tsconfig.json +12 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for SemanticTranslator (Phase 7: Task 20)
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect } from 'vitest';
|
|
5
|
+
import { SemanticTranslator, createEntityRegistry, createEmptyRegistry, } from '../semantic-translator';
|
|
6
|
+
describe('SemanticTranslator', () => {
|
|
7
|
+
describe('parseVarId', () => {
|
|
8
|
+
it('should parse valid VarId keys', () => {
|
|
9
|
+
const translator = new SemanticTranslator(createEmptyRegistry());
|
|
10
|
+
expect(translator.parseVarId('1:x')).toEqual({ entityId: 1, component: 'x' });
|
|
11
|
+
expect(translator.parseVarId('42:y')).toEqual({ entityId: 42, component: 'y' });
|
|
12
|
+
expect(translator.parseVarId('100:value')).toEqual({ entityId: 100, component: 'value' });
|
|
13
|
+
expect(translator.parseVarId('5:r')).toEqual({ entityId: 5, component: 'r' });
|
|
14
|
+
expect(translator.parseVarId('5:alpha')).toEqual({ entityId: 5, component: 'alpha' });
|
|
15
|
+
});
|
|
16
|
+
it('should return null for invalid keys', () => {
|
|
17
|
+
const translator = new SemanticTranslator(createEmptyRegistry());
|
|
18
|
+
expect(translator.parseVarId('')).toBeNull();
|
|
19
|
+
expect(translator.parseVarId('invalid')).toBeNull();
|
|
20
|
+
expect(translator.parseVarId(':x')).toBeNull();
|
|
21
|
+
expect(translator.parseVarId('1:')).toBeNull();
|
|
22
|
+
expect(translator.parseVarId('1:unknown_component')).toBeNull();
|
|
23
|
+
expect(translator.parseVarId('abc:x')).toBeNull();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
describe('parseRationalToFloat', () => {
|
|
27
|
+
it('should parse rational strings', () => {
|
|
28
|
+
const translator = new SemanticTranslator(createEmptyRegistry());
|
|
29
|
+
expect(translator.parseRationalToFloat('100/1')).toBe(100);
|
|
30
|
+
expect(translator.parseRationalToFloat('1/2')).toBe(0.5);
|
|
31
|
+
expect(translator.parseRationalToFloat('100')).toBe(100);
|
|
32
|
+
expect(translator.parseRationalToFloat('-50/1')).toBe(-50);
|
|
33
|
+
expect(translator.parseRationalToFloat('1/3')).toBeCloseTo(0.333, 2);
|
|
34
|
+
});
|
|
35
|
+
it('should handle zero denominator', () => {
|
|
36
|
+
const translator = new SemanticTranslator(createEmptyRegistry());
|
|
37
|
+
expect(translator.parseRationalToFloat('1/0')).toBeNaN();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('translateSolution', () => {
|
|
41
|
+
it('should translate a simple point solution', () => {
|
|
42
|
+
const registry = createEntityRegistry([
|
|
43
|
+
{ entityId: 1, type: 'point', name: 'P1' },
|
|
44
|
+
]);
|
|
45
|
+
const translator = new SemanticTranslator(registry);
|
|
46
|
+
const rawSolution = new Map([
|
|
47
|
+
['1:x', '100/1'],
|
|
48
|
+
['1:y', '200/1'],
|
|
49
|
+
]);
|
|
50
|
+
const result = translator.translateSolution(rawSolution, 0);
|
|
51
|
+
expect(result.solutionIndex).toBe(0);
|
|
52
|
+
expect(result.entities).toHaveLength(1);
|
|
53
|
+
expect(result.entities[0].entityId).toBe(1);
|
|
54
|
+
expect(result.entities[0].type).toBe('point');
|
|
55
|
+
expect(result.entities[0].coordinates?.x).toBe(100);
|
|
56
|
+
expect(result.entities[0].coordinates?.y).toBe(200);
|
|
57
|
+
expect(result.entities[0].description).toContain('P1');
|
|
58
|
+
expect(result.entities[0].description).toContain('100');
|
|
59
|
+
expect(result.entities[0].description).toContain('200');
|
|
60
|
+
});
|
|
61
|
+
it('should translate multiple entities', () => {
|
|
62
|
+
const registry = createEntityRegistry([
|
|
63
|
+
{ entityId: 1, type: 'point', name: 'Start' },
|
|
64
|
+
{ entityId: 2, type: 'point', name: 'End' },
|
|
65
|
+
{ entityId: 3, type: 'control_point', name: 'CP1' },
|
|
66
|
+
]);
|
|
67
|
+
const translator = new SemanticTranslator(registry);
|
|
68
|
+
const rawSolution = new Map([
|
|
69
|
+
['1:x', '0/1'],
|
|
70
|
+
['1:y', '0/1'],
|
|
71
|
+
['2:x', '100/1'],
|
|
72
|
+
['2:y', '0/1'],
|
|
73
|
+
['3:x', '50/1'],
|
|
74
|
+
['3:y', '50/1'],
|
|
75
|
+
]);
|
|
76
|
+
const result = translator.translateSolution(rawSolution, 0);
|
|
77
|
+
expect(result.entities).toHaveLength(3);
|
|
78
|
+
expect(result.summary).toContain('3 entities');
|
|
79
|
+
});
|
|
80
|
+
it('should translate color stop entities', () => {
|
|
81
|
+
const registry = createEntityRegistry([
|
|
82
|
+
{ entityId: 10, type: 'color_stop', name: 'Stop1' },
|
|
83
|
+
]);
|
|
84
|
+
const translator = new SemanticTranslator(registry);
|
|
85
|
+
const rawSolution = new Map([
|
|
86
|
+
['10:r', '255/1'],
|
|
87
|
+
['10:g', '128/1'],
|
|
88
|
+
['10:b', '0/1'],
|
|
89
|
+
['10:alpha', '1/1'],
|
|
90
|
+
['10:position', '1/2'],
|
|
91
|
+
]);
|
|
92
|
+
const result = translator.translateSolution(rawSolution, 0);
|
|
93
|
+
expect(result.entities).toHaveLength(1);
|
|
94
|
+
expect(result.entities[0].type).toBe('color_stop');
|
|
95
|
+
expect(result.entities[0].color?.r).toBe(255);
|
|
96
|
+
expect(result.entities[0].color?.g).toBe(128);
|
|
97
|
+
expect(result.entities[0].color?.b).toBe(0);
|
|
98
|
+
expect(result.entities[0].color?.position).toBe(0.5);
|
|
99
|
+
expect(result.entities[0].description).toContain('50%');
|
|
100
|
+
expect(result.entities[0].description).toContain('rgb(255, 128, 0)');
|
|
101
|
+
});
|
|
102
|
+
it('should handle unknown entity types', () => {
|
|
103
|
+
const translator = new SemanticTranslator(createEmptyRegistry());
|
|
104
|
+
const rawSolution = new Map([
|
|
105
|
+
['99:x', '50/1'],
|
|
106
|
+
['99:y', '75/1'],
|
|
107
|
+
]);
|
|
108
|
+
const result = translator.translateSolution(rawSolution, 0);
|
|
109
|
+
expect(result.entities).toHaveLength(1);
|
|
110
|
+
expect(result.entities[0].type).toBe('unknown');
|
|
111
|
+
expect(result.entities[0].coordinates?.x).toBe(50);
|
|
112
|
+
});
|
|
113
|
+
it('should detect horizontal alignment relationships', () => {
|
|
114
|
+
const registry = createEntityRegistry([
|
|
115
|
+
{ entityId: 1, type: 'point' },
|
|
116
|
+
{ entityId: 2, type: 'point' },
|
|
117
|
+
{ entityId: 3, type: 'point' },
|
|
118
|
+
]);
|
|
119
|
+
const translator = new SemanticTranslator(registry);
|
|
120
|
+
// Three points on the same horizontal line (y=100)
|
|
121
|
+
const rawSolution = new Map([
|
|
122
|
+
['1:x', '0/1'],
|
|
123
|
+
['1:y', '100/1'],
|
|
124
|
+
['2:x', '50/1'],
|
|
125
|
+
['2:y', '100/1'],
|
|
126
|
+
['3:x', '100/1'],
|
|
127
|
+
['3:y', '100/1'],
|
|
128
|
+
]);
|
|
129
|
+
const result = translator.translateSolution(rawSolution, 0);
|
|
130
|
+
expect(result.relationships.length).toBeGreaterThan(0);
|
|
131
|
+
const alignment = result.relationships.find(r => r.type === 'alignment');
|
|
132
|
+
expect(alignment).toBeDefined();
|
|
133
|
+
expect(alignment?.description).toContain('horizontally aligned');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe('compareSolutions', () => {
|
|
137
|
+
it('should detect identical solutions', () => {
|
|
138
|
+
const registry = createEntityRegistry([
|
|
139
|
+
{ entityId: 1, type: 'point', name: 'P1' },
|
|
140
|
+
]);
|
|
141
|
+
const translator = new SemanticTranslator(registry);
|
|
142
|
+
const rawSolution = new Map([
|
|
143
|
+
['1:x', '100/1'],
|
|
144
|
+
['1:y', '200/1'],
|
|
145
|
+
]);
|
|
146
|
+
const solution1 = translator.translateSolution(rawSolution, 0);
|
|
147
|
+
const solution2 = translator.translateSolution(rawSolution, 1);
|
|
148
|
+
const diff = translator.compareSolutions(solution1, solution2);
|
|
149
|
+
expect(diff.differingEntities).toHaveLength(0);
|
|
150
|
+
expect(diff.summary).toContain('identical');
|
|
151
|
+
});
|
|
152
|
+
it('should detect differing solutions', () => {
|
|
153
|
+
const registry = createEntityRegistry([
|
|
154
|
+
{ entityId: 1, type: 'point', name: 'P1' },
|
|
155
|
+
]);
|
|
156
|
+
const translator = new SemanticTranslator(registry);
|
|
157
|
+
const solution1 = translator.translateSolution(new Map([['1:x', '100/1'], ['1:y', '200/1']]), 0);
|
|
158
|
+
const solution2 = translator.translateSolution(new Map([['1:x', '150/1'], ['1:y', '250/1']]), 1);
|
|
159
|
+
const diff = translator.compareSolutions(solution1, solution2);
|
|
160
|
+
expect(diff.differingEntities).toHaveLength(1);
|
|
161
|
+
expect(diff.differingEntities[0].entityId).toBe(1);
|
|
162
|
+
expect(diff.summary).toContain('1 entities differ');
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
describe('translateMultipleSolutions', () => {
|
|
166
|
+
it('should translate and compare multiple solutions', () => {
|
|
167
|
+
const registry = createEntityRegistry([
|
|
168
|
+
{ entityId: 1, type: 'point', name: 'P1' },
|
|
169
|
+
]);
|
|
170
|
+
const translator = new SemanticTranslator(registry);
|
|
171
|
+
const rawSolutions = [
|
|
172
|
+
new Map([['1:x', '100/1'], ['1:y', '0/1']]),
|
|
173
|
+
new Map([['1:x', '-100/1'], ['1:y', '0/1']]),
|
|
174
|
+
];
|
|
175
|
+
const result = translator.translateMultipleSolutions(rawSolutions);
|
|
176
|
+
expect(result.solutions).toHaveLength(2);
|
|
177
|
+
expect(result.comparison).toContain('2 solutions found');
|
|
178
|
+
expect(result.comparison).toContain('differ');
|
|
179
|
+
});
|
|
180
|
+
it('should handle single solution', () => {
|
|
181
|
+
const translator = new SemanticTranslator(createEmptyRegistry());
|
|
182
|
+
const rawSolutions = [
|
|
183
|
+
new Map([['1:x', '100/1']]),
|
|
184
|
+
];
|
|
185
|
+
const result = translator.translateMultipleSolutions(rawSolutions);
|
|
186
|
+
expect(result.solutions).toHaveLength(1);
|
|
187
|
+
expect(result.comparison).toContain('Only one solution');
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
describe('createEntityRegistry', () => {
|
|
192
|
+
it('should create a working registry', () => {
|
|
193
|
+
const entities = [
|
|
194
|
+
{ entityId: 1, type: 'point', name: 'P1' },
|
|
195
|
+
{ entityId: 2, type: 'rect', name: 'R1' },
|
|
196
|
+
];
|
|
197
|
+
const registry = createEntityRegistry(entities);
|
|
198
|
+
expect(registry.get(1)?.type).toBe('point');
|
|
199
|
+
expect(registry.get(2)?.name).toBe('R1');
|
|
200
|
+
expect(registry.get(999)).toBeUndefined();
|
|
201
|
+
expect(registry.getAll()).toHaveLength(2);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic Translator for P/Q Dimension Bridge (Phase 7: Task 20)
|
|
3
|
+
*
|
|
4
|
+
* This module converts raw solver output (VarId -> Rational maps) into
|
|
5
|
+
* entity-level coordinate descriptions suitable for LLM comprehension.
|
|
6
|
+
*
|
|
7
|
+
* ## Purpose
|
|
8
|
+
*
|
|
9
|
+
* The P-dimension solver produces solutions in the form:
|
|
10
|
+
* { "1:x": "100/1", "1:y": "200/1", "2:x": "300/1", ... }
|
|
11
|
+
*
|
|
12
|
+
* This is not LLM-friendly. The SemanticTranslator converts this to:
|
|
13
|
+
* {
|
|
14
|
+
* entities: [
|
|
15
|
+
* { entityId: 1, coordinates: { x: 100, y: 200 }, description: "Point at (100, 200)" },
|
|
16
|
+
* { entityId: 2, coordinates: { x: 300, y: 150 }, description: "Point at (300, 150)" }
|
|
17
|
+
* ],
|
|
18
|
+
* relationships: [
|
|
19
|
+
* { type: "distance", from: 1, to: 2, value: "~212 units" }
|
|
20
|
+
* ]
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* ## Axiom 2: Ouroboros Binding
|
|
24
|
+
*
|
|
25
|
+
* This module sits at the P/Q dimension boundary. It translates deterministic
|
|
26
|
+
* solver output (P) into natural language suitable for non-deterministic
|
|
27
|
+
* oracles (Q/LLM).
|
|
28
|
+
*
|
|
29
|
+
* ## Usage
|
|
30
|
+
*
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const translator = new SemanticTranslator(entityRegistry);
|
|
33
|
+
* const semanticSolution = translator.translateSolution(rawSolution);
|
|
34
|
+
* const diff = translator.compareSolutions(solution1, solution2);
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
import type { EntityId } from '../ast/types';
|
|
38
|
+
/**
|
|
39
|
+
* Raw solution from solver: "entity_id:component" -> "numerator/denominator"
|
|
40
|
+
*/
|
|
41
|
+
export type RawSolution = Map<string, string>;
|
|
42
|
+
/**
|
|
43
|
+
* Parsed VarId key.
|
|
44
|
+
*/
|
|
45
|
+
export interface ParsedVarId {
|
|
46
|
+
entityId: EntityId;
|
|
47
|
+
component: VectorComponent;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Vector components matching Rust VectorComponent enum.
|
|
51
|
+
*/
|
|
52
|
+
export type VectorComponent = 'x' | 'y' | 'z' | 't' | 'value' | 'r' | 'g' | 'b' | 'alpha' | 'position';
|
|
53
|
+
/**
|
|
54
|
+
* Entity type classification for semantic descriptions.
|
|
55
|
+
*/
|
|
56
|
+
export type EntityType = 'point' | 'control_point' | 'rect' | 'circle' | 'text' | 'color_stop' | 'scalar' | 'unknown';
|
|
57
|
+
/**
|
|
58
|
+
* Metadata about an entity (provided by the constraint graph).
|
|
59
|
+
*/
|
|
60
|
+
export interface EntityMetadata {
|
|
61
|
+
entityId: EntityId;
|
|
62
|
+
type: EntityType;
|
|
63
|
+
name?: string;
|
|
64
|
+
parentId?: EntityId;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Registry of entity metadata for semantic translation.
|
|
68
|
+
*/
|
|
69
|
+
export interface EntityRegistry {
|
|
70
|
+
get(entityId: EntityId): EntityMetadata | undefined;
|
|
71
|
+
getAll(): EntityMetadata[];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Coordinates for a spatial entity.
|
|
75
|
+
*/
|
|
76
|
+
export interface EntityCoordinates {
|
|
77
|
+
x?: number;
|
|
78
|
+
y?: number;
|
|
79
|
+
z?: number;
|
|
80
|
+
t?: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Color values for a color stop entity.
|
|
84
|
+
*/
|
|
85
|
+
export interface EntityColor {
|
|
86
|
+
r?: number;
|
|
87
|
+
g?: number;
|
|
88
|
+
b?: number;
|
|
89
|
+
alpha?: number;
|
|
90
|
+
position?: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Scalar value for value-only entities.
|
|
94
|
+
*/
|
|
95
|
+
export interface EntityScalar {
|
|
96
|
+
value?: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* A semantic entity description.
|
|
100
|
+
*/
|
|
101
|
+
export interface SemanticEntity {
|
|
102
|
+
entityId: EntityId;
|
|
103
|
+
type: EntityType;
|
|
104
|
+
name?: string;
|
|
105
|
+
/** Spatial coordinates (for points, rects, etc.) */
|
|
106
|
+
coordinates?: EntityCoordinates;
|
|
107
|
+
/** Color values (for color stops) */
|
|
108
|
+
color?: EntityColor;
|
|
109
|
+
/** Scalar value (for radius, angle, etc.) */
|
|
110
|
+
scalar?: EntityScalar;
|
|
111
|
+
/** Human-readable description for LLM */
|
|
112
|
+
description: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Relationship between entities derived from geometry.
|
|
116
|
+
*/
|
|
117
|
+
export interface SemanticRelationship {
|
|
118
|
+
type: 'distance' | 'alignment' | 'containment' | 'collinear';
|
|
119
|
+
fromEntityId: EntityId;
|
|
120
|
+
toEntityId: EntityId;
|
|
121
|
+
description: string;
|
|
122
|
+
value?: string;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Complete semantic solution.
|
|
126
|
+
*/
|
|
127
|
+
export interface SemanticSolution {
|
|
128
|
+
/** Unique identifier for this solution (index in MultipleSolutions) */
|
|
129
|
+
solutionIndex: number;
|
|
130
|
+
/** All entities with resolved coordinates */
|
|
131
|
+
entities: SemanticEntity[];
|
|
132
|
+
/** Derived relationships between entities */
|
|
133
|
+
relationships: SemanticRelationship[];
|
|
134
|
+
/** High-level summary for LLM consumption */
|
|
135
|
+
summary: string;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Difference between two solutions.
|
|
139
|
+
*/
|
|
140
|
+
export interface SolutionDiff {
|
|
141
|
+
/** Entities that differ between solutions */
|
|
142
|
+
differingEntities: EntityDiff[];
|
|
143
|
+
/** Human-readable diff summary */
|
|
144
|
+
summary: string;
|
|
145
|
+
}
|
|
146
|
+
export interface EntityDiff {
|
|
147
|
+
entityId: EntityId;
|
|
148
|
+
name?: string;
|
|
149
|
+
solution1: SemanticEntity;
|
|
150
|
+
solution2: SemanticEntity;
|
|
151
|
+
description: string;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Translates raw solver output to LLM-friendly semantic descriptions.
|
|
155
|
+
*/
|
|
156
|
+
export declare class SemanticTranslator {
|
|
157
|
+
private readonly registry;
|
|
158
|
+
constructor(registry: EntityRegistry);
|
|
159
|
+
/**
|
|
160
|
+
* Parse a raw VarId key (e.g., "5:x") into its components.
|
|
161
|
+
*/
|
|
162
|
+
parseVarId(key: string): ParsedVarId | null;
|
|
163
|
+
/**
|
|
164
|
+
* Parse a rational string (e.g., "100/1" or "100") to a number.
|
|
165
|
+
*
|
|
166
|
+
* WARNING: This converts P-dimension exact rationals to Q-dimension floats.
|
|
167
|
+
* Only use for display/LLM consumption, NEVER for constraint solving.
|
|
168
|
+
*/
|
|
169
|
+
parseRationalToFloat(value: string): number;
|
|
170
|
+
/**
|
|
171
|
+
* Translate a raw solution to a semantic solution.
|
|
172
|
+
*/
|
|
173
|
+
translateSolution(rawSolution: RawSolution, solutionIndex?: number): SemanticSolution;
|
|
174
|
+
/**
|
|
175
|
+
* Build a semantic entity from raw components.
|
|
176
|
+
*/
|
|
177
|
+
private buildSemanticEntity;
|
|
178
|
+
/**
|
|
179
|
+
* Generate description for a spatial entity.
|
|
180
|
+
*/
|
|
181
|
+
private describeSpatialEntity;
|
|
182
|
+
/**
|
|
183
|
+
* Generate description for a color stop.
|
|
184
|
+
*/
|
|
185
|
+
private describeColorStop;
|
|
186
|
+
/**
|
|
187
|
+
* Generate description for a scalar entity.
|
|
188
|
+
*/
|
|
189
|
+
private describeScalar;
|
|
190
|
+
/**
|
|
191
|
+
* Format a coordinate value for display.
|
|
192
|
+
*/
|
|
193
|
+
private formatCoord;
|
|
194
|
+
/**
|
|
195
|
+
* Derive geometric relationships between entities.
|
|
196
|
+
*/
|
|
197
|
+
private deriveRelationships;
|
|
198
|
+
/**
|
|
199
|
+
* Generate a high-level summary of the solution.
|
|
200
|
+
*/
|
|
201
|
+
private generateSummary;
|
|
202
|
+
/**
|
|
203
|
+
* Compare two solutions and generate a diff.
|
|
204
|
+
*/
|
|
205
|
+
compareSolutions(solution1: SemanticSolution, solution2: SemanticSolution): SolutionDiff;
|
|
206
|
+
/**
|
|
207
|
+
* Check if two semantic entities are equal.
|
|
208
|
+
*/
|
|
209
|
+
private entitiesEqual;
|
|
210
|
+
/**
|
|
211
|
+
* Describe the difference between two entities.
|
|
212
|
+
*/
|
|
213
|
+
private describeDiff;
|
|
214
|
+
/**
|
|
215
|
+
* Translate multiple solutions and generate comparative descriptions.
|
|
216
|
+
*/
|
|
217
|
+
translateMultipleSolutions(rawSolutions: RawSolution[]): {
|
|
218
|
+
solutions: SemanticSolution[];
|
|
219
|
+
comparison: string;
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Create an EntityRegistry from an array of metadata.
|
|
224
|
+
*/
|
|
225
|
+
export declare function createEntityRegistry(entities: EntityMetadata[]): EntityRegistry;
|
|
226
|
+
/**
|
|
227
|
+
* Create an empty EntityRegistry (all entities will be "unknown" type).
|
|
228
|
+
*/
|
|
229
|
+
export declare function createEmptyRegistry(): EntityRegistry;
|