Skip to content

Instantly share code, notes, and snippets.

@cynthiateeters
Created February 25, 2026 19:33
Show Gist options
  • Select an option

  • Save cynthiateeters/08b4ce16d375871697ccc4b6b3866d19 to your computer and use it in GitHub Desktop.

Select an option

Save cynthiateeters/08b4ce16d375871697ccc4b6b3866d19 to your computer and use it in GitHub Desktop.
Using custom cowsay files with configurable eyes

Custom cowsay files with configurable eyes

The npm cowsay package supports loading custom .cow files from any path, not just the built-in ones. This lets you create modified versions with configurable features like dynamic eyes.

The discovery

Looking at the cowsay source code in lib/cows.js:

if (cow.match(/\\/) || cow.match(/\//)) {
  filePath = cow; // Use as full path if contains slash
} else {
  filePath = path.join(__dirname, "/../cows", cow) + ".cow";
}

Key insight: If the f option contains a / or \, cowsay treats it as a file path instead of looking in node_modules/cowsay/cows/.

Visual examples

Fox awake (nighttime) - wide eyes

 ________________________
< Wa-pa-pa-pa-pa-pa-pow! >
 ------------------------
\
 \
   /\   /\   Todd Vargo
  //\_//\     ____
  \_     _/    /   /
   / * * \    /^^^]
   \_\O/_/    [   ]
    /   \_    [   /
    \     \_  /  /
     [ [ /  \/ _/
    _[ [ \  /_/

Fox sleeping (daytime) - sleepy eyes

 ________
< Zzz... >
 --------
\
 \
   /\   /\   Todd Vargo
  //\_//\     ____
  \_     _/    /   /
   / - - \    /^^^]
   \_\O/_/    [   ]
    /   \_    [   /
    \     \_  /  /
     [ [ /  \/ _/
    _[ [ \  /_/

How to implement

1. Create a custom .cow file

Copy the original and replace hardcoded eyes with $eyes:

# new-cows/fox.cow
$the_cow = <<EOC;
$thoughts
 $thoughts
   /\   /\   Todd Vargo
  //\\_//\\     ____
  \_     _/    /   /
   / $eyes \    /^^^]
   \_\O/_/    [   ]
    /   \_    [   /
    \     \_  /  /
     [ [ /  \/ _/
    _[ [ \  /_/
EOC

2. Use the custom file with configurable eyes

import * as cowsay from "cowsay";

// Load custom cow file (path must contain a slash)
// Set eyes with the 'e' option
console.log(
  cowsay.say({
    text: "Hello!",
    f: "./new-cows/fox.cow",
    e: "* *",
  }),
);

3. Make eyes dynamic

const hour = new Date().getHours();
const isSleeping = hour >= 7 && hour < 19;

const text = isSleeping ? "Zzz..." : "What does the fox say?";
const eyes = isSleeping ? "- -" : "* *";

console.log(
  cowsay.say({
    text: text,
    f: "./new-cows/fox.cow",
    e: eyes,
  }),
);

Available variables in .cow files

Variable Description Example
$thoughts Speech bubble connector \ or o
$eyes Two-character eye string oo, **, ^^
$tongue Tongue string U

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment