Skip to content

refactor: プラグイン設定キー名をcamelCaseに統一#122

Open
oboroge0 wants to merge 2 commits intomainfrom
refactor/unify-config-naming
Open

refactor: プラグイン設定キー名をcamelCaseに統一#122
oboroge0 wants to merge 2 commits intomainfrom
refactor/unify-config-naming

Conversation

@oboroge0
Copy link
Copy Markdown
Owner

@oboroge0 oboroge0 commented Feb 26, 2026

概要

プラグインの manifest.json における設定キー名(config keys)がsnake_caseとcamelCaseで混在していた問題を修正し、JS/TSの慣例に合わせてcamelCaseに統一しました。

対象プラグイン(8プラグイン)

プラグイン 変更前(snake_case) 変更後(camelCase)
audio-player wait_for_completion, output_device waitForCompletion, outputDevice
avatar-configuration model_url, idle_animation, vtube_port, vtube_mouth_param, vtube_expression_map, png_config modelUrl, idleAnimation, vtubePort, vtubeMouthParam, vtubeExpressionMap, pngConfig
motion-trigger motion_url, emit_events motionUrl, emitEvents
lip-sync emit_realtime, frame_rate, mouth_values(出力) emitRealtime, frameRate, mouthValues
obs-source-toggle scene_name, source_name sceneName, sourceName
obs-scene-switch scene_name, current_scene(出力) sceneName, currentScene
emotion-analyzer custom_mappings, llm_provider, llm_api_key, llm_model, emit_events customMappings, llmProvider, llmApiKey, llmModel, emitEvents
subtitle-display font_size, font_color, background_color, show_speaker fontSize, fontColor, backgroundColor, showSpeaker

変更範囲

  • プラグイン: 8プラグインの manifest.jsonnode.ts
  • フロントエンド: NodeSettings.tsx, Canvas.tsx, overlay/editor/preview の client-page.tsx, useWebSocket.ts
  • サーバー: executor.ts(VTube Studio設定読み取り)
  • テンプレート: 全7テンプレートJSON
  • ドキュメント: api-reference.md, api-reference.ja.md

