@things-factory/board-ai 10.1.24 β†’ 10.1.26

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 (107) hide show
  1. package/PLAN-styling-tools.md +1 -1
  2. package/dist-client/server/service/assistant.d.ts +5 -4
  3. package/dist-client/server/service/assistant.js +35 -35
  4. package/dist-client/server/service/assistant.js.map +1 -1
  5. package/dist-client/server/service/styling/clear-tools.d.ts +2 -2
  6. package/dist-client/server/service/styling/clear-tools.js.map +1 -1
  7. package/dist-client/server/service/styling/copy-tools.d.ts +3 -3
  8. package/dist-client/server/service/styling/copy-tools.js +1 -1
  9. package/dist-client/server/service/styling/copy-tools.js.map +1 -1
  10. package/dist-client/server/service/styling/effect-tools.d.ts +2 -2
  11. package/dist-client/server/service/styling/effect-tools.js.map +1 -1
  12. package/dist-client/server/service/styling/fill-tools.d.ts +3 -3
  13. package/dist-client/server/service/styling/fill-tools.js +1 -1
  14. package/dist-client/server/service/styling/fill-tools.js.map +1 -1
  15. package/dist-client/server/service/styling/material-tools.d.ts +2 -2
  16. package/dist-client/server/service/styling/material-tools.js.map +1 -1
  17. package/dist-client/server/service/styling/registry.d.ts +6 -6
  18. package/dist-client/server/service/styling/registry.js +2 -2
  19. package/dist-client/server/service/styling/registry.js.map +1 -1
  20. package/dist-client/server/service/styling/stroke-tools.d.ts +2 -2
  21. package/dist-client/server/service/styling/stroke-tools.js.map +1 -1
  22. package/dist-client/server/service/styling/text-tools.d.ts +2 -2
  23. package/dist-client/server/service/styling/text-tools.js.map +1 -1
  24. package/dist-client/server/service/types.d.ts +6 -148
  25. package/dist-client/server/service/types.js.map +1 -1
  26. package/dist-client/server/service/validation/board-model-schema.d.ts +262 -262
  27. package/dist-client/server/service/validation/board-model-schema.js +4 -4
  28. package/dist-client/server/service/validation/board-model-schema.js.map +1 -1
  29. package/dist-client/server/service/validation/tool-validation.js +5 -5
  30. package/dist-client/server/service/validation/tool-validation.js.map +1 -1
  31. package/dist-client/tsconfig.tsbuildinfo +1 -1
  32. package/dist-server/index.d.ts +2 -2
  33. package/dist-server/index.js +2 -2
  34. package/dist-server/index.js.map +1 -1
  35. package/dist-server/service/assistant.d.ts +5 -4
  36. package/dist-server/service/assistant.js +37 -37
  37. package/dist-server/service/assistant.js.map +1 -1
  38. package/dist-server/service/board-ai-resolver.js +2 -2
  39. package/dist-server/service/board-ai-resolver.js.map +1 -1
  40. package/dist-server/service/index.d.ts +0 -1
  41. package/dist-server/service/index.js +0 -1
  42. package/dist-server/service/index.js.map +1 -1
  43. package/dist-server/service/patch-entry/board-patch-subscription.js +1 -1
  44. package/dist-server/service/patch-entry/board-patch-subscription.js.map +1 -1
  45. package/dist-server/service/patch-entry/patch-entry.d.ts +1 -1
  46. package/dist-server/service/patch-entry/patch-entry.js +1 -1
  47. package/dist-server/service/patch-entry/patch-entry.js.map +1 -1
  48. package/dist-server/service/styling/clear-tools.d.ts +2 -2
  49. package/dist-server/service/styling/clear-tools.js.map +1 -1
  50. package/dist-server/service/styling/copy-tools.d.ts +3 -3
  51. package/dist-server/service/styling/copy-tools.js +1 -1
  52. package/dist-server/service/styling/copy-tools.js.map +1 -1
  53. package/dist-server/service/styling/effect-tools.d.ts +2 -2
  54. package/dist-server/service/styling/effect-tools.js.map +1 -1
  55. package/dist-server/service/styling/fill-tools.d.ts +3 -3
  56. package/dist-server/service/styling/fill-tools.js +1 -1
  57. package/dist-server/service/styling/fill-tools.js.map +1 -1
  58. package/dist-server/service/styling/material-tools.d.ts +2 -2
  59. package/dist-server/service/styling/material-tools.js.map +1 -1
  60. package/dist-server/service/styling/registry.d.ts +6 -6
  61. package/dist-server/service/styling/registry.js +2 -2
  62. package/dist-server/service/styling/registry.js.map +1 -1
  63. package/dist-server/service/styling/stroke-tools.d.ts +2 -2
  64. package/dist-server/service/styling/stroke-tools.js.map +1 -1
  65. package/dist-server/service/styling/text-tools.d.ts +2 -2
  66. package/dist-server/service/styling/text-tools.js.map +1 -1
  67. package/dist-server/service/types.d.ts +6 -148
  68. package/dist-server/service/types.js.map +1 -1
  69. package/dist-server/service/validation/board-model-schema.d.ts +262 -262
  70. package/dist-server/service/validation/board-model-schema.js +4 -4
  71. package/dist-server/service/validation/board-model-schema.js.map +1 -1
  72. package/dist-server/service/validation/tool-validation.js +5 -5
  73. package/dist-server/service/validation/tool-validation.js.map +1 -1
  74. package/dist-server/tsconfig.tsbuildinfo +1 -1
  75. package/logs/.5e5d741d8b7784a2fbad65eedc0fd46946aaf6f2-audit.json +5 -0
  76. package/logs/connections-2026-09-17-16.log +0 -0
  77. package/package.json +8 -7
  78. package/server/index.ts +2 -2
  79. package/server/service/assistant-integration.test.ts +44 -44
  80. package/server/service/assistant-llm-smoke.test.ts +5 -5
  81. package/server/service/assistant.test.ts +86 -86
  82. package/server/service/assistant.ts +41 -43
  83. package/server/service/board-ai-resolver.ts +2 -2
  84. package/server/service/index.ts +0 -1
  85. package/server/service/patch-entry/board-patch-subscription.ts +1 -1
  86. package/server/service/patch-entry/patch-entry.ts +2 -2
  87. package/server/service/styling/clear-tools.ts +2 -2
  88. package/server/service/styling/copy-tools.ts +3 -3
  89. package/server/service/styling/effect-tools.ts +2 -2
  90. package/server/service/styling/fill-tools.test.ts +1 -1
  91. package/server/service/styling/fill-tools.ts +4 -4
  92. package/server/service/styling/material-tools.ts +2 -2
  93. package/server/service/styling/registry.ts +6 -6
  94. package/server/service/styling/stroke-tools.test.ts +1 -1
  95. package/server/service/styling/stroke-tools.ts +3 -3
  96. package/server/service/styling/text-tools.ts +2 -2
  97. package/server/service/tool-exposure.test.ts +7 -7
  98. package/server/service/types.ts +9 -110
  99. package/server/service/validation/board-model-schema.test.ts +3 -3
  100. package/server/service/validation/board-model-schema.ts +4 -4
  101. package/server/service/validation/tool-validation.ts +5 -5
  102. package/dist-server/service/apply-patch.d.ts +0 -47
  103. package/dist-server/service/apply-patch.js +0 -369
  104. package/dist-server/service/apply-patch.js.map +0 -1
  105. package/server/service/apply-patch-drift.test.ts +0 -831
  106. package/server/service/apply-patch.test.ts +0 -757
  107. package/server/service/apply-patch.ts +0 -411
