Inject ASCII Art in any HTML pages rendered by Docusaurus
Inject an ASCII-art banner into every generated Docusaurus HTML page using a lightweight postBuild plugin. Appears in page source or can be rendered visibly.
This article is part of the Creating Docusaurus components series:
- Change how Docusaurus will create img tags
- Overrides the generation of img tags with Docusaurus
- Organize Your Docusaurus Content with a Custom Series Component
- Providing a go to the top button in Docusaurus posts
- Creating a search&replace plugin for Docusaurus
- A component for showing code snippets in a Docusaurus blog
- A Docusaurus component that alerts readers the article is over a year old
- Showing the changelog of your post
- Inject ASCII Art in any HTML pages rendered by Docusaurus
- Best Practice - Customizing the Docusaurus RSS Feed for Full Content & Images
- Running some checks on your Docusaurus images
- Tags management in Docusaurus
- Automating TL;DR Summaries with Gemini AI
- Introducing the ProjectSetup Component - A Standardized Way to Share Project Structures
- How to indicate AI-assisted content in a Docusaurus blog
- Bring Your CLI Tutorials to Life with a Typewriter Terminal
- Meerkat Mischief: Sprinkling Easter Eggs Across my Blog
- AI-Powered Code Tooltips in Docusaurus — Explain Like I'm Five
- Adding Reader Reactions to Your Docusaurus Blog
- Your Blog Is Unreadable to an AI. Here Is the Fix.
- Shake Your Phone, Startle the Meerkat
- Add a "Copy as Markdown" Button to Your Docusaurus Blog
- Ask My Blog: Turning 259 Articles Into 2,160 Searchable Questions
- The Third Door: A Floating Chat Bubble, and the Feature Nobody Could Find
- Drawing a Map of My Own Blog
- Let Readers Flag Issues — A Multi-Type Feedback Widget for Docusaurus

