Skip to main content
Glama

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
NameRequiredDescriptionDefault
directionYesDirection to look
durationNoDuration 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) {
          // エラーを無視
        }
      }
    }
  • 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
          };
        }
      }
    );
  • Type definition for LookDirection used in the tool's input schema.
    export type LookDirection = 'left' | 'right';
Install Server

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Krekun/vrchat-mcp-osc'

If you have feedback or need assistance with the MCP directory API, please join our Discord server