Skip to main content
Glama

character

Generate a unique ASCII character from a seed string. Choose from 16 species, 10 eyes, 8 mouths, 10 hats, and 12 accessories. Use mood presets for quick expression changes.

Instructions

Generate a unique ASCII character from a seed. 153600 possible combinations (16 species × 10 eyes × 8 mouths × 10 hats × 12 accessories). Same seed always produces the same character. Use mood for quick expression presets. Output can be piped to the animate tool.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
seedYesDeterministic seed string — same seed = same character
speciesNoBody override
eyesNoEyes override
mouthNoMouth override
hatNoHat override
accessoryNoAccessory override
moodNoExpression preset (overrides eyes+mouth). Explicit eyes/mouth still take priority.
sizeNoSize: "standard" (full character) or "mini" (2-line inline, no hat/accessory)standard

Implementation Reference

  • src/mcp.ts:308-334 (registration)
    Registration of the 'character' tool with the MCP server, including its schema definition (seed, species, eyes, mouth, hat, accessory, mood, size) and handler that calls generateCharacter().
    server.tool(
      'character',
      `Generate a unique ASCII character from a seed. ${SPECIES.length * EYES.length * MOUTHS.length * HATS.length * ACCESSORIES.length} possible combinations (${SPECIES.length} species × ${EYES.length} eyes × ${MOUTHS.length} mouths × ${HATS.length} hats × ${ACCESSORIES.length} accessories). Same seed always produces the same character. Use mood for quick expression presets. Output can be piped to the animate tool.`,
      {
        seed: z.string().min(1).max(MAX_CHARACTER_SEED_LENGTH).describe('Deterministic seed string — same seed = same character'),
        species: z.enum(SPECIES as unknown as [string, ...string[]]).optional().describe('Body override'),
        eyes: z.enum(EYES as unknown as [string, ...string[]]).optional().describe('Eyes override'),
        mouth: z.enum(MOUTHS as unknown as [string, ...string[]]).optional().describe('Mouth override'),
        hat: z.enum(HATS as unknown as [string, ...string[]]).optional().describe('Hat override'),
        accessory: z.enum(ACCESSORIES as unknown as [string, ...string[]]).optional().describe('Accessory override'),
        mood: z.enum(MOODS as unknown as [string, ...string[]]).optional().describe('Expression preset (overrides eyes+mouth). Explicit eyes/mouth still take priority.'),
        size: z.enum(SIZES as unknown as [string, ...string[]]).default('standard').describe('Size: "standard" (full character) or "mini" (2-line inline, no hat/accessory)'),
      },
      async ({ seed, species, eyes, mouth, hat, accessory, mood, size }) => {
        const result = generateCharacter({
          seed,
          species: species as any,
          eyes: eyes as any,
          mouth: mouth as any,
          hat: hat as any,
          accessory: accessory as any,
          mood: mood as any,
          size: size as any,
        });
        return { content: [{ type: 'text', text: result }] };
      }
    );
  • The generateCharacter() function that executes the character generation logic: hashes the seed, selects species/eyes/mouth/hat/accessory deterministically, replaces markers in templates, prepends hat, and attaches accessories.
    export function generateCharacter(options: CharacterOptions): string {
      const hash = hashSeed(options.seed);
      const size = options.size ?? 'standard';
    
      // Mood sets eyes+mouth defaults (explicit eyes/mouth still override)
      const moodPreset = options.mood ? MOOD_MAP[options.mood] : undefined;
    
      const species = options.species ?? SPECIES[selectIndex(hash, 0, SPECIES.length)];
      const eyes = options.eyes ?? moodPreset?.eyes ?? EYES[selectIndex(hash, 1, EYES.length)];
      const mouth = options.mouth ?? moodPreset?.mouth ?? MOUTHS[selectIndex(hash, 2, MOUTHS.length)];
    
      // 1. Get body template (copy)
      const templates = size === 'mini' ? MINI_TEMPLATES : BODY_TEMPLATES;
      const bodyTemplate = [...templates[species]];
    
      // 2. Replace eye/mouth markers
      const [leftEye, rightEye] = EYE_PARTS[eyes];
      const mouthChar = MOUTH_PARTS[mouth];
      const body = replaceMarkers(bodyTemplate, leftEye, rightEye, mouthChar);
    
      // Mini: no hat/accessory — return immediately
      if (size === 'mini') {
        return body.join('\n');
      }
    
      const hat = options.hat ?? HATS[selectIndex(hash, 3, HATS.length)];
      const accessory = options.accessory ?? ACCESSORIES[selectIndex(hash, 4, ACCESSORIES.length)];
    
      // 3. Prepend hat
      const hatLines = HAT_PARTS[hat];
      const withHat = prependLines(hatLines, body);
    
      // 4. Attach accessory
      const final = attachAccessory(withHat, ACCESSORY_PARTS[accessory]);
    
      return final.join('\n');
    }
  • Type definitions including CharacterOptions interface and the exported enums: SPECIES, EYES, MOUTHS, HATS, ACCESSORIES, MOODS, SIZES.
    // --- Types ---
    
    export const SPECIES = ['blob', 'cat', 'bear', 'robot', 'bird', 'bunny', 'ghost', 'alien', 'fox', 'frog', 'penguin', 'octopus', 'dragon', 'mushroom', 'cactus', 'skull'] as const;
    export const EYES = ['dot', 'round', 'wide', 'wink', 'happy', 'star', 'x', 'at', 'dash', 'asym'] as const;
    export const MOUTHS = ['smile', 'grin', 'open', 'flat', 'cat', 'teeth', 'tongue', 'zigzag'] as const;
    export const HATS = ['none', 'tophat', 'crown', 'party', 'cap', 'beanie', 'antenna', 'bow', 'halo', 'headband'] as const;
    export const ACCESSORIES = ['none', 'bowtie', 'scarf', 'sword', 'shield', 'tail', 'glasses', 'cape', 'wings', 'staff', 'bag', 'flower'] as const;
    export const MOODS = ['happy', 'sad', 'angry', 'surprised', 'sleepy', 'cool', 'love', 'silly'] as const;
    export const SIZES = ['mini', 'standard'] as const;
    
    export type Species = (typeof SPECIES)[number];
    export type Eyes = (typeof EYES)[number];
    export type Mouth = (typeof MOUTHS)[number];
    export type Hat = (typeof HATS)[number];
    export type Accessory = (typeof ACCESSORIES)[number];
    export type Mood = (typeof MOODS)[number];
    export type CharacterSize = (typeof SIZES)[number];
    
    export interface CharacterOptions {
      seed: string;
      species?: Species;
      eyes?: Eyes;
      mouth?: Mouth;
      hat?: Hat;
      accessory?: Accessory;
      mood?: Mood;
      size?: CharacterSize;
    }
  • Helper functions: hashSeed() implements FNV-1a 32-bit hash for deterministic seeding, and selectIndex() uses bit rotation and golden ratio mixing for slot-independent selection.
    export function hashSeed(seed: string): number {
      let h = 0x811c9dc5;
      for (let i = 0; i < seed.length; i++) {
        h ^= seed.charCodeAt(i);
        h = Math.imul(h, 0x01000193);
      }
      return h >>> 0; // unsigned 32-bit
    }
    
    // --- Slot-independent selection via bit rotation + golden ratio mixing ---
    
    export function selectIndex(hash: number, slot: number, count: number): number {
      // Rotate bits by slot * 7 to decorrelate slots
      const rotation = (slot * 7) % 32;
      const rotated = ((hash << rotation) | (hash >>> (32 - rotation))) >>> 0;
      // Golden ratio mixing
      const mixed = Math.imul(rotated, 0x9e3779b9) >>> 0;
      return mixed % count;
    }
  • Constant MAX_CHARACTER_SEED_LENGTH = 200 used for seed validation in the tool schema.
    export const MAX_CHARACTER_SEED_LENGTH = 200;
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden. It discloses determinism (same seed = same character), override priority for explicit eyes/mouth over mood, and the effect of size field ('mini' excludes hat/accessory). It does not mention permissions, rate limits, or side effects, but these are less critical for a generation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each delivering unique information: purpose and combinations, determinism, and usage tips (mood, piping). No filler, well front-loaded, and every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 8 parameters (1 required, 7 enums) and no output schema, the description covers determinism, mood priority, size options, and integration with animate. It could mention the output format more explicitly (e.g., string representation), but overall it's sufficiently complete for correct usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with descriptions for each parameter. The description adds value beyond schema by explaining mood as a quick preset for eyes+mouth, the deterministic nature of seed, the total combination count (153,600), and the ability to pipe output to animate. This contextual information enhances parameter understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it generates an ASCII character from a seed, with specific verb 'Generate' and resource 'unique ASCII character'. It mentions 153,600 combinations and determinism. However, it does not explicitly differentiate from sibling tools like kaomoji or animate, though the context implies it's a character generator.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description advises using 'mood' for quick expression presets and notes output can be piped to 'animate' tool. It provides some usage guidance but does not offer exclusions or alternative tools for different scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/rxolve/artscii'

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