This article demonstrates how to inject a custom ASCII art banner into every HTML page generated by Docusaurus. It involves creating a lightweight postBuild plugin that scans generated files and inserts the ASCII art as an HTML comment after the <!doctype html> tag. The guide provides steps for creating the ASCII art file, the plugin, and configuring Docusaurus to activate it.
It might be entirely useless, and only the most dedicated tech-heads will spot it, but we're going to dive into how to inject a custom ASCII art banner at the very top of every HTML page generated for our blog.
Right now, just press CTRL+U (it's the same as View page source) to see what we'll do in this article.
The Result
Once the plugin is in place (covered below), pressing CTRL+U on any page of the generated site shows this, right after the <!doctype html> tag:

Your website is demonstrably world-class and utterly unique in its field. ;-)
Why It Works
- The plugin hooks into Docusaurus's
postBuildevent — it only runs onceyarn docusaurus buildhas finished writing HTML to disk. - It scans every generated
.htmlfile in the build output. - For each one, it injects the ASCII art as an HTML comment right after the
<!doctype html>opening tag — invisible on the rendered page, visible only in the page source.
Unlike the remark plugins I've written before (see Creating a search&replace plugin for Docusaurus), this one doesn't touch the Markdown at all: it works on the generated HTML.
Installation
Create your personalized logo
First, we have to get some ASCII art. If you don't have one yet, you can use this online tool: Image to ASCII Art Converter. Just upload a small character on it and convert it. I've also covered the command-line way of producing such banners in Bash - ASCII art.
In your Docusaurus site, please create the src/data/banner.txt file and paste your ASCII art in it. Here is mine:
:+***###%%%%%%%%##****=:
.-*##%%%%%%##%%%%%%%%%%%%%%%%%%%%##+.
.=#%%%#%#%+.:..........::--------=#%%%%%%%%*:
.+#%%%##:........:------------------------+%%@@@@@:.
..=%#%##=......:----------------------------------*%%@@@#..
.:#%##*=.....:----:---------------------------=#@@%+=--*%@@@%-.
:####+.....:-+%@@@*=:-------------------------=@@@@@@@+----#@@@%=.
:#%%#+....:::*@@@@@@@@:-------------------------=**+-+##=------#@@@%-
.*#%%+....:::::=#%*--++-------------------------------------------=#@@@#:
-#%%*....:::::::::------------------------------------=++++++=-----===%@@#-
=#%%=...:::::::--=++++++----------------------------+************+=--===*@@%=
+%%%-...:-:::-++************+-----------------------******************====*@@@=.
+%%%-..:-----******************+--------------------****#%%%%%%##*******+===*@@@=
=%%%-..:----**********%@@@@@@****+------------------***%@@@%**%@@@@@*******===*@@@=
-#%%-..:----*******#@@@@%*=-=%@@@%**-----------------*#@#-::....::-#%@@#*****===*@@@%%=.
...=#%%=...:--=******#%@@+-::.....::-%@%*----------------*%-::+@@#-.....:%@@*****+==+#@@@%%%@:
.-%%%%%%%=..:---******#@@*-:....+%@@@%-:-%#----------------#==#:..+@@@%-....#@%*****+==*@@@##%%%*.
.-%%%%+*%%=..:---*******%@*:.......*@@@@@%--%*---------------==@@#-+%@@@@@-....@@*****+===#@@%#*%%%%.
.%%%#=.=%%%=..:--=******#@@*....**==%@@@@@@%:+*----------------*@@@@@@@@@@@-....@%******+==#@@@##+%@%+
.%%%#..-#@@@=..:--+******#%@*...:*@@@@@@@@@@%==#-------++++++=--=@@@@@@@@@@@-...=@%******+==+%@@##*%@@%
*%%#.:+*%@@#-.:---+*******#@*:...+@@@@@@@@@@%-#=---=*#*+=====*%*=-%@@@@@@@%-...=@%******+====#@@%##%@@%
%%%+.++#%@@*-::----********#@#-...-#@@@@@@%=:*+:::=#%#*+++++*#%%%-:=+*#+=-...+%@#******+-:===#@@@#*@@@%
%%%+=+##%@@#-------=*********%%*-...:------**-:...=@@%%%%%%@@@@@@#..:=++**#%##********+:..-==#@@@#%@@@:
%%%%++**#@@#=------.:**********#%%#####%*#*-:.....+@@@@@@@@@@@@@%-:....:=**********+:.....-==#@@%%%@%:
-@@@#+**#@@@+-----:...:*****************-:.........:*@@@@@@@@@@#=-:::....................:-=*%@@@@@%.
=@@@%+*#@@@+-----:.......-*+++****=:.................-#@@@@*=--::::=*...................:-=#@@@@+.
.%@@@#*%@@%=-----........................:@@#............:-::-:-=%@*:::...............:==*@@@-
.-%@@@@@@@*-----.........................:*%@#-:......:::::-=+@@#=::::::............:==+#@@*:
.=##%@@@+-----...........................-#%@@@%*===+#@@@%#*::::::::::.........:-==+%@@#:
+%@@*-----:.............................:+#******#-:::::::::::::::.......-===*@@@*:
=%@@#=-----:...................................::::::::::::::::::....:-====#@@%=.
-#@@@*------:................................:::::::::::::::::::::-====+#@@@#:
.-%@@@#-------::......................:::::::::::::::::::::::--=====#%@@@#- =+*+.
.-%@@@%#==-------::.........::::::::::::::::::::::::::---=====-#%@@@@#: +%@@%@@*
.:%@@@@%#+========------::::::::::::::::::::------======-*%@@@@@#:. .#@=--*@%-
.:*@@@@@@%#+--==--------------------------------====#@@@@@+:. :#@=---@@=
..:#@@@@@@@@%=------------------------------=-===#@@@: :#@---=@@=
.+%@@@=-----------------------------------*%@@: .#@%*-@@@@@@%+.
-#@@=------------------------------------#@@+. .*%%%*%@@=-=%=%@#-
.*%%-..--------------------:::::::-------#@@@: -#@=----=@%=*%=+#@*:
*%%#..----------------:..............:--+%@@:. +@@+==#%@@*#@#+*%@*:
+%%%:..-------------:..................:-#@@@%==: ..-+%%%*+++###%@@@%@@%-
:#%%:..:----------:......................*@@@@@@%%%%%%%%%%*::=++++++*#@@%+.
.=#%%%*-...:--------:........................#@@#+++*###*==:..:---===+++*@@#.
-#%%%#=...::---------:.........................=%@@*--::::::::---------==+@@%+
.-#%%%+:..::------------:..........................#@@@=-----------------===@@@*.
:#%%#=...::--------------:..........................-%@@%=-------------====#@@@*.
.#%%%+...:-----------------:..........................:+@@@+==---------====+%%@%:
.%%%*...:::-----------------:...........................-%@@%====--=======+%@@@%
.%%%*..:--------------=%=----:...........................--@@@#++++=====+#@@@@#.
%%%#..::------------+%%+-----:...........................:-%@@%+++++**%@@@@#+.
.%%#:..::----------#@@%*=-----:............................-=@@@@@@@@@@@%#+.
=%%#..-:----------%@@@=+=-----:............................-=#@@@@%#*+=.
:%%%-------------=+%@@#=------:............................-==@@%+
%%%#-------------=+%@@#------:............................:==@@@#
.@@%#=------------=+@@%+-----:.............................==*@@#:
.#@@%*=---------==++@@%-----:.............................===@@@*
.-%@@@%%%%%%%*++++*@@%-----:.............................===%@@*
..=@@@@@*+++++++@@%=-----:.............................-==+@@#-
=@@#+++++++%@@@+=----:..............................:==+@@@*
=@@#*++%@@@@@%===----:..............................:===%@@*
.=%@@@@@@%%++===-----:..............................:===*@@#:
.:=+%%@#*++--------:::..........:::-----+%@@#+++++===-----:...............................:===+@@@+
:+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@@#+=====--------:..............................::===+@@@*
:#%%%******++++++**#######*++++=++++++++*#%%%=.:-------------:............................::::===+%@@*
-%%%#*********************-:::::::::::::=#%%+..:-------------:..........................::::::===+#@@*.
.+%%%#*******************=--------------*%%*:.::-------------:........................::::::::====+@@#:
.=%@@@%#****************=-------------+@@#=..:--------------:......................:::::::::-====+@@#-
.-#@@@%%*********####*=============+@@@+..:---------------:....................::::::::::-=====+@@@+
..+%@@@@@@#***#####+=============#@@*..:-----------------:................::::::::::::-======+@@@+
.#@@@@@@@@%###+============+@@@*.:-------------------:............::::::::::::::========+@@@+
.*%%@@@@@@@@@@%*=++++++#@@*..:---------------------:.......::::::::::::::--=====+===+@@@+
.:*##%@@@@@@@@@@@@@@@*.:-------------------------::::::::::::::::--============+@@@+
.:=+***##@@@*.:-----------------------======---------===========+=+===+@@@+
:@@%+:--------------------================================+===+@@@+
:@@%=------------------====================++++++++++++++=====+@@@+
.:@@#=---------------==========*###%@@@@@@@@@@@@%%##*+==+++====+@@%=
.-@@%=------------=========*#%@@@@@@@@##@@@@@@@@@@%##*+++++++++*@@#-
:@@%+----------========+#%@@@#=-... :@@@%++++++++++++++++++*@@#:
=#%%@@%*-------=========+#@@@*-. .-@@@#=++++++++++++++++*@@@@%%*:
=%%@@#:::------==========+%@@#:. .=@@%*+++++++++++++++++=-=*%@@@%-
#@@@....-----============+@@@# .*@@#++++++++++++++++++++=--*@@@:
.:%@@@@@@@@@@@@@@@@@@@@@@@@@@@# :%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#:
.+############################: :##############################:.
This is ASCII art depicting what appears to be a stylized owl or bird face. The image is constructed entirely from text characters like `@`, `%`, `#`, `*`, `+`, and `-` arranged to create shading and depth that resembles a creature with large eyes and a pointed beak or face. It's purely decorative and serves no programmatic function.
Create the plugin and load it
Now, let's create the plugin. Please create plugins/ascii-injector/index.mjs and copy/paste the source code here below to your file:
/** * Docusaurus Plugin: ascii-injector * * Purpose: * This plugin will prepend an ASCII art banner (from a specified text file) * in all generated HTML files as an HTML comment. * * Usage: * - Save this plugin as `plugins/ascii-injector/index.mjs` * - Create the file containing the ASCII art in `src/data/banner.txt`. * - Add the plugin to `docusaurus.config.js` plugins array. * * Please see readme.md for more details */
import { promises as fs } from "node:fs";import path from "node:path";
/** * Recursively collect all HTML files in a given directory. */async function collectHtmlFiles(dir) { const entries = await fs.readdir(dir, { withFileTypes: true }); const files = await Promise.all( entries.map(async (entry) => { const fullPath = path.resolve(dir, entry.name); if (entry.isDirectory()) return collectHtmlFiles(fullPath); if (entry.isFile() && entry.name.endsWith(".html")) return [fullPath]; return []; }), ); return files.flat();}
/** * Docusaurus plugin that injects an ASCII art banner into all generated HTML files. * * @param {object} context - Docusaurus plugin context (unused). * @param {object} options - Plugin configuration options. * @param {string} options.bannerPath - Relative path (from siteDir) to the ASCII banner file. */export default function asciiInjectorPlugin(context, options) { if (!options || typeof options.bannerPath !== "string") { throw new Error("[ascii-injector] Missing required option: bannerPath (string)"); }
return { name: "ascii-injector-plugin",
async postBuild({ outDir, siteDir }) { const bannerPath = path.resolve(siteDir, options.bannerPath);
let rawBanner; try { rawBanner = await fs.readFile(bannerPath, "utf8"); } catch (err) { console.error(`[ascii-injector] Banner file missing: ${err.message}`); return; }
const commentBanner = `<!--\n${rawBanner}\n-->\n\n`;
const htmlFiles = await collectHtmlFiles(outDir); console.log( `[ascii-injector] Preparing to inject banner into ${htmlFiles.length} HTML files...`, );
const results = await Promise.allSettled( htmlFiles.map(async (filePath) => { try { const html = await fs.readFile(filePath, "utf8");
// proceed to inject; files are always regenerated during build
let updated;
// Default: insert comment after <!doctype ...> const doctype = /<!doctype[^>]*>/i; if (doctype.test(html)) { updated = html.replace(doctype, (m) => `${m}\n${commentBanner}`); } else { // fallback to prepending comment updated = commentBanner + html; }
// Write atomically: temp file + rename avoids race conditions // with other postBuild plugins that read HTML concurrently. const tmpPath = `${filePath}.tmp`; await fs.writeFile(tmpPath, updated, "utf8"); await fs.rename(tmpPath, filePath); return { status: "ok", filePath }; } catch (err) { return { status: "error", filePath, error: err }; } }), );
const ok = results.filter( (r) => r.status === "fulfilled" && r.value && r.value.status === "ok", ).length; const skipped = results.filter( (r) => r.status === "fulfilled" && r.value && r.value.status === "skipped", ).length; const failed = results.filter( (r) => r.status === "fulfilled" && r.value && r.value.status === "error", ).length + results.filter((r) => r.status === "rejected").length;
console.log( `[ascii-injector] Injection complete — ok: ${ok}, skipped: ${skipped}, failed: ${failed}`, ); }, };}This is a Docusaurus plugin that reads an ASCII art banner from a text file and injects it as an HTML comment into every generated HTML file in the build output. It does this by recursively finding all HTML files, reading the banner file, and then updating each HTML file — inserting the banner after the doctype declaration if one exists, or prepending it otherwise.
Almost done. Now, finalize the installation by editing your docusaurus.config.js file and, under plugins, please do this:
// [...]plugins: [ // [...] [ "./plugins/ascii-injector/index.mjs", { bannerPath: "src/data/banner.txt" }, ],],This is a plugin configuration array that registers a custom plugin called 'ascii-injector' and passes it a configuration object specifying where to find a banner text file. The plugin will likely read that banner file and inject its ASCII art content somewhere in the build output.
The very last thing to do is to restart your Docusaurus website to load the updated configuration file.
More Demos
Time to test
Nothing new here, just generate the static version of your site.
Once your website is generated, just open any page and press CTRL+U and tadaaa, your ASCII art is there — exactly the result shown at the top of this article.
Under the Hood (skip this if you just want to use it)
Not during preview mode
This plugin is only fired during the postBuild event i.e. only after your blog has been rendered as an HTML page. So if you're running Docusaurus in preview mode; you'll not see the ASCII art.
Conclusion
A postBuild plugin, one ASCII art file, and a three-line config addition — and every page your site generates carries a small, pointless, entirely intentional signature in its source. If the command-line side of generating ASCII banners interests you more than the Docusaurus plumbing, Bash - ASCII art covers that half.
This article is part of the Creating Docusaurus components series:
- Change how Docusaurus will create img tags
- Overrides the generation of img tags with Docusaurus
- Organize Your Docusaurus Content with a Custom Series Component
- Providing a go to the top button in Docusaurus posts
- Creating a search&replace plugin for Docusaurus
- A component for showing code snippets in a Docusaurus blog
- A Docusaurus component that alerts readers the article is over a year old
- Showing the changelog of your post
- Inject ASCII Art in any HTML pages rendered by Docusaurus
- Best Practice - Customizing the Docusaurus RSS Feed for Full Content & Images
- Running some checks on your Docusaurus images
- Tags management in Docusaurus
- Automating TL;DR Summaries with Gemini AI
- Introducing the ProjectSetup Component - A Standardized Way to Share Project Structures
- How to indicate AI-assisted content in a Docusaurus blog
- Bring Your CLI Tutorials to Life with a Typewriter Terminal
- Meerkat Mischief: Sprinkling Easter Eggs Across my Blog
- AI-Powered Code Tooltips in Docusaurus — Explain Like I'm Five
- Adding Reader Reactions to Your Docusaurus Blog
- Your Blog Is Unreadable to an AI. Here Is the Fix.
- Shake Your Phone, Startle the Meerkat
- Add a "Copy as Markdown" Button to Your Docusaurus Blog
- Ask My Blog: Turning 259 Articles Into 2,160 Searchable Questions
- The Third Door: A Floating Chat Bubble, and the Feature Nobody Could Find
- Drawing a Map of My Own Blog
- Let Readers Flag Issues — A Multi-Type Feedback Widget for Docusaurus
Loading comments…





