@things-factory/board-ai 10.1.24 → 10.1.25

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 (105) hide show
  1. package/dist-client/server/service/assistant.d.ts +5 -4
  2. package/dist-client/server/service/assistant.js +35 -35
  3. package/dist-client/server/service/assistant.js.map +1 -1
  4. package/dist-client/server/service/styling/clear-tools.d.ts +2 -2
  5. package/dist-client/server/service/styling/clear-tools.js.map +1 -1
  6. package/dist-client/server/service/styling/copy-tools.d.ts +3 -3
  7. package/dist-client/server/service/styling/copy-tools.js +1 -1
  8. package/dist-client/server/service/styling/copy-tools.js.map +1 -1
  9. package/dist-client/server/service/styling/effect-tools.d.ts +2 -2
  10. package/dist-client/server/service/styling/effect-tools.js.map +1 -1
  11. package/dist-client/server/service/styling/fill-tools.d.ts +3 -3
  12. package/dist-client/server/service/styling/fill-tools.js +1 -1
  13. package/dist-client/server/service/styling/fill-tools.js.map +1 -1
  14. package/dist-client/server/service/styling/material-tools.d.ts +2 -2
  15. package/dist-client/server/service/styling/material-tools.js.map +1 -1
  16. package/dist-client/server/service/styling/registry.d.ts +6 -6
  17. package/dist-client/server/service/styling/registry.js +2 -2
  18. package/dist-client/server/service/styling/registry.js.map +1 -1
  19. package/dist-client/server/service/styling/stroke-tools.d.ts +2 -2
  20. package/dist-client/server/service/styling/stroke-tools.js.map +1 -1
  21. package/dist-client/server/service/styling/text-tools.d.ts +2 -2
  22. package/dist-client/server/service/styling/text-tools.js.map +1 -1
  23. package/dist-client/server/service/types.d.ts +6 -148
  24. package/dist-client/server/service/types.js.map +1 -1
  25. package/dist-client/server/service/validation/board-model-schema.d.ts +262 -262
  26. package/dist-client/server/service/validation/board-model-schema.js +4 -4
  27. package/dist-client/server/service/validation/board-model-schema.js.map +1 -1
  28. package/dist-client/server/service/validation/tool-validation.js +5 -5
  29. package/dist-client/server/service/validation/tool-validation.js.map +1 -1
  30. package/dist-server/index.d.ts +2 -2
  31. package/dist-server/index.js +2 -2
  32. package/dist-server/index.js.map +1 -1
  33. package/dist-server/service/assistant.d.ts +5 -4
  34. package/dist-server/service/assistant.js +37 -37
  35. package/dist-server/service/assistant.js.map +1 -1
  36. package/dist-server/service/board-ai-resolver.js +2 -2
  37. package/dist-server/service/board-ai-resolver.js.map +1 -1
  38. package/dist-server/service/index.d.ts +0 -1
  39. package/dist-server/service/index.js +0 -1
  40. package/dist-server/service/index.js.map +1 -1
  41. package/dist-server/service/patch-entry/board-patch-subscription.js +1 -1
  42. package/dist-server/service/patch-entry/board-patch-subscription.js.map +1 -1
  43. package/dist-server/service/patch-entry/patch-entry.d.ts +1 -1
  44. package/dist-server/service/patch-entry/patch-entry.js +1 -1
  45. package/dist-server/service/patch-entry/patch-entry.js.map +1 -1
  46. package/dist-server/service/styling/clear-tools.d.ts +2 -2
  47. package/dist-server/service/styling/clear-tools.js.map +1 -1
  48. package/dist-server/service/styling/copy-tools.d.ts +3 -3
  49. package/dist-server/service/styling/copy-tools.js +1 -1
  50. package/dist-server/service/styling/copy-tools.js.map +1 -1
  51. package/dist-server/service/styling/effect-tools.d.ts +2 -2
  52. package/dist-server/service/styling/effect-tools.js.map +1 -1
  53. package/dist-server/service/styling/fill-tools.d.ts +3 -3
  54. package/dist-server/service/styling/fill-tools.js +1 -1
  55. package/dist-server/service/styling/fill-tools.js.map +1 -1
  56. package/dist-server/service/styling/material-tools.d.ts +2 -2
  57. package/dist-server/service/styling/material-tools.js.map +1 -1
  58. package/dist-server/service/styling/registry.d.ts +6 -6
  59. package/dist-server/service/styling/registry.js +2 -2
  60. package/dist-server/service/styling/registry.js.map +1 -1
  61. package/dist-server/service/styling/stroke-tools.d.ts +2 -2
  62. package/dist-server/service/styling/stroke-tools.js.map +1 -1
  63. package/dist-server/service/styling/text-tools.d.ts +2 -2
  64. package/dist-server/service/styling/text-tools.js.map +1 -1
  65. package/dist-server/service/types.d.ts +6 -148
  66. package/dist-server/service/types.js.map +1 -1
  67. package/dist-server/service/validation/board-model-schema.d.ts +262 -262
  68. package/dist-server/service/validation/board-model-schema.js +4 -4
  69. package/dist-server/service/validation/board-model-schema.js.map +1 -1
  70. package/dist-server/service/validation/tool-validation.js +5 -5
  71. package/dist-server/service/validation/tool-validation.js.map +1 -1
  72. package/package.json +6 -5
  73. package/server/index.ts +2 -2
  74. package/server/service/assistant-integration.test.ts +44 -44
  75. package/server/service/assistant-llm-smoke.test.ts +5 -5
  76. package/server/service/assistant.test.ts +86 -86
  77. package/server/service/assistant.ts +41 -43
  78. package/server/service/board-ai-resolver.ts +2 -2
  79. package/server/service/index.ts +0 -1
  80. package/server/service/patch-entry/board-patch-subscription.ts +1 -1
  81. package/server/service/patch-entry/patch-entry.ts +2 -2
  82. package/server/service/styling/clear-tools.ts +2 -2
  83. package/server/service/styling/copy-tools.ts +3 -3
  84. package/server/service/styling/effect-tools.ts +2 -2
  85. package/server/service/styling/fill-tools.test.ts +1 -1
  86. package/server/service/styling/fill-tools.ts +4 -4
  87. package/server/service/styling/material-tools.ts +2 -2
  88. package/server/service/styling/registry.ts +6 -6
  89. package/server/service/styling/stroke-tools.test.ts +1 -1
  90. package/server/service/styling/stroke-tools.ts +3 -3
  91. package/server/service/styling/text-tools.ts +2 -2
  92. package/server/service/tool-exposure.test.ts +7 -7
  93. package/server/service/types.ts +9 -110
  94. package/server/service/validation/board-model-schema.test.ts +3 -3
  95. package/server/service/validation/board-model-schema.ts +4 -4
  96. package/server/service/validation/tool-validation.ts +5 -5
  97. package/dist-client/tsconfig.tsbuildinfo +0 -1
  98. package/dist-server/service/apply-patch.d.ts +0 -47
  99. package/dist-server/service/apply-patch.js +0 -369
  100. package/dist-server/service/apply-patch.js.map +0 -1
  101. package/dist-server/tsconfig.tsbuildinfo +0 -1
  102. package/logs/connections-2026-09-12-15.log +0 -0
  103. package/server/service/apply-patch-drift.test.ts +0 -831
  104. package/server/service/apply-patch.test.ts +0 -757
  105. package/server/service/apply-patch.ts +0 -411