@@ -572,7 +572,7 @@ packages/board-ai/server/service/
572
572
 
573
573
  ```ts
574
574
  // 예: setFill(refids=[35], mode='solid', color='red')
575
- // β†’ BoardEditPatch:
575
+ // β†’ SceneEditPatch:
576
576
  {
577
577
  ops: [
578
578
  { op: 'modify', refid: 35, patch: { fillStyle: { type: 'solid', color: '#ff0000' } } }
@@ -3,8 +3,9 @@
3
3
  */
4
4
  import type { AIClient, AITool, AIToolCall, AIToolChatResult } from '@things-factory/ai-client-base';
5
5
  import { type BoardModel, type ComponentCategory } from '@things-factory/board-import';
6
- import type { BoardAIAssistant, BoardEditOp, ChatOptions, ChatResponse, LLMMessage } from './types.js';
6
+ import type { BoardAIAssistant, ChatOptions, ChatResponse, LLMMessage } from './types.js';
7
7
  import { formatAbortNotice, summarizeToolResult, type ToolGate as NeutralToolGate } from '@things-factory/ai-client-base';
8
+ import type { SceneEditOp } from '@operato/scene-ops';
8
9
  import { type ToolCategoryFilter } from '@things-factory/ai-client-base';
9
10
  export interface BoardAIAssistantOptions {
10
11
  /** κΈ°λ³Έ scope (chat 호좜 μ‹œ μ˜΅μ…˜μ΄ μ—†μœΌλ©΄ μ‚¬μš©) */
@@ -96,10 +97,10 @@ export interface ToolGate extends NeutralToolGate {
96
97
  */
97
98
  export declare function buildToolGate(exposure?: ToolExposure): ToolGate;
98
99
  /**
99
- * Tool call β†’ BoardActionOp λ³€ν™˜ (C-1 ephemeral scene μ‘°μž‘).
100
+ * Tool call β†’ SceneActionOp λ³€ν™˜ (C-1 ephemeral scene μ‘°μž‘).
100
101
  * 잘λͺ»λœ μΈμžλŠ” null β€” agentic loop κ°€ Unknown tool λΉ„μŠ·ν•˜κ²Œ 처리.
101
102
  */
102
- export declare function toolCallToBoardActionOp(tc: AIToolCall, gate?: ToolGate): import('./types.js').BoardActionOp | null;
103
+ export declare function toolCallToSceneActionOp(tc: AIToolCall, gate?: ToolGate): import('@operato/scene-ops').SceneActionOp | null;
103
104
  /**
104
105
  * AIToolChatResult β†’ ChatResponse.
105
106
  *
@@ -109,5 +110,5 @@ export declare function toolCallToBoardActionOp(tc: AIToolCall, gate?: ToolGate)
109
110
  * 섀계.
110
111
  */
111
112
  export declare function toolResultToChatResponse(result: AIToolChatResult): ChatResponse;
112
- export declare function toolCallToBoardEditOp(tc: AIToolCall, components?: ReadonlyArray<any>, gate?: ToolGate): BoardEditOp | BoardEditOp[] | null;
113
+ export declare function toolCallToSceneEditOp(tc: AIToolCall, components?: ReadonlyArray<any>, gate?: ToolGate): SceneEditOp | SceneEditOp[] | null;
113
114
  export declare function summarizeBoard(board: BoardModel | null | undefined): any;
@@ -166,7 +166,7 @@ export class DefaultBoardAIAssistant {
166
166
  executeReadTool: (tc, ctx) => wrappedExecuteReadTool(tc, ctx.board, ctx.selectedRefids),
167
167
  /* λ¬Έμ„œμ—μ„œ λΆ€ν’ˆμ„ κΊΌλ‚΄λŠ” 일은 **μ—¬κΈ°μ„œ** ν•œλ‹€ β€” λ£¨ν”„λŠ” board 의 λͺ¨μ–‘을 λͺ¨λ₯Έλ‹€. */
168
168
  validateWriteToolCall: (tc, ctx) => validateWriteToolCall(tc, (ctx.board?.components ?? [])),
169
- toolCallToOp: toolCallToBoardActionOp,
169
+ toolCallToOp: toolCallToSceneActionOp,
170
170
  summarizeToolResult
171
171
  },
172
172
  context: { board: currentBoard, selectedRefids }
@@ -176,11 +176,11 @@ export class DefaultBoardAIAssistant {
176
176
  const toolUsages = loopResult.toolUsages;
177
177
  const lastText = loopResult.lastText;
178
178
  const stopReason = loopResult.stopReason;
179
- // accumulated write calls β†’ BoardEditPatch (tool 이 array λ°˜ν™˜ κ°€λŠ₯ β€” flat)
179
+ // accumulated write calls β†’ SceneEditPatch (tool 이 array λ°˜ν™˜ κ°€λŠ₯ β€” flat)
180
180
  const components = (currentBoard?.components ?? []);
181
181
  const ops = accumulatedWriteCalls
182
182
  .flatMap(call => {
183
- const r = toolCallToBoardEditOp(call, components, gate);
183
+ const r = toolCallToSceneEditOp(call, components, gate);
184
184
  if (r === null)
185
185
  return [];
186
186
  return Array.isArray(r) ? r : [r];
@@ -270,7 +270,7 @@ export class DefaultBoardAIAssistant {
270
270
  아무것도 μ•ˆ λ°”λ€Œμ—ˆκΈ° λ•Œλ¬Έ.
271
271
 
272
272
  λ£°:
273
- 1. λ³€κ²½ μš”μ²­ β†’ write tool 호좜 ν•„μˆ˜ (modifyBoard / setFill / setStroke / setMaterial /
273
+ 1. λ³€κ²½ μš”μ²­ β†’ write tool 호좜 ν•„μˆ˜ (modifyScene / setFill / setStroke / setMaterial /
274
274
  setShadow / setOpacity / setVisible / setFont / setText / setMaterial / addComponent /
275
275
  removeComponentByRefid / modifyComponentByRefid / align/distribute/group/zorder λ“±)
276
276
  2. 호좜 + 짧은 reply ν…μŠ€νŠΈ λ™μ‹œ μž‘μ„± OK β€” reply λŠ” *κ²°κ³Ό* λ₯Ό ν•œκ΅­μ–΄λ‘œ ν•œλ‘ λ¬Έμž₯ μš”μ•½
@@ -294,22 +294,22 @@ root-level properties separate from any child:
294
294
  - 3D ν™˜κ²½: \`sky\` / \`skyColor\` / \`exposure\` / \`hemi*\` / \`dirLight*\` / \`dirShadow*\` / \`camera*\` / \`autoRotate\`
295
295
  - 식별: \`id\`, \`refid\`, \`type\` ("model-layer")
296
296
  ⚠ λ³΄λ“œ \*\*name\*\* 은 root attribute κ°€ μ•„λ‹˜ β€” Board μ—”ν‹°ν‹°μ˜ DB μ»¬λŸΌμ΄μ§€ scene
297
- MODEL 의 ν•„λ“œκ°€ μ•„λ‹˜ (model-layer κ°€ λ¬΄μ‹œ). λ³΄λ“œ 라벨 변경은 modifyBoard μ˜μ—­ X.
297
+ MODEL 의 ν•„λ“œκ°€ μ•„λ‹˜ (model-layer κ°€ λ¬΄μ‹œ). λ³΄λ“œ 라벨 변경은 modifyScene μ˜μ—­ X.
298
298
  β€’ Children: an array of components inside the board (rect / circle / text /
299
299
  gauge / etc.). μ»΄ν¬λ„ŒνŠΈλ“€μ€ \`name\` (user label) λ₯Ό κ°€μ§ˆ 수 있음 β€” μ΄λŠ” child
300
300
  component 의 속성이지 board root 의 속성이 μ•„λ‹˜.
301
301
 
302
302
  Rules:
303
303
  - To change a board-level attribute (background, board size, 3D atmosphere)
304
- β†’ call \`modifyBoard({ patch: { fillStyle: ..., width: ..., sky: ..., exposure: ..., dirLight*: ..., hemi*: ... } })\`.
304
+ β†’ call \`modifyScene({ patch: { fillStyle: ..., width: ..., sky: ..., exposure: ..., dirLight*: ..., hemi*: ... } })\`.
305
305
  NOTE: λ³΄λ“œ 라벨/제λͺ© ("λ³΄λ“œ 이름") 은 scene model 이 μ•„λ‹ˆλΌ Board *μ—”ν‹°ν‹°* 의 컬럼.
306
- things-scene 의 model-layer λŠ” \`name\` 을 μΈμ‹ν•˜μ§€ μ•ŠμŒ. modifyBoard 의 patch 에
306
+ things-scene 의 model-layer λŠ” \`name\` 을 μΈμ‹ν•˜μ§€ μ•ŠμŒ. modifyScene 의 patch 에
307
307
  \`name\` 을 λ„£μ§€ 말 것 β€” 죽은 ν•„λ“œλ‘œ λ°•νž 뿐 효과 μ—†μŒ.
308
308
  - To change a CHILD COMPONENT's attribute β†’ call \`modifyComponentByRefid\`.
309
- - DO NOT use modifyBoard to change a child. DO NOT use modifyComponentByRefid
309
+ - DO NOT use modifyScene to change a child. DO NOT use modifyComponentByRefid
310
310
  to change board background.
311
311
  - "λ³΄λ“œ 배경색", "board background", "ν…Œλ‘λ¦¬/μΊ”λ²„μŠ€ 크기" 같은 μš”μ²­μ€ root
312
- attribute λ³€κ²½ β†’ \`modifyBoard\`.
312
+ attribute λ³€κ²½ β†’ \`modifyScene\`.
313
313
 
314
314
  ==== COMPONENT TREE (NESTING) ====
315
315
  μ»΄ν¬λ„ŒνŠΈλŠ” *μž¬κ·€ ꡬ쑰*. group / container 같은 λΆ€λͺ¨ μ»΄ν¬λ„ŒνŠΈλŠ” 자기 \`components\`
@@ -375,8 +375,8 @@ to that wording in your reply. Do not echo refid back to the user.
375
375
 
376
376
  ==== AVAILABLE TOOLS ====
377
377
  Board-level (root attributes):
378
- - 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 μ—”ν‹°ν‹° 컬럼.
379
- - replaceBoard: wholesale board reset (heavy β€” prefer modifyBoard for most changes)
378
+ - 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 μ—”ν‹°ν‹° 컬럼.
379
+ - replaceBoard: wholesale board reset (heavy β€” prefer modifyScene for most changes)
380
380
  Child components β€” data:
381
381
  - addComponent: add a new component (parallel calls for multiple adds)
382
382
  - removeComponentByRefid: remove a child by refid
@@ -433,10 +433,10 @@ Modeller actions (ephemeral β€” does NOT modify the board model, no undo, no sav
433
433
  - fitToView: reset view so the board fits the canvas (mode: fit/ratio/width/height)
434
434
  - setSceneMode: switch modeller between 'edit' and 'view' modes
435
435
  Knowledge:
436
- - 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.
436
+ - 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.
437
437
 
438
438
  ==== 3D ATMOSPHERE SYNTHESIS ====
439
- 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.
439
+ 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.
440
440
 
441
441
  For ANY natural-language atmospheric request β€” "곡μž₯ λΆ„μœ„κΈ°λ‘œ", "심해 컬러", "ν™©ν˜Ό", "μ‚¬μ΄λ²„νŽ‘ν¬", "μ•ˆκ°œ μžμš±ν•œ μƒˆλ²½", "1980 μš°μ£Όμ •κ±°μž₯", "λ”°λœ»ν•˜κ²Œ", "μ°¨κ°‘κ³  극적으둜" β€” follow this workflow:
442
442
 
@@ -444,11 +444,11 @@ For ANY natural-language atmospheric request β€” "곡μž₯ λΆ„μœ„κΈ°λ‘œ", "심해
444
444
  2. From the guide's "archetypes" section, pick the closest base recipe (time-of-day / indoor / surreal). Interpolate if user combines multiple cues.
445
445
  3. Apply user's nuance via the guide's "modifiers" (warm/cool, drama, saturation, contrast).
446
446
  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.
447
- 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.
447
+ 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.
448
448
  6. In the reply, briefly state which archetype + modifier you composed.
449
449
 
450
450
  Avoid:
451
- - Calling modifyBoard with only "fillStyle" for atmospheric requests β€” that only changes 2D background and floor tint, NOT the 3D scene mood.
451
+ - Calling modifyScene with only "fillStyle" for atmospheric requests β€” that only changes 2D background and floor tint, NOT the 3D scene mood.
452
452
  - Mixing a sky preset with explicit skyColor (preset wins, skyColor ignored).
453
453
  - Setting dirLightAzimuth/Elevation while leaving dirLightFollowCamera=true (no effect β€” set follow=false first).
454
454
  - Using only canned presets when the user describes a custom mood β€” the guide enables synthesis beyond presets.
@@ -633,7 +633,7 @@ export function buildBoardEditTools(knownTypes, exposure = {}) {
633
633
  }
634
634
  },
635
635
  {
636
- name: 'modifyBoard',
636
+ name: 'modifyScene',
637
637
  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.",
638
638
  parameters: {
639
639
  type: 'object',
@@ -649,7 +649,7 @@ export function buildBoardEditTools(knownTypes, exposure = {}) {
649
649
  },
650
650
  {
651
651
  name: 'replaceBoard',
652
- 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.',
652
+ 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.',
653
653
  parameters: {
654
654
  type: 'object',
655
655
  properties: {
@@ -718,7 +718,7 @@ export function buildBoardEditTools(knownTypes, exposure = {}) {
718
718
  },
719
719
  {
720
720
  name: 'getAtmosphereGuide',
721
- 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.",
721
+ 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.",
722
722
  parameters: { type: 'object', properties: {} }
723
723
  },
724
724
  {
@@ -1050,7 +1050,7 @@ const WRITE_TOOL_NAMES = new Set([
1050
1050
  'setShadowProperties',
1051
1051
  'clearStyle',
1052
1052
  'copyStyle',
1053
- 'modifyBoard',
1053
+ 'modifyScene',
1054
1054
  'replaceBoard',
1055
1055
  // Phase 2 β€” model 차원 scene μ‘°μž‘ (μ’Œν‘œ/ꡬ쑰/zorder)
1056
1056
  'alignComponents',
@@ -1067,7 +1067,7 @@ const WRITE_TOOL_NAMES = new Set([
1067
1067
  ]);
1068
1068
  /**
1069
1069
  * C-1 β€” ephemeral scene μ‘°μž‘ (selection / view / mode). model λ³€κ²½ X, undo 영ν–₯ X.
1070
- * 별도 ChatResponse.actions μ±„λ„λ‘œ 전달 β†’ ν˜ΈμŠ€νŠΈκ°€ board-action-execute 둜 적용.
1070
+ * 별도 ChatResponse.actions μ±„λ„λ‘œ 전달 β†’ ν˜ΈμŠ€νŠΈκ°€ scene-action-execute 둜 적용.
1071
1071
  */
1072
1072
  const ACTION_TOOL_NAMES = new Set([
1073
1073
  'selectComponents',
@@ -1204,13 +1204,13 @@ export function executeReadTool(call, currentBoard, selectedRefids) {
1204
1204
  *
1205
1205
  * μ˜λ„ β€” preset ν•œ λ‹¨μ–΄λ‘œ λλ‚˜μ§€ μ•ŠλŠ” μ‚¬μš©μž μš”μ²­ ("심해", "ν™©ν˜Ό", "1980 μš°μ£Όμ •κ±°μž₯",
1206
1206
  * "μ•ˆκ°œ μƒˆλ²½") 에 AI κ°€ ꡬ체적 νŒŒλΌλ―Έν„° 값을 직접 ν•©μ„±ν•˜λ„λ‘ 물리/색채/λ―Έν•™ 지식
1207
- * λ™μ‹œ 제곡. AI λŠ” 이 κ°€μ΄λ“œλ₯Ό 받은 λ’€ modifyBoard 둜 ν•œ λ²ˆμ— 적용.
1207
+ * λ™μ‹œ 제곡. AI λŠ” 이 κ°€μ΄λ“œλ₯Ό 받은 λ’€ modifyScene 둜 ν•œ λ²ˆμ— 적용.
1208
1208
  *
1209
- * things-scene 의 board model 에 λ“€μ–΄κ°€λŠ” root level ν‚€λ§Œ λ‹€λ£Έ (modifyBoard 둜
1209
+ * things-scene 의 board model 에 λ“€μ–΄κ°€λŠ” root level ν‚€λ§Œ λ‹€λ£Έ (modifyScene 둜
1210
1210
  * 적용 κ°€λŠ₯ν•œ 것). camera position 같은 ephemeral ν•œ 것은 별도 μ˜μ—­.
1211
1211
  */
1212
1212
  const ATMOSPHERE_GUIDE = {
1213
- 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.',
1213
+ 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.',
1214
1214
  parameters: {
1215
1215
  sky: {
1216
1216
  description: '3D λ°°κ²½ + IBL (image-based lighting) 의 source. preset / "color" / "" μ…‹ 쀑 ν•˜λ‚˜.',
@@ -1535,7 +1535,7 @@ const ATMOSPHERE_GUIDE = {
1535
1535
  '2. archetypes μ—μ„œ κ°€μž₯ κ°€κΉŒμš΄ base λ ˆμ‹œν”Ό 선택.',
1536
1536
  '3. modifiers 둜 μ‚¬μš©μž μš”μ²­ λ‰˜μ•™μŠ€ fine-tune (warm/cool/drama/...).',
1537
1537
  '4. sanity check β€” exposure Γ— hemi Γ— dir μ–΄λŠ ν•œμͺ½ 극단 μ•„λ‹Œμ§€, hemi sky/ground 색 λͺ¨μˆœ μ—†λŠ”μ§€.',
1538
- "5. modifyBoard({ patch: { ...combined keys... } }) ν•œ λ²ˆμ— 적용. μ‚¬μš©μžμ—κ²Œ μ–΄λ–€ archetype + modifier μ‘°ν•©μœΌλ‘œ κ°”λŠ”μ§€ ν•œ μ€„λ‘œ μ„€λͺ…."
1538
+ "5. modifyScene({ patch: { ...combined keys... } }) ν•œ λ²ˆμ— 적용. μ‚¬μš©μžμ—κ²Œ μ–΄λ–€ archetype + modifier μ‘°ν•©μœΌλ‘œ κ°”λŠ”μ§€ ν•œ μ€„λ‘œ μ„€λͺ…."
1539
1539
  ],
1540
1540
  pitfalls: [
1541
1541
  'sky preset μœ„μ— skyColor 같이 μ§€μ •ν•˜λ©΄ preset 이 μš°μ„  (skyColor λ¬΄μ‹œ).',
@@ -1555,7 +1555,7 @@ const ATMOSPHERE_GUIDE = {
1555
1555
  * μ‚¬μš© 흐름:
1556
1556
  * 1. μ‚¬μš©μž μ˜λ„ (μ‚°μ—… / 금육 / 의료 / SF / ...) 식별
1557
1557
  * 2. recommendations μ—μ„œ λ§€μΉ­ 후보 1~2개 μΆ”λ¦Ό
1558
- * 3. modifyBoard 둜 board.fillStyle 을 palette.base 둜 μ„€μ •
1558
+ * 3. modifyScene 둜 board.fillStyle 을 palette.base 둜 μ„€μ •
1559
1559
  * 4. addPrefab / addComponent μ‹œ palette 의 surface/accent/text μ‚¬μš©
1560
1560
  * 5. μΌκ΄€λœ 룩 β†’ ν•œ 번 μ •ν•œ νŒ”λ ˆνŠΈ μ•ˆμ—μ„œλ§Œ 색 선택
1561
1561
  *
@@ -1682,7 +1682,7 @@ const COLOR_PALETTES = {
1682
1682
  workflow: [
1683
1683
  '1. μ‚¬μš©μž 도메인 / λΆ„μœ„κΈ° ν‚€μ›Œλ“œ 식별 β€” μ‚°μ—…/금육/κ΄€μ œ/의료/SF/ν”„λ ˆμ  ν…Œμ΄μ…˜',
1684
1684
  '2. recommendations μ—μ„œ λ§€μΉ­ 후보 μΆ”λ¦Ό. μ‚¬μš©μž λͺ¨ν˜Έν•˜λ©΄ κ°€μž₯ ν”ν•œ industrial-steel λ””ν΄νŠΈ.',
1685
- "3. modifyBoard({ patch: { fillStyle: palette.base } }) 으둜 λ³΄λ“œ λ°°κ²½ set.",
1685
+ "3. modifyScene({ patch: { fillStyle: palette.base } }) 으둜 λ³΄λ“œ λ°°κ²½ set.",
1686
1686
  '4. 이후 λͺ¨λ“  add / addPrefab 호좜 μ‹œ palette.surface / accent / text / border μ‚¬μš©. 자유 색 X.',
1687
1687
  '5. status ν‘œμ‹œλŠ” success / warning / danger / info 4μ’…μ—μ„œλ§Œ β€” 자체 hex λ§Œλ“€μ§€ 마라.'
1688
1688
  ],
@@ -1867,10 +1867,10 @@ function buildExternalCategoryDefinitions(filter) {
1867
1867
  }));
1868
1868
  }
1869
1869
  /**
1870
- * Tool call β†’ BoardActionOp λ³€ν™˜ (C-1 ephemeral scene μ‘°μž‘).
1870
+ * Tool call β†’ SceneActionOp λ³€ν™˜ (C-1 ephemeral scene μ‘°μž‘).
1871
1871
  * 잘λͺ»λœ μΈμžλŠ” null β€” agentic loop κ°€ Unknown tool λΉ„μŠ·ν•˜κ²Œ 처리.
1872
1872
  */
1873
- export function toolCallToBoardActionOp(tc, gate = buildToolGate()) {
1873
+ export function toolCallToSceneActionOp(tc, gate = buildToolGate()) {
1874
1874
  const args = tc.arguments ?? {};
1875
1875
  /* 씬 μ‘°μž‘ μ•‘μ…˜μ€ μ „λΆ€ μ½”μ–΄(λ³΄λ“œ) λŠ₯λ ₯ β€” λ…ΈμΆœ μ•ˆ 된 λŒ€ν™”μ—μ„œλŠ” λ§Œλ“€μ§€ μ•ŠλŠ”λ‹€.
1876
1876
  * loop λŠ” gate.isAction 으둜 이미 κ±ΈλŸ¬λ‚΄μ§€λ§Œ, λ‹€λ₯Έ ν˜ΈμΆœλΆ€μ˜ μ˜€μš©λ„ λ§‰λŠ”λ‹€. */
@@ -1907,7 +1907,7 @@ export function toolCallToBoardActionOp(tc, gate = buildToolGate()) {
1907
1907
  return null;
1908
1908
  }
1909
1909
  }
1910
- // ── Tool call β†’ BoardEditOp λ³€ν™˜ ───────────────────────────────────
1910
+ // ── Tool call β†’ SceneEditOp λ³€ν™˜ ───────────────────────────────────
1911
1911
  /**
1912
1912
  * AIToolChatResult β†’ ChatResponse.
1913
1913
  *
@@ -1919,7 +1919,7 @@ export function toolCallToBoardActionOp(tc, gate = buildToolGate()) {
1919
1919
  export function toolResultToChatResponse(result) {
1920
1920
  const ops = result.toolCalls
1921
1921
  .flatMap(call => {
1922
- const r = toolCallToBoardEditOp(call);
1922
+ const r = toolCallToSceneEditOp(call);
1923
1923
  if (r === null)
1924
1924
  return [];
1925
1925
  return Array.isArray(r) ? r : [r];
@@ -1935,7 +1935,7 @@ export function toolResultToChatResponse(result) {
1935
1935
  }
1936
1936
  return { reply, patch, followUp: undefined };
1937
1937
  }
1938
- export function toolCallToBoardEditOp(tc, components = [], gate = buildToolGate()) {
1938
+ export function toolCallToSceneEditOp(tc, components = [], gate = buildToolGate()) {
1939
1939
  const args = tc.arguments ?? {};
1940
1940
  /* λ…ΈμΆœλ˜μ§€ μ•Šμ€ μ½”μ–΄(λ³΄λ“œ νŽΈμ§‘) λ„κ΅¬λŠ” op λ₯Ό λ§Œλ“€μ§€ μ•ŠλŠ”λ‹€ β€” μ •μ˜λ₯Ό μˆ¨κ²Όμ–΄λ„ ν˜ΈμΆœμ€ 올 수 μžˆλ‹€. */
1941
1941
  if (!gate.coreOn && !gate.spec(tc.name))
@@ -1948,7 +1948,7 @@ export function toolCallToBoardEditOp(tc, components = [], gate = buildToolGate(
1948
1948
  return dispatchStylingTool(tc.name, args, components);
1949
1949
  }
1950
1950
  // tool-registry plugin point β€” μ™ΈλΆ€ 등둝 'write' μΉ΄ν…Œκ³ λ¦¬ dispatch.
1951
- // builder κ²°κ³ΌλŠ” BoardEditOp[] | { ops, errors? } | null μ…‹ 쀑 ν•˜λ‚˜.
1951
+ // builder κ²°κ³ΌλŠ” SceneEditOp[] | { ops, errors? } | null μ…‹ 쀑 ν•˜λ‚˜.
1952
1952
  // (read/external μΉ΄ν…Œκ³ λ¦¬λŠ” 별도 dispatch path β€” agentic loop 의 executeReadTool 이 직접 처리.)
1953
1953
  const registrySpec = gate.spec(tc.name);
1954
1954
  if (registrySpec && registrySpec.kind === 'write') {
@@ -1980,17 +1980,17 @@ export function toolCallToBoardEditOp(tc, components = [], gate = buildToolGate(
1980
1980
  // λͺ¨λ“  styling tool (setFill/setStroke/setText/setFont/setShadow/setOpacity/
1981
1981
  // setVisible/setMaterial/setShadowProperties/clearStyle/copyStyle) 은 registry
1982
1982
  // κ°€ 처리 β€” 상단 isStylingTool λΆ„κΈ° μ°Έμ‘°
1983
- case 'modifyBoard': {
1983
+ case 'modifyScene': {
1984
1984
  if (!args.patch || typeof args.patch !== 'object' || Array.isArray(args.patch))
1985
1985
  return null;
1986
- return { op: 'modifyBoard', patch: args.patch };
1986
+ return { op: 'modifyScene', patch: args.patch };
1987
1987
  }
1988
1988
  case 'replaceBoard': {
1989
1989
  if (!Array.isArray(args.components))
1990
1990
  return null;
1991
1991
  return {
1992
1992
  op: 'replace',
1993
- board: {
1993
+ model: {
1994
1994
  width: typeof args.width === 'number' ? args.width : undefined,
1995
1995
  height: typeof args.height === 'number' ? args.height : undefined,
1996
1996
  fillStyle: typeof args.fillStyle === 'string' ? args.fillStyle : undefined,