テスト計画

  • 全95テストがパス(npm test
  • エディターでノードの設定パネルが正しく表示・保存されること
  • オーバーレイでアバター表示・リップシンク・字幕が動作すること
  • テンプレートからワークフローを正しく作成できること

closes #104

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

Summary by CodeRabbit

  • Refactor
    • Standardized configuration field naming conventions from snake_case to camelCase across avatar configurations, node plugins, WebSocket event payloads, and template files. Updated corresponding internal references and API documentation to reflect the new naming format.

全プラグインのmanifest.jsonおよびnode.tsで、snake_caseの設定キー名を
JS/TSの慣例に合わせてcamelCaseに変更。

対象プラグイン:
- audio-player: wait_for_completion → waitForCompletion, output_device → outputDevice
- avatar-configuration: model_url → modelUrl, idle_animation → idleAnimation,
  vtube_port → vtubePort, vtube_mouth_param → vtubeMouthParam,
  vtube_expression_map → vtubeExpressionMap, png_config → pngConfig
- motion-trigger: motion_url → motionUrl, emit_events → emitEvents
- lip-sync: emit_realtime → emitRealtime, frame_rate → frameRate,
  mouth_values → mouthValues
- obs-source-toggle: scene_name → sceneName, source_name → sourceName
- obs-scene-switch: scene_name → sceneName, current_scene → currentScene
- emotion-analyzer: custom_mappings → customMappings, llm_provider → llmProvider,
  llm_api_key → llmApiKey, llm_model → llmModel, emit_events → emitEvents
- subtitle-display: font_size → fontSize, font_color → fontColor,
  background_color → backgroundColor, show_speaker → showSpeaker

フロントエンド、サーバー、テンプレート、ドキュメントも同期更新。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 26, 2026

Warning

Rate limit exceeded

@oboroge0 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 0 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 593ce4c and a5ecd40.

📒 Files selected for processing (14)
  • apps/server-ts/src/engine/executor.ts
  • apps/web/app/(editor)/editor/[id]/client-page.tsx
  • apps/web/app/(editor)/preview/[id]/client-page.tsx
  • apps/web/app/(overlay)/overlay/[id]/client-page.tsx
  • apps/web/components/panels/NodeSettings.tsx
  • plugins/audio-player/node.ts
  • plugins/avatar-configuration/node.ts
  • plugins/emotion-analyzer/node.ts
  • plugins/lip-sync/node.ts
  • plugins/motion-trigger/manifest.json
  • plugins/motion-trigger/node.ts
  • plugins/obs-scene-switch/node.ts
  • plugins/obs-source-toggle/node.ts
  • plugins/subtitle-display/node.ts
📝 Walkthrough

Walkthrough

This PR standardizes configuration field naming conventions across the entire codebase from snake_case to camelCase, aligning with JavaScript/TypeScript conventions. Changes affect plugin manifests, node implementations, web editor components, WebSocket event payloads, documentation, and example templates. No new functionality is introduced.

Changes

Cohort / File(s) Summary
Plugin Avatar Configuration
plugins/avatar-configuration/manifest.json, plugins/avatar-configuration/node.ts
Renames avatar config keys: model_urlmodelUrl, idle_animationidleAnimation, vtube_portvtubePort, vtube_mouth_paramvtubeMouthParam, vtube_expression_mapvtubeExpressionMap, png_configpngConfig. Updates manifest schema and node setup/event payload accordingly.
Plugin Emotion Analyzer
plugins/emotion-analyzer/manifest.json, plugins/emotion-analyzer/node.ts
Renames config keys: custom_mappingscustomMappings, llm_providerllmProvider, llm_api_keyllmApiKey, llm_modelllmModel, emit_eventsemitEvents. Updates dependsOn references to match new camelCase naming.
Plugin Lip Sync
plugins/lip-sync/manifest.json, plugins/lip-sync/node.ts
Renames output and config keys: mouth_valuesmouthValues, emit_realtimeemitRealtime, frame_rateframeRate. Updates manifest with numeric constraints (frameRate: default 30, min 10, max 60) and node payload references.
Plugin Motion Trigger
plugins/motion-trigger/manifest.json, plugins/motion-trigger/node.ts
Renames node input and config keys: motion_urlmotionUrl, emit_eventsemitEvents. Adds .fbx file accept attribute. Updates execute return payload and emitted event payload.
Plugin OBS Scene Switch
plugins/obs-scene-switch/manifest.json, plugins/obs-scene-switch/node.ts
Renames input/output/config IDs: scene_namesceneName, current_scenecurrentScene. Updates error and success return payloads with fallback logic for scene fetch.
Plugin OBS Source Toggle
plugins/obs-source-toggle/manifest.json, plugins/obs-source-toggle/node.ts
Renames config and output keys: scene_namesceneName, source_namesourceName. Updates all response payloads and config initialization references.
Plugin Subtitle Display
plugins/subtitle-display/manifest.json, plugins/subtitle-display/node.ts
Renames config keys: font_sizefontSize, font_colorfontColor, background_colorbackgroundColor, show_speakershowSpeaker. Updates manifest and node setup accordingly.
Plugin Audio Player
plugins/audio-player/manifest.json, plugins/audio-player/node.ts
Renames config keys: wait_for_completionwaitForCompletion, output_deviceoutputDevice. Manifest adds default value for waitForCompletion (true).
Web Editor & Preview Components
apps/web/app/(editor)/editor/[id]/client-page.tsx, apps/web/app/(editor)/preview/[id]/client-page.tsx, apps/web/components/editor/Canvas.tsx, apps/web/components/panels/NodeSettings.tsx
Updates component references to camelCase keys across avatar configuration extraction, node port definitions, and form field mappings. Changes output port IDs and internal field lookups to match renamed configuration.
Web Overlay & Hooks
apps/web/app/(overlay)/overlay/[id]/client-page.tsx, apps/web/hooks/useWebSocket.ts
Renames avatar config parsing and WebSocket event handling to use camelCase keys. Updates motion event payload references from motion_url to motionUrl with corresponding fallback logic.
Server Engine
apps/server-ts/src/engine/executor.ts
Renames avatar configuration field lookups: vtube_portvtubePort, vtube_mouth_paramvtubeMouthParam, vtube_expression_mapvtubeExpressionMap. Updates parsing behavior to use new field names.
API Documentation
docs/api-reference.md, docs/api-reference.ja.md
Updates WebSocket avatar.motion event example: motion_urlmotionUrl in payload schema documentation.
Example Templates
templates/discord-bot.json, templates/simple-vtuber.json, templates/streaming-vtuber.json, templates/twitch-vtuber.json, templates/voice-chatbot.json, templates/vtube-studio-vtuber.json, templates/youtube-vtuber.json
Converts all node configuration keys from snake_case to camelCase across avatar, audio-player, emotion-analyzer, lip-sync, and subtitle-display node configs. Maintains all values unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • #93: Updates manifest-driven and dynamic config rendering that operates on the same camelCase config fields being renamed in this PR across plugin manifests and editor components.
  • #42: Modifies Canvas/Sidebar port handling and plugin-driven input/output definitions; directly intersects with port ID renaming (e.g., motion_urlmotionUrl, mouth_valuesmouthValues) in this PR.
  • #22: VTube Studio integration changes that correspond to this PR's renaming of VTube-related config fields (vtube_port, vtube_mouth_param, vtube_expression_map) and avatar overlay wiring.

Poem

🐰 Hops with glee through camelCase dreams,
Where snake_case vanished in refactoring streams,
Config keys dancing in consistent delight,
JavaScript conventions shining so bright!
One naming to rule them all—what a sight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly describes the main objective: unifying plugin configuration key names to camelCase. It accurately reflects the primary refactoring effort across the codebase.
Linked Issues check ✅ Passed The PR comprehensively implements all coding requirements from issue #104: converting all plugin config keys from snake_case to camelCase across manifest files, node implementations, frontend components, backend services, templates, and documentation.
Out of Scope Changes check ✅ Passed All changes are directly related to the stated objective of unifying configuration key naming. Updates span plugins, frontend, backend, templates, and documentation—all necessary to complete the refactoring consistently throughout the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/unify-config-naming

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@oboroge0
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 26, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@oboroge0
Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 26, 2026

✅ Actions performed

Full review triggered.

@oboroge0
Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 26, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
plugins/obs-scene-switch/node.ts (1)

28-29: ⚠️ Potential issue | 🟠 Major

Use typed config/input/output contracts instead of Record<string, any>.

Method signatures at lines 28, 56-59 use Record<string, any>, which prevents compile-time type safety. Define explicit interfaces matching manifest types to catch key mismatches at compile time.

Proposed typing refactor
+type OBSSceneSwitchConfig = {
+  host?: string;
+  port?: number;
+  password?: string;
+  sceneName?: string;
+};
+
+type OBSSceneSwitchInputs = {
+  sceneName?: string;
+};
+
+type OBSSceneSwitchResult = {
+  success: boolean;
+  currentScene: string;
+  scenes: string[];
+};
...
-  async setup(config: Record<string, any>, context: NodeContext): Promise<void> {
+  async setup(config: OBSSceneSwitchConfig, context: NodeContext): Promise<void> {
...
-  async execute(
-    inputs: Record<string, any>,
-    context: NodeContext,
-  ): Promise<Record<string, any>> {
+  async execute(
+    inputs: OBSSceneSwitchInputs,
+    context: NodeContext,
+  ): Promise<OBSSceneSwitchResult> {

Per coding guidelines, **/*.ts: Use TypeScript type safety - match manifest types with TypeScript implementations for config, inputs, and outputs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/obs-scene-switch/node.ts` around lines 28 - 29, The setup and other
method signatures (e.g., setup, plus the methods around lines 56-59) currently
use Record<string, any>, losing compile-time type safety; define TypeScript
interfaces that reflect the plugin manifest's config, input and output contracts
(e.g., ObsSceneSwitchConfig, ObsSceneSwitchInputs, ObsSceneSwitchOutputs) and
replace Record<string, any> in the signatures for setup and any input/output
handlers with these explicit types so the compiler enforces correct keys and
value types across the plugin implementation.
apps/web/components/panels/NodeSettings.tsx (1)

1212-1660: ⚠️ Potential issue | 🟠 Major

Renamed field keys need a legacy-config normalization step in the editor.

After this rename, old workflow configs still containing snake_case keys won’t bind to the new fields, so users can open a node, see defaults, and accidentally overwrite valid previous values on save.

💡 Suggested compatibility normalization (apply when loading selected node config)
+const LEGACY_KEY_MAP: Record<string, Record<string, string>> = {
+  "avatar-configuration": {
+    model_url: "modelUrl",
+    idle_animation: "idleAnimation",
+    vtube_port: "vtubePort",
+    png_config: "pngConfig",
+  },
+  "motion-trigger": { motion_url: "motionUrl", emit_events: "emitEvents" },
+  "emotion-analyzer": {
+    llm_provider: "llmProvider",
+    llm_api_key: "llmApiKey",
+    llm_model: "llmModel",
+    custom_mappings: "customMappings",
+    emit_events: "emitEvents",
+  },
+  "lip-sync": { emit_realtime: "emitRealtime", frame_rate: "frameRate" },
+  "audio-player": {
+    output_device: "outputDevice",
+    wait_for_completion: "waitForCompletion",
+  },
+  "subtitle-display": {
+    font_size: "fontSize",
+    font_color: "fontColor",
+    background_color: "backgroundColor",
+    show_speaker: "showSpeaker",
+  },
+  "obs-scene-switch": { scene_name: "sceneName" },
+  "obs-source-toggle": { scene_name: "sceneName", source_name: "sourceName" },
+};
+
+const normalizeLegacyConfig = (nodeType: string, config: Record<string, unknown>) => {
+  const map = LEGACY_KEY_MAP[nodeType] ?? {};
+  const normalized = { ...config };
+  for (const [legacyKey, newKey] of Object.entries(map)) {
+    if (normalized[newKey] === undefined && normalized[legacyKey] !== undefined) {
+      normalized[newKey] = normalized[legacyKey];
+    }
+  }
+  return normalized;
+};

Then use it where localConfig is initialized from selectedNode.config.

Also applies to: 1878-1881, 1952-1954

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/components/panels/NodeSettings.tsx` around lines 1212 - 1660,
SelectedNode rename broke binding for older snake_case keys: when initializing
localConfig from selectedNode.config you must normalize legacy keys (e.g.,
model_url -> modelUrl, idle_animation -> idleAnimation, vtube_port -> vtubePort,
png_config -> pngConfig, auto_emotion -> auto_emotion -> auto_emotion? map to
auto_emotion -> auto_emotion? — map snake_case to their camelCase equivalents
used in the fields) so old configs don't get overwritten; implement a small
normalization helper called (for example) normalizeLegacyConfig and call it
where localConfig is created from selectedNode.config (refer to selectedNode and
localConfig in the editor component) to copy/translate snake_case keys to the
new camelCase field keys before using them.
plugins/motion-trigger/manifest.json (1)

79-83: ⚠️ Potential issue | 🟡 Minor

Update legacy config description text to match new key naming.

The motion description still says use motion_url instead, which is outdated after the rename to motionUrl.

✏️ Suggested text fix
-      "description": "Motion/animation name to trigger (use motion_url instead)",
+      "description": "Motion/animation name to trigger (use motionUrl instead)",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/motion-trigger/manifest.json` around lines 79 - 83, The manifest
entry for the "motion" config option still instructs users to "use motion_url
instead"; update the description for the "motion" key in manifest.json to
reference the new camelCase key name ("motionUrl") — e.g., change the text "use
motion_url instead" to "use motionUrl instead" while keeping the rest of the
description intact so it reflects the new key naming.
🧹 Nitpick comments (3)
plugins/motion-trigger/node.ts (2)

60-60: Stale comment: update motion_url to motionUrl.

📝 Suggested fix
-      // Emit motion event if configured (motion_url takes priority)
+      // Emit motion event if configured (motionUrl takes priority)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/motion-trigger/node.ts` at line 60, The inline comment is stale:
replace the snake_case reference `motion_url` with the code's actual camelCase
name `motionUrl` so the comment matches the implementation; update the comment
near the motion emission logic (the line mentioning motion_url) to reference
`motionUrl` and ensure any surrounding comments consistently use `motionUrl`.

5-5: Stale documentation: update emit_events to emitEvents.

The doc comment still references emit_events (snake_case) but the config key is now emitEvents.

📝 Suggested fix
-* Can also emit events directly if emit_events is enabled.
+* Can also emit events directly if emitEvents is enabled.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/motion-trigger/node.ts` at line 5, Update the stale doc comment that
references the old config key `emit_events` to the current camelCase key
`emitEvents` in the plugins/motion-trigger/node.ts file; search for the doc
comment near the module/class or function that handles emitting events (look for
symbols like the motion trigger node class or its configuration usage, e.g.,
references to emitEvents in the code) and replace `emit_events` with
`emitEvents` so the documentation matches the actual config key.
apps/web/app/(overlay)/overlay/[id]/client-page.tsx (1)

228-251: Consider extracting only known fields instead of spreading rest into state.

Line 250 spreads the entire rest object into avatarState, which could introduce unexpected fields from the event payload into the component state. While this may be intentional for flexibility, it could lead to subtle bugs if the backend sends additional fields.

💡 Suggested fix to explicitly pick known fields
-            setAvatarState((prev) => ({ ...prev, ...rest }));
+            // Only apply known avatar state fields from the event
+            const { expression, mouthOpen, motion, lookAt } = rest;
+            setAvatarState((prev) => ({
+              ...prev,
+              ...(expression !== undefined && { expression }),
+              ...(mouthOpen !== undefined && { mouthOpen }),
+              ...(motion !== undefined && { motion }),
+              ...(lookAt !== undefined && { lookAt }),
+            }));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/`(overlay)/overlay/[id]/client-page.tsx around lines 228 - 251,
The handler for the 'avatar.update' event currently spreads the entire rest
object into state via setAvatarState((prev) => ({ ...prev, ...rest })); instead
extract and assign only the known fields (e.g., renderer, modelUrl,
idleAnimation/animationUrl, vtubePort, vtubeMouthParam, vtubeExpressionMap, plus
any other explicitly allowed keys) and merge those into prev to avoid injecting
unexpected properties; update the case block to build a whitelist object from
rest and pass that to setAvatarState instead of spreading rest directly, keeping
the existing setAvatarConfig logic as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/server-ts/src/engine/executor.ts`:
- Around line 311-316: The avatarConfig reads only camelCase keys (vtubePort,
vtubeMouthParam, vtubeExpressionMap) causing loss of existing snake_case
settings; update the resolution logic around avatarConfig (where port,
mouthParam, rawMap/expressionMap are set) to accept both camelCase and
snake_case keys (vtubePort or vtube_port, vtubeMouthParam or vtube_mouth_param,
vtubeExpressionMap or vtube_expression_map), prefer the camelCase value if
present but fall back to the snake_case equivalent, and coerce types
consistently (number for port, string for mouthParam,
object/Record<string,string> for expressionMap) so existing workflows remain
compatible.

In `@apps/web/app/`(editor)/editor/[id]/client-page.tsx:
- Around line 175-176: The editor preview now only reads camelCase keys and will
drop older snake_case values; update the avatar config reads so modelUrl and
animationUrl fall back to legacy keys: when resolving avatarNode?.config, check
avatarNode?.config?.modelUrl || avatarNode?.config?.model_url ||
DEFAULT_MODEL_URL for modelUrl, and avatarNode?.config?.idleAnimation ||
avatarNode?.config?.idle_animation for animationUrl (keep DEFAULT_MODEL_URL as
final fallback); change the assignments where modelUrl and animationUrl are set
to include these legacy-key fallbacks so existing saved workflows keep their
assets.

In `@apps/web/app/`(editor)/preview/[id]/client-page.tsx:
- Around line 108-115: The preview config only falls back to legacy snake_case
for modelUrl, causing old workflows to lose animationUrl, vtubePort, and
pngConfig; update the setAvatarConfig call (and any reads of avatarNode.config)
to use legacy fallbacks: use avatarNode.config.animationUrl ||
avatarNode.config.animation_url for animationUrl, avatarNode.config.vtubePort ||
avatarNode.config.vtube_port for vtubePort, and avatarNode.config.pngConfig ||
avatarNode.config.png_config for pngConfig (keeping the existing modelUrl/vrm
fallback logic intact).

In `@plugins/lip-sync/node.ts`:
- Around line 21-22: Ensure backward compatibility by accepting snake_case
config keys and emitting snake_case fields in outputs: when setting options,
read both emitRealtime and emit_realtime, and frameRate and frame_rate (e.g.,
replace the assignments around emitRealtime/frameRate to prefer camelCase but
fallback to snake_case); likewise when producing result payloads include both
mouthValues and mouth_values, emitRealtime and emit_realtime, frameRate and
frame_rate. Apply this aliasing consistently in the initialization code (where
emitRealtime and frameRate are set) and in all early/final return payloads
mentioned (the blocks around the other affected lines).

In `@plugins/obs-scene-switch/node.ts`:
- Line 40: Update configuration/read and output paths to support both camelCase
and snake_case keys: when initializing this.sceneName (currently using
config.sceneName) also fallback to config.scene_name if present; likewise,
wherever the code returns or emits currentScene, also populate/emit
current_scene (and accept current_scene when reading inputs) to preserve
compatibility. Search for assignments/returns referencing this.sceneName and the
output key currentScene and add symmetric handling for scene_name/current_scene
(read old key into the same variable, and emit both keys) so existing saved
workflows continue to work while you can deprecate the snake_case names later.

In `@plugins/obs-source-toggle/manifest.json`:
- Around line 44-48: Update the plugin to use camelCase keys everywhere: ensure
manifest.json defines "sourceName" and "sceneName", update the execute method to
return an object with sourceName (not source_name), and update the setup/init
code to read config.sceneName and config.sourceName; to avoid breaking existing
users, add fallback handling in your setup and execute call sites to accept
snake_case inputs (config.source_name/config.scene_name) and map them to the
camelCase variables used by functions like setup and execute.

In `@plugins/obs-source-toggle/node.ts`:
- Around line 42-43: The constructor and all output-return locations currently
only use camelCase config keys and return values (this.sceneName,
this.sourceName, config.sceneName, config.sourceName), which breaks older
configs using snake_case; update the constructor to read legacy keys
(config.scene_name ?? config.sceneName ?? "" and config.source_name ??
config.sourceName ?? ""), and update every execute/return path that emits
sourceName to also include the snake_case aliases in the returned object (emit
both sourceName and source_name, and sceneName and scene_name where applicable)
so existing workflows remain compatible; apply the same alias pattern to the
other return paths referenced (lines around 65-66, 76-77, 82-83, 101-102,
137-141).

In `@plugins/subtitle-display/node.ts`:
- Around line 23-26: The current setup only reads camelCase config keys
(this.fontSize, this.fontColor, this.backgroundColor, this.showSpeaker) and will
ignore older snake_case keys; update the initialization to check camelCase
first, then fall back to snake_case (font_size, font_color, background_color,
show_speaker) before using the default values so existing saved configs are
respected; implement this logic within the same setup/constructor block where
config is read so the precedence is: config.fontSize || config.font_size ||
default, and similarly for fontColor/font_color,
backgroundColor/background_color, and showSpeaker/show_speaker.

---

Outside diff comments:
In `@apps/web/components/panels/NodeSettings.tsx`:
- Around line 1212-1660: SelectedNode rename broke binding for older snake_case
keys: when initializing localConfig from selectedNode.config you must normalize
legacy keys (e.g., model_url -> modelUrl, idle_animation -> idleAnimation,
vtube_port -> vtubePort, png_config -> pngConfig, auto_emotion -> auto_emotion
-> auto_emotion? map to auto_emotion -> auto_emotion? — map snake_case to their
camelCase equivalents used in the fields) so old configs don't get overwritten;
implement a small normalization helper called (for example)
normalizeLegacyConfig and call it where localConfig is created from
selectedNode.config (refer to selectedNode and localConfig in the editor
component) to copy/translate snake_case keys to the new camelCase field keys
before using them.

In `@plugins/motion-trigger/manifest.json`:
- Around line 79-83: The manifest entry for the "motion" config option still
instructs users to "use motion_url instead"; update the description for the
"motion" key in manifest.json to reference the new camelCase key name
("motionUrl") — e.g., change the text "use motion_url instead" to "use motionUrl
instead" while keeping the rest of the description intact so it reflects the new
key naming.

In `@plugins/obs-scene-switch/node.ts`:
- Around line 28-29: The setup and other method signatures (e.g., setup, plus
the methods around lines 56-59) currently use Record<string, any>, losing
compile-time type safety; define TypeScript interfaces that reflect the plugin
manifest's config, input and output contracts (e.g., ObsSceneSwitchConfig,
ObsSceneSwitchInputs, ObsSceneSwitchOutputs) and replace Record<string, any> in
the signatures for setup and any input/output handlers with these explicit types
so the compiler enforces correct keys and value types across the plugin
implementation.

---

Nitpick comments:
In `@apps/web/app/`(overlay)/overlay/[id]/client-page.tsx:
- Around line 228-251: The handler for the 'avatar.update' event currently
spreads the entire rest object into state via setAvatarState((prev) => ({
...prev, ...rest })); instead extract and assign only the known fields (e.g.,
renderer, modelUrl, idleAnimation/animationUrl, vtubePort, vtubeMouthParam,
vtubeExpressionMap, plus any other explicitly allowed keys) and merge those into
prev to avoid injecting unexpected properties; update the case block to build a
whitelist object from rest and pass that to setAvatarState instead of spreading
rest directly, keeping the existing setAvatarConfig logic as-is.

In `@plugins/motion-trigger/node.ts`:
- Line 60: The inline comment is stale: replace the snake_case reference
`motion_url` with the code's actual camelCase name `motionUrl` so the comment
matches the implementation; update the comment near the motion emission logic
(the line mentioning motion_url) to reference `motionUrl` and ensure any
surrounding comments consistently use `motionUrl`.
- Line 5: Update the stale doc comment that references the old config key
`emit_events` to the current camelCase key `emitEvents` in the
plugins/motion-trigger/node.ts file; search for the doc comment near the
module/class or function that handles emitting events (look for symbols like the
motion trigger node class or its configuration usage, e.g., references to
emitEvents in the code) and replace `emit_events` with `emitEvents` so the
documentation matches the actual config key.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4920ffd and 593ce4c.

📒 Files selected for processing (32)
  • apps/server-ts/src/engine/executor.ts
  • apps/web/app/(editor)/editor/[id]/client-page.tsx
  • apps/web/app/(editor)/preview/[id]/client-page.tsx
  • apps/web/app/(overlay)/overlay/[id]/client-page.tsx
  • apps/web/components/editor/Canvas.tsx
  • apps/web/components/panels/NodeSettings.tsx
  • apps/web/hooks/useWebSocket.ts
  • docs/api-reference.ja.md
  • docs/api-reference.md
  • plugins/audio-player/manifest.json
  • plugins/audio-player/node.ts
  • plugins/avatar-configuration/manifest.json
  • plugins/avatar-configuration/node.ts
  • plugins/emotion-analyzer/manifest.json
  • plugins/emotion-analyzer/node.ts
  • plugins/lip-sync/manifest.json
  • plugins/lip-sync/node.ts
  • plugins/motion-trigger/manifest.json
  • plugins/motion-trigger/node.ts
  • plugins/obs-scene-switch/manifest.json
  • plugins/obs-scene-switch/node.ts
  • plugins/obs-source-toggle/manifest.json
  • plugins/obs-source-toggle/node.ts
  • plugins/subtitle-display/manifest.json
  • plugins/subtitle-display/node.ts
  • templates/discord-bot.json
  • templates/simple-vtuber.json
  • templates/streaming-vtuber.json
  • templates/twitch-vtuber.json
  • templates/voice-chatbot.json
  • templates/vtube-studio-vtuber.json
  • templates/youtube-vtuber.json

Comment thread apps/server-ts/src/engine/executor.ts Outdated
Comment thread apps/web/app/(editor)/editor/[id]/client-page.tsx Outdated
Comment on lines +108 to +115
const workflowModelUrl = avatarNode.config.modelUrl || avatarNode.config.vrm_model;
setAvatarConfig((prev) => ({
renderer: avatarNode.config.renderer || 'vrm',
// Keep saved model URL if workflow doesn't have one
modelUrl: workflowModelUrl || prev.modelUrl,
animationUrl: avatarNode.config.animation_url,
vtubePort: avatarNode.config.vtube_port,
pngConfig: avatarNode.config.png_config,
animationUrl: avatarNode.config.animationUrl,
vtubePort: avatarNode.config.vtubePort,
pngConfig: avatarNode.config.pngConfig,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add legacy key fallback for preview config to prevent migration regressions.

Only modelUrl has a legacy fallback path right now. animationUrl, vtubePort, and pngConfig no longer read snake_case fields, so older workflows can lose expected preview behavior.

💡 Suggested compatibility-safe patch
-            const workflowModelUrl = avatarNode.config.modelUrl || avatarNode.config.vrm_model;
+            const workflowModelUrl =
+              avatarNode.config.modelUrl ||
+              avatarNode.config.model_url ||
+              avatarNode.config.vrm_model;
             setAvatarConfig((prev) => ({
               renderer: avatarNode.config.renderer || 'vrm',
               // Keep saved model URL if workflow doesn't have one
               modelUrl: workflowModelUrl || prev.modelUrl,
-              animationUrl: avatarNode.config.animationUrl,
-              vtubePort: avatarNode.config.vtubePort,
-              pngConfig: avatarNode.config.pngConfig,
+              animationUrl: avatarNode.config.animationUrl || avatarNode.config.animation_url || avatarNode.config.idle_animation,
+              vtubePort: avatarNode.config.vtubePort || avatarNode.config.vtube_port,
+              pngConfig: avatarNode.config.pngConfig || avatarNode.config.png_config,
             }));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/`(editor)/preview/[id]/client-page.tsx around lines 108 - 115,
The preview config only falls back to legacy snake_case for modelUrl, causing
old workflows to lose animationUrl, vtubePort, and pngConfig; update the
setAvatarConfig call (and any reads of avatarNode.config) to use legacy
fallbacks: use avatarNode.config.animationUrl || avatarNode.config.animation_url
for animationUrl, avatarNode.config.vtubePort || avatarNode.config.vtube_port
for vtubePort, and avatarNode.config.pngConfig || avatarNode.config.png_config
for pngConfig (keeping the existing modelUrl/vrm fallback logic intact).

Comment thread plugins/lip-sync/node.ts Outdated
Comment on lines +21 to +22
this.emitRealtime = config.emitRealtime ?? true;
this.frameRate = Number(config.frameRate ?? 30);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Keep temporary snake_case compatibility for config and outputs.

Line 21-22 and return payloads now assume camelCase only. Older workflows/integrations using emit_realtime, frame_rate, or mouth_values will regress.

💡 Compatibility bridge example
-    this.emitRealtime = config.emitRealtime ?? true;
-    this.frameRate = Number(config.frameRate ?? 30);
+    this.emitRealtime = config.emitRealtime ?? config.emit_realtime ?? true;
+    this.frameRate = Number(config.frameRate ?? config.frame_rate ?? 30);
-      return { mouthValues: [], duration: 0.0, audio: "" };
+      return { mouthValues: [], mouth_values: [], duration: 0.0, audio: "" };

(Apply the same aliasing to all early/final returns.)

Also applies to: 50-53, 61-63, 71-73, 86-90

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/lip-sync/node.ts` around lines 21 - 22, Ensure backward compatibility
by accepting snake_case config keys and emitting snake_case fields in outputs:
when setting options, read both emitRealtime and emit_realtime, and frameRate
and frame_rate (e.g., replace the assignments around emitRealtime/frameRate to
prefer camelCase but fallback to snake_case); likewise when producing result
payloads include both mouthValues and mouth_values, emitRealtime and
emit_realtime, frameRate and frame_rate. Apply this aliasing consistently in the
initialization code (where emitRealtime and frameRate are set) and in all
early/final return payloads mentioned (the blocks around the other affected
lines).

Comment thread plugins/obs-scene-switch/node.ts Outdated
this.port = config.port ?? 4455;
this.password = config.password ?? "";
this.sceneName = config.scene_name ?? "";
this.sceneName = config.sceneName ?? "";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add temporary snake_case fallbacks to avoid breaking existing saved workflows.

Line 40 and Line 77 now read only camelCase keys, and Lines 61/72/81/97/108/112 return only currentScene. Existing flows using scene_name / current_scene will silently break after upgrade. Please keep a compatibility window (read old+new keys, optionally emit both outputs) and deprecate old keys in a later release.

Proposed compatibility patch
-    this.sceneName = config.sceneName ?? "";
+    this.sceneName = config.sceneName ?? config.scene_name ?? "";
...
-    const targetScene: string = inputs.sceneName ?? this.sceneName;
+    const targetScene: string =
+      inputs.sceneName ?? inputs.scene_name ?? this.sceneName;
...
-      return { success: true, currentScene: currentScene, scenes };
+      return {
+        success: true,
+        currentScene,
+        current_scene: currentScene, // temporary backward compatibility
+        scenes,
+      };
...
-      return { success: false, currentScene: "", scenes: [] };
+      return { success: false, currentScene: "", current_scene: "", scenes: [] };

Also applies to: 61-61, 72-72, 77-77, 81-81, 97-97, 108-108, 112-112

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/obs-scene-switch/node.ts` at line 40, Update configuration/read and
output paths to support both camelCase and snake_case keys: when initializing
this.sceneName (currently using config.sceneName) also fallback to
config.scene_name if present; likewise, wherever the code returns or emits
currentScene, also populate/emit current_scene (and accept current_scene when
reading inputs) to preserve compatibility. Search for assignments/returns
referencing this.sceneName and the output key currentScene and add symmetric
handling for scene_name/current_scene (read old key into the same variable, and
emit both keys) so existing saved workflows continue to work while you can
deprecate the snake_case names later.

Comment thread plugins/obs-source-toggle/manifest.json
Comment thread plugins/obs-source-toggle/node.ts Outdated
Comment on lines +42 to +43
this.sceneName = config.sceneName ?? "";
this.sourceName = config.sourceName ?? "";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add legacy config/output aliases to avoid breaking existing workflows.

Line 42 and Line 43 now read only camelCase keys, and all execute returns now expose only sourceName. Existing workflows saved with scene_name / source_name can silently fail after upgrade.

💡 Migration-safe fallback (minimal)
-    this.sceneName = config.sceneName ?? "";
-    this.sourceName = config.sourceName ?? "";
+    this.sceneName = config.sceneName ?? config.scene_name ?? "";
+    this.sourceName = config.sourceName ?? config.source_name ?? "";
-      return { success: false, visible: false, sourceName: this.sourceName };
+      return {
+        success: false,
+        visible: false,
+        sourceName: this.sourceName,
+        source_name: this.sourceName,
+      };

(Apply the same alias pattern to other return paths.)

Also applies to: 65-66, 76-77, 82-83, 101-102, 137-141

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/obs-source-toggle/node.ts` around lines 42 - 43, The constructor and
all output-return locations currently only use camelCase config keys and return
values (this.sceneName, this.sourceName, config.sceneName, config.sourceName),
which breaks older configs using snake_case; update the constructor to read
legacy keys (config.scene_name ?? config.sceneName ?? "" and config.source_name
?? config.sourceName ?? ""), and update every execute/return path that emits
sourceName to also include the snake_case aliases in the returned object (emit
both sourceName and source_name, and sceneName and scene_name where applicable)
so existing workflows remain compatible; apply the same alias pattern to the
other return paths referenced (lines around 65-66, 76-77, 82-83, 101-102,
137-141).

Comment thread plugins/subtitle-display/node.ts Outdated
既存のワークフローで保存されたsnake_caseキーが新しいcamelCase
キーに移行後も正しく読み込まれるよう、全箇所にフォールバック
処理を追加。

- NodeSettings: normalizeLegacyConfig関数で読み込み時に自動変換
- executor.ts: VTube Studio設定のsnake_caseフォールバック
- editor/preview/overlay: アバター設定読み込み時のフォールバック
- 全プラグインnode.ts: config読み取り時のsnake_caseフォールバック
  (avatar-configuration, motion-trigger, emotion-analyzer, lip-sync,
   audio-player, subtitle-display, obs-scene-switch, obs-source-toggle)
- overlay: avatar.updateでrest展開ではなくホワイトリスト方式に変更
- motion-trigger: manifest.jsonとコメントの古いsnake_case参照を修正

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: プラグイン間の設定命名規則の統一

1 participant