readColorRam
Reads color RAM to retrieve foreground color values for each character on the Commodore 64 screen. Returns a 25x40 grid of color data with names and 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:1183-1236 (handler)Handler function that reads color RAM memory from $D800 for 1000 bytes, extracts 4-bit color values, computes usage statistics, optionally builds a 25x40 color grid, and formats the response using 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:1176-1181 (schema)Input schema defining optional 'summary' boolean parameter to control whether full color grid or just summary is returned.inputSchema: z.object({ summary: z .boolean() .optional() .describe("Return only color usage summary, not full grid (default: false)"), }),
- src/index.ts:1164-1237 (registration)MCP tool registration for 'readColorRam', including description, input schema, and handler reference.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/utils/c64.ts:4-34 (helper)Color palette constants and helper functions getColorName/getColorInfo used to interpret raw color RAM bytes into named C64 colors (0-15). Called multiple times in the handler.export const C64_COLORS = [ "black", "white", "red", "cyan", "purple", "green", "blue", "yellow", "orange", "brown", "light red", "dark gray", "gray", "light green", "light blue", "light gray", ] 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), }; }