Skip to main content
Glama
simen
by simen

readColorRam

Reads color RAM values from the Commodore 64 emulator to analyze character foreground colors on screen. Returns a 25x40 grid of color values with names and a usage summary for debugging C64 programs.

Instructions

Read color RAM ($D800-$DBE7) and return color values with names.

Color RAM determines the foreground color of each character on screen.

Returns:

  • 25x40 grid of color values (0-15) with names

  • Summary of colors used

Related tools: readScreen, readVicState

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
summaryNoReturn only color usage summary, not full grid (default: false)

Implementation Reference

  • src/index.ts:1152-1225 (registration)
    Registration of the 'readColorRam' MCP tool, including input schema for optional summary mode and the full handler implementation that reads 1000 bytes from color RAM at $D800, computes color frequency statistics, optionally builds a 25x40 color grid using getColorInfo, and returns formatted response with _meta state.
    server.registerTool( "readColorRam", { description: `Read color RAM ($D800-$DBE7) and return color values with names. Color RAM determines the foreground color of each character on screen. Returns: - 25x40 grid of color values (0-15) with names - Summary of colors used Related tools: readScreen, readVicState`, inputSchema: z.object({ summary: z .boolean() .optional() .describe("Return only color usage summary, not full grid (default: false)"), }), }, async (args) => { try { // Color RAM is always at $D800 const colorData = await client.readMemory(0xd800, 0xd800 + 999); // Count color usage const colorCounts = new Map<number, number>(); for (const byte of colorData) { const color = byte & 0x0f; colorCounts.set(color, (colorCounts.get(color) || 0) + 1); } // Sort by frequency const colorUsage = Array.from(colorCounts.entries()) .sort((a, b) => b[1] - a[1]) .map(([color, count]) => ({ color: getColorInfo(color), count, percentage: Math.round((count / 1000) * 100), })); const response: Record<string, unknown> = { address: { value: 0xd800, hex: "$D800" }, summary: { uniqueColors: colorUsage.length, dominantColor: colorUsage[0]?.color || null, usage: colorUsage, }, }; if (!args.summary) { // Convert to 25 lines of 40 color values const colorLines: Array<Array<{ value: number; name: string }>> = []; for (let row = 0; row < 25; row++) { const line: Array<{ value: number; name: string }> = []; for (let col = 0; col < 40; col++) { const offset = row * 40 + col; line.push(getColorInfo(colorData[offset])); } colorLines.push(line); } response.grid = colorLines; } response.hint = colorUsage.length === 1 ? `Entire screen uses ${colorUsage[0].color.name} (${colorUsage[0].color.value})` : `${colorUsage.length} colors used. Dominant: ${colorUsage[0]?.color.name} (${colorUsage[0]?.percentage}%)`; return formatResponse(response); } catch (error) { return formatError(error as ViceError); } } );
  • Inline handler function for readColorRam tool: reads color RAM, processes color counts, generates grid or summary, uses getColorInfo for color names.
    async (args) => { try { // Color RAM is always at $D800 const colorData = await client.readMemory(0xd800, 0xd800 + 999); // Count color usage const colorCounts = new Map<number, number>(); for (const byte of colorData) { const color = byte & 0x0f; colorCounts.set(color, (colorCounts.get(color) || 0) + 1); } // Sort by frequency const colorUsage = Array.from(colorCounts.entries()) .sort((a, b) => b[1] - a[1]) .map(([color, count]) => ({ color: getColorInfo(color), count, percentage: Math.round((count / 1000) * 100), })); const response: Record<string, unknown> = { address: { value: 0xd800, hex: "$D800" }, summary: { uniqueColors: colorUsage.length, dominantColor: colorUsage[0]?.color || null, usage: colorUsage, }, }; if (!args.summary) { // Convert to 25 lines of 40 color values const colorLines: Array<Array<{ value: number; name: string }>> = []; for (let row = 0; row < 25; row++) { const line: Array<{ value: number; name: string }> = []; for (let col = 0; col < 40; col++) { const offset = row * 40 + col; line.push(getColorInfo(colorData[offset])); } colorLines.push(line); } response.grid = colorLines; } response.hint = colorUsage.length === 1 ? `Entire screen uses ${colorUsage[0].color.name} (${colorUsage[0].color.value})` : `${colorUsage.length} colors used. Dominant: ${colorUsage[0]?.color.name} (${colorUsage[0]?.percentage}%)`; return formatResponse(response); } catch (error) { return formatError(error as ViceError); } } );
  • Input schema and description for readColorRam tool: optional 'summary' boolean to return only stats instead of full grid.
    "readColorRam", { description: `Read color RAM ($D800-$DBE7) and return color values with names. Color RAM determines the foreground color of each character on screen. Returns: - 25x40 grid of color values (0-15) with names - Summary of colors used Related tools: readScreen, readVicState`, inputSchema: z.object({ summary: z .boolean() .optional() .describe("Return only color usage summary, not full grid (default: false)"), }), },
  • Helper functions getColorInfo and getColorName, plus C64_COLORS array used to interpret color RAM bytes (0-15) into named colors in the readColorRam handler.
    ] as const; export type C64Color = (typeof C64_COLORS)[number]; export function getColorName(value: number): C64Color { return C64_COLORS[value & 0x0f]; } export function getColorInfo(value: number): { value: number; name: C64Color } { return { value: value & 0x0f, name: getColorName(value), }; }

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/simen/vice-mcp'

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