Skip to main content
Glama

view_level_image

Convert encoded VibeTide level data into a color-accurate PNG image for visual representation, generating temporary files for display in MCP clients.

Instructions

View a VibeTide level as a beautiful PNG image with proper colors.

This generates a much better visual representation than the ASCII version,
using the same colors as the web builder. The image is saved to a temporary
file and the file path is returned for MCP clients to display.

Args:
    encoded_level: An encoded level string from a URL or sharing link
    tile_size: Size of each tile in pixels (default 16, will auto-adjust for wide levels)
    max_width: Maximum image width in pixels (default 1200)

Returns:
    The file path to the generated PNG image

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
encoded_levelYes
tile_sizeNo
max_widthNo

Implementation Reference

  • The main handler function for the 'view_level_image' MCP tool. It decodes the encoded level string and generates a PNG image file path using the helper function.
    @mcp.tool()
    async def view_level_image(
        encoded_level: str, tile_size: int = 16, max_width: int = 1200
    ) -> str:
        """View a VibeTide level as a beautiful PNG image with proper colors.
    
        This generates a much better visual representation than the ASCII version,
        using the same colors as the web builder. The image is saved to a temporary
        file and the file path is returned for MCP clients to display.
    
        Args:
            encoded_level: An encoded level string from a URL or sharing link
            tile_size: Size of each tile in pixels (default 16, will auto-adjust for wide levels)
            max_width: Maximum image width in pixels (default 1200)
    
        Returns:
            The file path to the generated PNG image
        """
        try:
            # Decode level from string
            level_data = level_encoder.decode(encoded_level)
    
            # Generate PNG image to temporary file
            image_path = generate_level_image_to_file(level_data, tile_size, max_width)
    
            return image_path
    
        except Exception as e:
            logger.error(f"Failed to generate level image: {e}")
            # Return error as string since we're returning a simple string now
            raise Exception(f"Failed to generate level image: {str(e)}")
  • The core helper function that creates the PNG image visualization of the level using Pillow library, drawing each tile with appropriate colors, borders, and labels if possible.
    def generate_level_image_to_file(
        level_data: Dict[str, Any], tile_size: int = 16, max_width: int = 1200
    ) -> str:
        """Generate a PNG image of the level and save to a temporary file. Returns the file path."""
        tiles = level_data.get("tiles", [])
    
        # Create a temporary file
        temp_file = tempfile.NamedTemporaryFile(
            delete=False, suffix=".png", prefix="vibe_tide_level_"
        )
        temp_path = temp_file.name
        temp_file.close()
    
        if not tiles:
            # Create a small error image
            img = Image.new("RGB", (200, 100), (255, 255, 255))
            draw = ImageDraw.Draw(img)
            draw.text((10, 40), "Empty Level", fill=(0, 0, 0))
            img.save(temp_path, format="PNG")
            return temp_path
    
        height = len(tiles)
        width = len(tiles[0]) if tiles else 0
    
        # Calculate image dimensions
        # For very wide levels, make tiles smaller to fit in max_width
        actual_tile_size = min(tile_size, max_width // width) if width > 0 else tile_size
        actual_tile_size = max(4, actual_tile_size)  # Minimum 4px per tile
    
        img_width = width * actual_tile_size
        img_height = height * actual_tile_size
    
        # Create image with white background
        img = Image.new("RGB", (img_width, img_height), (255, 255, 255))
        draw = ImageDraw.Draw(img)
    
        # Try to load a font for labels (fallback to default if not available)
        try:
            font = ImageFont.truetype("arial.ttf", max(8, actual_tile_size // 2))
        except:
            try:
                font = ImageFont.load_default()
            except:
                font = None
    
        # Draw tiles
        for y in range(height):
            for x in range(width):
                tile_type = tiles[y][x]
    
                # Calculate tile position
                left = x * actual_tile_size
                top = y * actual_tile_size
                right = left + actual_tile_size
                bottom = top + actual_tile_size
    
                # Get colors
                fill_color = TILE_COLORS.get(tile_type, (128, 128, 128))
                border_color = TILE_BORDER_COLORS.get(tile_type, (0, 0, 0))
    
                # Draw tile background
                draw.rectangle(
                    [left, top, right - 1, bottom - 1],
                    fill=fill_color,
                    outline=border_color,
                )
    
                # Add label for non-empty tiles if tile is large enough
                if actual_tile_size >= 12 and tile_type != 0:
                    label = TILE_LABELS.get(tile_type, str(tile_type))
                    if label and font:
                        # Calculate text position (center of tile)
                        bbox = draw.textbbox((0, 0), label, font=font)
                        text_width = bbox[2] - bbox[0]
                        text_height = bbox[3] - bbox[1]
                        text_x = left + (actual_tile_size - text_width) // 2
                        text_y = top + (actual_tile_size - text_height) // 2
    
                        # Use white text for dark backgrounds, black for light
                        text_color = (255, 255, 255) if sum(fill_color) < 400 else (0, 0, 0)
                        draw.text((text_x, text_y), label, fill=text_color, font=font)
    
        # Save to temporary file
        img.save(temp_path, format="PNG", optimize=True)
        return temp_path
  • The @mcp.tool() decorator registers the view_level_image function as an MCP tool.
    @mcp.tool()

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/banjtheman/vibe_tide_mcp'

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