@@ -9,9 +9,9 @@ exports.listLayoutTemplateNames = listLayoutTemplateNames;
9
9
  exports.isWriteTool = isWriteTool;
10
10
  exports.isActionTool = isActionTool;
11
11
  exports.buildToolGate = buildToolGate;
12
- exports.toolCallToBoardActionOp = toolCallToBoardActionOp;
12
+ exports.toolCallToSceneActionOp = toolCallToSceneActionOp;
13
13
  exports.toolResultToChatResponse = toolResultToChatResponse;
14
- exports.toolCallToBoardEditOp = toolCallToBoardEditOp;
14
+ exports.toolCallToSceneEditOp = toolCallToSceneEditOp;
15
15
  exports.summarizeBoard = summarizeBoard;
16
16
  const board_import_1 = require("@things-factory/board-import");
17
17
  const prefab_registry_1 = require("./prefab-registry");
@@ -183,7 +183,7 @@ class DefaultBoardAIAssistant {
183
183
  executeReadTool: (tc, ctx) => wrappedExecuteReadTool(tc, ctx.board, ctx.selectedRefids),
184
184
  /* 문서에서 부품을 꺼내는 일은 **여기서** 한다 — 루프는 board 의 모양을 모른다. */
185
185
  validateWriteToolCall: (tc, ctx) => (0, tool_validation_1.validateWriteToolCall)(tc, (ctx.board?.components ?? [])),
186
- toolCallToOp: toolCallToBoardActionOp,
186
+ toolCallToOp: toolCallToSceneActionOp,
187
187
  summarizeToolResult: ai_client_base_1.summarizeToolResult
188
188
  },
