Skip to main content
Glama
simen
by simen

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
NameRequiredDescriptionDefault
summaryNoReturn only color usage summary, not full grid (default: false)

Implementation Reference

  • 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); } }
  • 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); } } );
  • 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), }; }

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