look_direction
Control avatar gaze direction in VRChat by sending commands to turn left or right for a set duration, enabling precise AI-driven interactions in virtual environments.
Instructions
Turn to look in a specific direction.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| direction | Yes | Direction to look | |
| duration | No | Duration in seconds |
Implementation Reference
- Main handler function implementing the look_direction tool. Sends LookLeft or LookRight OSC inputs via WebSocket to turn the avatar's view.public async look( direction: LookDirection, duration: number = 1.0, ctx?: ToolContext ): Promise<string> { if (ctx) { await ctx.info(`Looking ${direction} for ${duration} seconds`); } if (direction !== 'left' && direction !== 'right') { return `Unknown direction: ${direction}`; } // ボタン入力名を決定 const inputName = direction === 'left' ? 'LookLeft' : 'LookRight'; try { logger.info(`[LOOK] Starting look ${direction} operation, duration: ${duration}s`); // ボタン入力を実行 const result = await this.tryButtonLook(inputName, duration); if (!result.success) { return `Failed to look ${direction}: ${result.error}`; } return `Looked ${direction} for ${duration} seconds`; } catch (error) { const errorMsg = `Error during look ${direction}: ${error instanceof Error ? error.message : String(error)}`; logger.error(`[LOOK] ${errorMsg}`); // 緊急リセット try { await this.wsClient.sendInput(inputName, 0); logger.info(`[LOOK] Emergency reset of look input after error`); } catch (resetError) { logger.error(`[LOOK] Failed emergency reset: ${resetError instanceof Error ? resetError.message : String(resetError)}`); } return errorMsg; } }
- Supporting helper method that handles the precise sequence of button press, hold, and release for look inputs, including retries and safety resets.private async tryButtonLook( inputName: string, duration: number ): Promise<{success: boolean, error?: string}> { try { // ボタン入力では、まず0(リリース)を送信してから1(プレス)を送信する必要がある logger.info(`[LOOK-BUTTON] Initializing button ${inputName}=0`); await this.wsClient.sendInput(inputName, 0); // 少し待機 await new Promise(r => setTimeout(r, 50)); // ボタンプレスを送信 logger.info(`[LOOK-BUTTON] Pressing button ${inputName}=1`); const pressSuccess = await this.wsClient.sendInput(inputName, 1); if (!pressSuccess) { return {success: false, error: `Failed to press button ${inputName}`}; } // 時間待機 await new Promise(r => setTimeout(r, (duration+2)*100 )); // ボタンリリースを送信 logger.info(`[LOOK-BUTTON] Releasing button ${inputName}=0`); const releaseSuccess = await this.wsClient.sendInput(inputName, 0); if (!releaseSuccess) { logger.warn(`[LOOK-BUTTON] Failed to release button ${inputName}`); // 再試行 await new Promise(r => setTimeout(r, 100)); await this.wsClient.sendInput(inputName, 0); } // // 指定された持続時間だけ待機 // if (duration > 0.2) { // すでに少し待機したので調整 // logger.info(`[LOOK-BUTTON] Waiting for remaining duration: ${duration - 0.2} seconds`); // await new Promise(resolve => setTimeout(resolve, (duration - 0.2) * 1000)); // } return {success: true}; } catch (error) { const errorMsg = `Error in button look: ${error instanceof Error ? error.message : String(error)}`; logger.error(`[LOOK-BUTTON] ${errorMsg}`); return {success: false, error: errorMsg}; } finally { // 最終的な安全策として、もう一度入力をリセットする try { await this.wsClient.sendInput(inputName, 0); logger.info(`[LOOK-BUTTON] Final safety reset of ${inputName}`); } catch (e) { // エラーを無視 } } }
- packages/mcp-server/src/server.ts:512-534 (registration)MCP server registration of the 'look_direction' tool, including input schema validation with zod and delegation to InputTools.look handler.server.tool( 'look_direction', 'Turn to look in a specific direction.', { direction: z.enum(['left', 'right']).describe('Direction to look'), duration: z.number().default(1.0).describe('Duration in seconds') }, async ({ direction, duration }, extra) => { try { const ctx = createToolContext(extra); const result = await inputTools.look(direction as LookDirection, duration, ctx); return { content: [{ type: 'text', text: result }] }; } catch (error) { return { content: [{ type: 'text', text: `Error looking direction: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } );
- packages/types/src/tools.ts:18-18 (schema)Type definition for LookDirection used in the tool's input schema.export type LookDirection = 'left' | 'right';