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
| Name | Required | Description | Default |
|---|---|---|---|
| summary | No | Return 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); } } );
- src/index.ts:1171-1225 (handler)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); } } );
- src/index.ts:1153-1170 (schema)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)"), }), },
- src/utils/c64.ts:21-34 (helper)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), }; }