189
189
  context: { board: currentBoard, selectedRefids }
@@ -193,11 +193,11 @@ class DefaultBoardAIAssistant {
193
193
  const toolUsages = loopResult.toolUsages;
194
194
  const lastText = loopResult.lastText;
195
195
  const stopReason = loopResult.stopReason;
196
- // accumulated write calls → BoardEditPatch (tool 이 array 반환 가능 — flat)
196
+ // accumulated write calls → SceneEditPatch (tool 이 array 반환 가능 — flat)
197
197
  const components = (currentBoard?.components ?? []);
198
198
  const ops = accumulatedWriteCalls
199
199
  .flatMap(call => {
200
- const r = toolCallToBoardEditOp(call, components, gate);
200
+ const r = toolCallToSceneEditOp(call, components, gate);
201
201
  if (r === null)
202
202
  return [];
203
203
  return Array.isArray(r) ? r : [r];
@@ -287,7 +287,7 @@ class DefaultBoardAIAssistant {
287
287
  아무것도 안 바뀌었기 때문.
288
288
 
289
289
  룰:
290
- 1. 변경 요청 → write tool 호출 필수 (modifyBoard / setFill / setStroke / setMaterial /
290
+ 1. 변경 요청 → write tool 호출 필수 (modifyScene / setFill / setStroke / setMaterial /
291
291
  setShadow / setOpacity / setVisible / setFont / setText / setMaterial / addComponent /
292
292
  removeComponentByRefid / modifyComponentByRefid / align/distribute/group/zorder 등)
293
293
  2. 호출 + 짧은 reply 텍스트 동시 작성 OK — reply 는 *결과* 를 한국어로 한두 문장 요약
@@ -311,22 +311,22 @@ root-level properties separate from any child:
311
311
  - 3D 환경: \`sky\` / \`skyColor\` / \`exposure\` / \`hemi*\` / \`dirLight*\` / \`dirShadow*\` / \`camera*\` / \`autoRotate\`
312
312
  - 식별: \`id\`, \`refid\`, \`type\` ("model-layer")
313
313
  ⚠ 보드 \*\*name\*\* 은 root attribute 가 아님 — Board 엔티티의 DB 컬럼이지 scene
314
- MODEL 의 필드가 아님 (model-layer 가 무시). 보드 라벨 변경은 modifyBoard 영역 X.
314
+ MODEL 의 필드가 아님 (model-layer 가 무시). 보드 라벨 변경은 modifyScene 영역 X.
315
315
  • Children: an array of components inside the board (rect / circle / text /
316
316
  gauge / etc.). 컴포넌트들은 \`name\` (user label) 를 가질 수 있음 — 이는 child
317
317
  component 의 속성이지 board root 의 속성이 아님.
318
318
 
319
319
  Rules:
320
320
  - To change a board-level attribute (background, board size, 3D atmosphere)
321
- → call \`modifyBoard({ patch: { fillStyle: ..., width: ..., sky: ..., exposure: ..., dirLight*: ..., hemi*: ... } })\`.
321
+ → call \`modifyScene({ patch: { fillStyle: ..., width: ..., sky: ..., exposure: ..., dirLight*: ..., hemi*: ... } })\`.
322
322
  NOTE: 보드 라벨/제목 ("보드 이름") 은 scene model 이 아니라 Board *엔티티* 의 컬럼.
323
- things-scene 의 model-layer 는 \`name\` 을 인식하지 않음. modifyBoard 의 patch 에
323
+ things-scene 의 model-layer 는 \`name\` 을 인식하지 않음. modifyScene 의 patch 에
324
324
  \`name\` 을 넣지 말 것 — 죽은 필드로 박힐 뿐 효과 없음.
325
325
  - To change a CHILD COMPONENT's attribute → call \`modifyComponentByRefid\`.
326
- - DO NOT use modifyBoard to change a child. DO NOT use modifyComponentByRefid
326
+ - DO NOT use modifyScene to change a child. DO NOT use modifyComponentByRefid
327
327
  to change board background.
328
328
  - "보드 배경색", "board background", "테두리/캔버스 크기" 같은 요청은 root
329
- attribute 변경 → \`modifyBoard\`.
329
+ attribute 변경 → \`modifyScene\`.
330
330
 
331
331
  ==== COMPONENT TREE (NESTING) ====
332
332
  컴포넌트는 *재귀 구조*. group / container 같은 부모 컴포넌트는 자기 \`components\`
@@ -392,8 +392,8 @@ to that wording in your reply. Do not echo refid back to the user.
392
392
 
393
393
  ==== AVAILABLE TOOLS ====
394
394
  Board-level (root attributes):
395
- - modifyBoard: change board's own fillStyle / width / height / fitMode / translate / scale AND 3D atmosphere (sky / skyColor / exposure / hemiSkyColor / hemiGroundColor / hemiIntensity / dirLightEnabled / dirLightColor / dirLightIntensity / dirLightFollowCamera / dirLightAzimuth / dirLightElevation / dirShadow* / camera* / autoRotate / initialCameraView). ⚠ "name" 금지 — scene MODEL 이 아니라 Board 엔티티 컬럼.
396
- - replaceBoard: wholesale board reset (heavy — prefer modifyBoard for most changes)
395
+ - modifyScene: change board's own fillStyle / width / height / fitMode / translate / scale AND 3D atmosphere (sky / skyColor / exposure / hemiSkyColor / hemiGroundColor / hemiIntensity / dirLightEnabled / dirLightColor / dirLightIntensity / dirLightFollowCamera / dirLightAzimuth / dirLightElevation / dirShadow* / camera* / autoRotate / initialCameraView). ⚠ "name" 금지 — scene MODEL 이 아니라 Board 엔티티 컬럼.
396
+ - replaceBoard: wholesale board reset (heavy — prefer modifyScene for most changes)
397
397
  Child components — data:
398
398
  - addComponent: add a new component (parallel calls for multiple adds)
399
399
  - removeComponentByRefid: remove a child by refid
@@ -450,10 +450,10 @@ Modeller actions (ephemeral — does NOT modify the board model, no undo, no sav
450
450
  - fitToView: reset view so the board fits the canvas (mode: fit/ratio/width/height)
451
451
  - setSceneMode: switch modeller between 'edit' and 'view' modes
452
452
  Knowledge:
453
- - getAtmosphereGuide: 3D atmosphere synthesis primer — parameter physics, ranges, color theory, archetype recipes (time-of-day / indoor / surreal). Call BEFORE applying atmospheric/styling modifyBoard for any natural-language mood request.
453
+ - getAtmosphereGuide: 3D atmosphere synthesis primer — parameter physics, ranges, color theory, archetype recipes (time-of-day / indoor / surreal). Call BEFORE applying atmospheric/styling modifyScene for any natural-language mood request.
454
454
 
455
455
  ==== 3D ATMOSPHERE SYNTHESIS ====
456
- 3D scene atmosphere = combination of (1) sky preset / color (2) exposure (3) hemisphere ambient (4) directional sun/key (5) floor material. ALL of these are root-level board attributes — applied via a SINGLE modifyBoard call.
456
+ 3D scene atmosphere = combination of (1) sky preset / color (2) exposure (3) hemisphere ambient (4) directional sun/key (5) floor material. ALL of these are root-level board attributes — applied via a SINGLE modifyScene call.
457
457
 
458
458
  For ANY natural-language atmospheric request — "공장 분위기로", "심해 컬러", "황혼", "사이버펑크", "안개 자욱한 새벽", "1980 우주정거장", "따뜻하게", "차갑고 극적으로" — follow this workflow:
459
459
 
@@ -461,11 +461,11 @@ For ANY natural-language atmospheric request — "공장 분위기로", "심해
461
461
  2. From the guide's "archetypes" section, pick the closest base recipe (time-of-day / indoor / surreal). Interpolate if user combines multiple cues.
462
462
  3. Apply user's nuance via the guide's "modifiers" (warm/cool, drama, saturation, contrast).
463
463
  4. Sanity-check: avoid washout (all params maxed) or mud (all minned). Confirm hemi sky/ground colors and dir color are consistent with the mood.
464
- 5. Apply ALL keys in ONE modifyBoard({patch}) call (sky, skyColor?, exposure, hemiIntensity, hemiSkyColor, hemiGroundColor, dirLightEnabled, dirLightColor, dirLightIntensity, dirLightFollowCamera=false, dirLightAzimuth, dirLightElevation, fillStyle?). ONE patch — not multiple modifyBoard calls.
464
+ 5. Apply ALL keys in ONE modifyScene({patch}) call (sky, skyColor?, exposure, hemiIntensity, hemiSkyColor, hemiGroundColor, dirLightEnabled, dirLightColor, dirLightIntensity, dirLightFollowCamera=false, dirLightAzimuth, dirLightElevation, fillStyle?). ONE patch — not multiple modifyScene calls.
465
465
  6. In the reply, briefly state which archetype + modifier you composed.
466
466
 
467
467
  Avoid:
468
- - Calling modifyBoard with only "fillStyle" for atmospheric requests — that only changes 2D background and floor tint, NOT the 3D scene mood.
468
+ - Calling modifyScene with only "fillStyle" for atmospheric requests — that only changes 2D background and floor tint, NOT the 3D scene mood.
469
469
  - Mixing a sky preset with explicit skyColor (preset wins, skyColor ignored).
470
470
  - Setting dirLightAzimuth/Elevation while leaving dirLightFollowCamera=true (no effect — set follow=false first).
471
471
  - Using only canned presets when the user describes a custom mood — the guide enables synthesis beyond presets.
@@ -651,7 +651,7 @@ function buildBoardEditTools(knownTypes, exposure = {}) {
651
651
  }
652
652
  },
653
653
  {
654
- name: 'modifyBoard',
654
+ name: 'modifyScene',
655
655
  description: "Modify the BOARD's OWN root-level properties — the board itself is the topmost parent (model-layer) and has its own attributes (NOT child components). Valid root keys (things-scene 의 model-layer 가 실제 인식하는 것만):\n • Layout/Geometry: `width`, `height`, `fitMode` ('ratio'|'both'|'width'|'height'|'center'|'none'), `translate` ({x,y}), `scale` ({x,y})\n • 2D 배경: `fillStyle` (string color or object)\n • 3D Sky: `sky` (preset 이름), `skyColor` (preset 미지정 시 단색)\n • 3D Tone: `exposure` (toneMappingExposure, 기본 1.0~1.2)\n • 3D Hemisphere light: `hemiSkyColor`, `hemiGroundColor`, `hemiIntensity` (기본 4.0)\n • 3D Directional light: `dirLightEnabled` (bool), `dirLightColor`, `dirLightIntensity` (기본 2.0), `dirLightFollowCamera` (bool, 기본 true), `dirLightAzimuth` (deg, follow=false 일 때만), `dirLightElevation` (deg, follow=false 일 때만)\n • 3D Shadow: `dirShadowEnabled`, `dirShadowMapSize` (기본 2048), `dirShadowBias`\n • 3D Camera: `cameraX`, `cameraY`, `cameraZ`, `cameraAutoPlay` ('orbit' 등), `autoRotate` (bool), `initialCameraView`\n\n⚠ 절대 사용 금지: `name` — Board *엔티티* 의 컬럼이지 scene MODEL 의 필드가 아님. things-scene 이 인식 안 함. 보드 라벨 변경은 GraphQL boardPatch 의 영역.\n\nDo NOT use for child component edits (use modifyComponentByRefid for those). Do NOT pass a `components` array here — children are managed by add/remove/modify ops separately.",
656
656
  parameters: {
657
657
  type: 'object',
@@ -667,7 +667,7 @@ function buildBoardEditTools(knownTypes, exposure = {}) {
667
667
  },
668
668
  {
669
669
  name: 'replaceBoard',
670
- description: 'Replace the entire board (use ONLY for fresh start or wholesale redesign — heavy operation that resets undo history). For just changing background or size, prefer modifyBoard. Provide width/height and the full components array.',
670
+ description: 'Replace the entire board (use ONLY for fresh start or wholesale redesign — heavy operation that resets undo history). For just changing background or size, prefer modifyScene. Provide width/height and the full components array.',
671
671
  parameters: {
672
672
  type: 'object',
673
673
  properties: {
@@ -736,7 +736,7 @@ function buildBoardEditTools(knownTypes, exposure = {}) {
736
736
  },
737
737
  {
738
738
  name: 'getAtmosphereGuide',
739
- description: "Get a comprehensive 3D atmosphere synthesis guide — parameter physics (sky / exposure / hemisphere / directional / shadow / floor / camera), sane ranges, color theory, time-of-day archetypes, and indoor/surreal mood recipes. Call this BEFORE applying atmospheric/styling changes via modifyBoard whenever the user describes a mood / scene / time-of-day in natural language (e.g. '심해 컬러', '황혼', '공장 분위기', '사이버펑크', '안개 자욱한 새벽'). The guide enables you to synthesize concrete parameter values yourself, beyond canned presets.",
739
+ description: "Get a comprehensive 3D atmosphere synthesis guide — parameter physics (sky / exposure / hemisphere / directional / shadow / floor / camera), sane ranges, color theory, time-of-day archetypes, and indoor/surreal mood recipes. Call this BEFORE applying atmospheric/styling changes via modifyScene whenever the user describes a mood / scene / time-of-day in natural language (e.g. '심해 컬러', '황혼', '공장 분위기', '사이버펑크', '안개 자욱한 새벽'). The guide enables you to synthesize concrete parameter values yourself, beyond canned presets.",
740
740
  parameters: { type: 'object', properties: {} }
741
741
  },
742
742
  {
@@ -1068,7 +1068,7 @@ const WRITE_TOOL_NAMES = new Set([
1068
1068
  'setShadowProperties',
1069
1069
  'clearStyle',
1070
1070
  'copyStyle',
1071
- 'modifyBoard',
1071
+ 'modifyScene',
1072
1072
  'replaceBoard',
1073
1073
  // Phase 2 — model 차원 scene 조작 (좌표/구조/zorder)
1074
1074
  'alignComponents',
@@ -1085,7 +1085,7 @@ const WRITE_TOOL_NAMES = new Set([
1085
1085
  ]);
1086
1086
  /**
1087
1087
  * C-1 — ephemeral scene 조작 (selection / view / mode). model 변경 X, undo 영향 X.
1088
- * 별도 ChatResponse.actions 채널로 전달 → 호스트가 board-action-execute 로 적용.
1088
+ * 별도 ChatResponse.actions 채널로 전달 → 호스트가 scene-action-execute 로 적용.
1089
1089
  */
1090
1090
  const ACTION_TOOL_NAMES = new Set([
1091
1091
  'selectComponents',
@@ -1222,13 +1222,13 @@ function executeReadTool(call, currentBoard, selectedRefids) {
1222
1222
  *
1223
1223
  * 의도 — preset 한 단어로 끝나지 않는 사용자 요청 ("심해", "황혼", "1980 우주정거장",
1224
1224
  * "안개 새벽") 에 AI 가 구체적 파라미터 값을 직접 합성하도록 물리/색채/미학 지식
1225
- * 동시 제공. AI 는 이 가이드를 받은 뒤 modifyBoard 로 한 번에 적용.
1225
+ * 동시 제공. AI 는 이 가이드를 받은 뒤 modifyScene 로 한 번에 적용.
1226
1226
  *
1227
- * things-scene 의 board model 에 들어가는 root level 키만 다룸 (modifyBoard 로
1227
+ * things-scene 의 board model 에 들어가는 root level 키만 다룸 (modifyScene 로
1228
1228
  * 적용 가능한 것). camera position 같은 ephemeral 한 것은 별도 영역.
1229
1229
  */
1230
1230
  const ATMOSPHERE_GUIDE = {
1231
- overview: '3D 보드 분위기는 (1) sky preset 또는 단색 (2) tone mapping exposure (3) hemisphere ambient (4) directional sun/key (5) floor 의 조합. 모두 board root model 의 속성이라 modifyBoard 단일 op 로 한 번에 적용. 자연어 요청은 archetype 레시피를 base 로 잡고 modifier 로 fine-tune.',
1231
+ overview: '3D 보드 분위기는 (1) sky preset 또는 단색 (2) tone mapping exposure (3) hemisphere ambient (4) directional sun/key (5) floor 의 조합. 모두 board root model 의 속성이라 modifyScene 단일 op 로 한 번에 적용. 자연어 요청은 archetype 레시피를 base 로 잡고 modifier 로 fine-tune.',
1232
1232
  parameters: {
1233
1233
  sky: {
1234
1234
  description: '3D 배경 + IBL (image-based lighting) 의 source. preset / "color" / "" 셋 중 하나.',
@@ -1553,7 +1553,7 @@ const ATMOSPHERE_GUIDE = {
1553
1553
  '2. archetypes 에서 가장 가까운 base 레시피 선택.',
1554
1554
  '3. modifiers 로 사용자 요청 뉘앙스 fine-tune (warm/cool/drama/...).',
1555
1555
  '4. sanity check — exposure × hemi × dir 어느 한쪽 극단 아닌지, hemi sky/ground 색 모순 없는지.',
1556
- "5. modifyBoard({ patch: { ...combined keys... } }) 한 번에 적용. 사용자에게 어떤 archetype + modifier 조합으로 갔는지 한 줄로 설명."
1556
+ "5. modifyScene({ patch: { ...combined keys... } }) 한 번에 적용. 사용자에게 어떤 archetype + modifier 조합으로 갔는지 한 줄로 설명."
1557
1557
  ],
1558
1558
  pitfalls: [
1559
1559
  'sky preset 위에 skyColor 같이 지정하면 preset 이 우선 (skyColor 무시).',
@@ -1573,7 +1573,7 @@ const ATMOSPHERE_GUIDE = {
1573
1573
  * 사용 흐름:
1574
1574
  * 1. 사용자 의도 (산업 / 금융 / 의료 / SF / ...) 식별
1575
1575
  * 2. recommendations 에서 매칭 후보 1~2개 추림
1576
- * 3. modifyBoard 로 board.fillStyle 을 palette.base 로 설정
1576
+ * 3. modifyScene 로 board.fillStyle 을 palette.base 로 설정
1577
1577
  * 4. addPrefab / addComponent 시 palette 의 surface/accent/text 사용
1578
1578
  * 5. 일관된 룩 → 한 번 정한 팔레트 안에서만 색 선택
1579
1579
  *
@@ -1700,7 +1700,7 @@ const COLOR_PALETTES = {
1700
1700
  workflow: [
1701
1701
  '1. 사용자 도메인 / 분위기 키워드 식별 — 산업/금융/관제/의료/SF/프레젠테이션',
1702
1702
  '2. recommendations 에서 매칭 후보 추림. 사용자 모호하면 가장 흔한 industrial-steel 디폴트.',
1703
- "3. modifyBoard({ patch: { fillStyle: palette.base } }) 으로 보드 배경 set.",
1703
+ "3. modifyScene({ patch: { fillStyle: palette.base } }) 으로 보드 배경 set.",
1704
1704
  '4. 이후 모든 add / addPrefab 호출 시 palette.surface / accent / text / border 사용. 자유 색 X.',
1705
1705
  '5. status 표시는 success / warning / danger / info 4종에서만 — 자체 hex 만들지 마라.'
1706
1706
  ],
@@ -1872,10 +1872,10 @@ function buildExternalCategoryDefinitions(filter) {
1872
1872
  }));
1873
1873
  }
1874
1874
  /**
1875
- * Tool call → BoardActionOp 변환 (C-1 ephemeral scene 조작).
1875
+ * Tool call → SceneActionOp 변환 (C-1 ephemeral scene 조작).
1876
1876
  * 잘못된 인자는 null — agentic loop 가 Unknown tool 비슷하게 처리.
1877
1877
  */
1878
- function toolCallToBoardActionOp(tc, gate = buildToolGate()) {
1878
+ function toolCallToSceneActionOp(tc, gate = buildToolGate()) {
1879
1879
  const args = tc.arguments ?? {};
1880
1880
  /* 씬 조작 액션은 전부 코어(보드) 능력 — 노출 안 된 대화에서는 만들지 않는다.
1881
1881
  * loop 는 gate.isAction 으로 이미 걸러내지만, 다른 호출부의 오용도 막는다. */
@@ -1912,7 +1912,7 @@ function toolCallToBoardActionOp(tc, gate = buildToolGate()) {
1912
1912
  return null;
1913
1913
  }
1914
1914
  }
1915
- // ── Tool call → BoardEditOp 변환 ───────────────────────────────────
1915
+ // ── Tool call → SceneEditOp 변환 ───────────────────────────────────
1916
1916
  /**
1917
1917
  * AIToolChatResult → ChatResponse.
1918
1918
  *
@@ -1924,7 +1924,7 @@ function toolCallToBoardActionOp(tc, gate = buildToolGate()) {
1924
1924
  function toolResultToChatResponse(result) {
1925
1925
  const ops = result.toolCalls
1926
1926
  .flatMap(call => {
1927
- const r = toolCallToBoardEditOp(call);
1927
+ const r = toolCallToSceneEditOp(call);
1928
1928
  if (r === null)
1929
1929
  return [];
1930
1930
  return Array.isArray(r) ? r : [r];
@@ -1940,7 +1940,7 @@ function toolResultToChatResponse(result) {
1940
1940
  }
1941
1941
  return { reply, patch, followUp: undefined };
1942
1942
  }
1943
- function toolCallToBoardEditOp(tc, components = [], gate = buildToolGate()) {
1943
+ function toolCallToSceneEditOp(tc, components = [], gate = buildToolGate()) {
1944
1944
  const args = tc.arguments ?? {};
1945
1945
  /* 노출되지 않은 코어(보드 편집) 도구는 op 를 만들지 않는다 — 정의를 숨겼어도 호출은 올 수 있다. */
1946
1946
  if (!gate.coreOn && !gate.spec(tc.name))
@@ -1953,7 +1953,7 @@ function toolCallToBoardEditOp(tc, components = [], gate = buildToolGate()) {
1953
1953
  return (0, registry_js_1.dispatchStylingTool)(tc.name, args, components);
1954
1954
  }
1955
1955
  // tool-registry plugin point — 외부 등록 'write' 카테고리 dispatch.
1956
- // builder 결과는 BoardEditOp[] | { ops, errors? } | null 셋 중 하나.
1956
+ // builder 결과는 SceneEditOp[] | { ops, errors? } | null 셋 중 하나.
1957
1957
  // (read/external 카테고리는 별도 dispatch path — agentic loop 의 executeReadTool 이 직접 처리.)
1958
1958
  const registrySpec = gate.spec(tc.name);
1959
1959
  if (registrySpec && registrySpec.kind === 'write') {
@@ -1985,17 +1985,17 @@ function toolCallToBoardEditOp(tc, components = [], gate = buildToolGate()) {
1985
1985
  // 모든 styling tool (setFill/setStroke/setText/setFont/setShadow/setOpacity/
1986
1986
  // setVisible/setMaterial/setShadowProperties/clearStyle/copyStyle) 은 registry
1987
1987
  // 가 처리 — 상단 isStylingTool 분기 참조
1988
- case 'modifyBoard': {
1988
+ case 'modifyScene': {
1989
1989
  if (!args.patch || typeof args.patch !== 'object' || Array.isArray(args.patch))
1990
1990
  return null;
1991
- return { op: 'modifyBoard', patch: args.patch };
1991
+ return { op: 'modifyScene', patch: args.patch };
1992
1992
  }
1993
1993
  case 'replaceBoard': {
1994
1994
  if (!Array.isArray(args.components))
1995
1995
  return null;
1996
1996
  return {
1997
1997
  op: 'replace',
1998
- board: {
1998
+ model: {
1999
1999
  width: typeof args.width === 'number' ? args.width : undefined,
2000
2000
  height: typeof args.height === 'number' ? args.height : undefined,
2001
2001
  fillStyle: typeof args.fillStyle === 'string' ? args.fillStyle : undefined,