Inspired by Bad Print, Aditya, in a fit of wild fancy (his words), wrote Bad Matrix. And you can promptly see that the results look just like Matrix digital rain not at all.
I was amused by the animation shown, so I tried to run the code — a single Bash function that delivers on its promise: the displayed effect is just as bad as advertized.
Now, the dollar-quoted stuff that shows up there, such as $'\235\246', is random, but the order of the kanji sequence isn’t — so I thought “hey, let’s change something to make this random as well”. Which I did.
Yet I seem to be incapable of restraining myself from tweaking other people’s Bash code when I put my hands on it. So there I go, renaming and regrouping things, and shuttling local functions out of the main one, and unbracing variables and compound commands, and adding arrays, and “hmm, I think this deserves to be a script instead of a single function”, and soon enough I have a whole file with another version of it — and then I might as well publish it, because people out there might really be in need of more Bad Matrices, and only a monster would hold back and deprive them of such basic necessities.
Therefore:
#!/usr/bin/env bash ## Bad Matrix Reloaded --- A still bad implementation of Matrix digital rain # SPDX-FileCopyrightText: © 2023 Aditya Athalye # SPDX-FileCopyrightText: © 2026 flandrew #---------------------# # Updated: 2026-04-20 # #---------------------# # Version: 0.2.0 # #---------------------# # SPDX-License-Identifier: GPL-3.0-or-later ## Commentary # # This is an intentionally bad implementation of Matrix digital rain. # https://en.wikipedia.org/wiki/Matrix_digital_rain # # "Bad" in the sense that the effect should look exactly like the original one # not at all — but with enough green dimmed Japanese stuff showing up that you # may perhaps be vaaaaguely reminded of the real thing. # # Aditya's original bad_matrix() function can be found here: # https://www.evalapply.org/posts/bad-matrix/index.html # # I (flandrew) pulled that function apart into this script; restructured and # simplified a few things; and further decomplected some internal functions. # # The only visible change for the user should be that the kanji selection is # now random (instead of always printing from the start: 日 一 大 年 中 会...) # I think this looks better, which means it's less bad — which may be worse. # But it still looks nearly as bad as before — which is most certainly good. # ############################################################################# #⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ ## Code ### Setup set -eo pipefail hash sed tput || exit 127 #⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ ### Variables cols=$(tput cols) rows=$(tput lines) # one hundred common kanji: ohck=(日 一 大 年 中 会 人 本 月 長 国 出 上 十 生 子 分 東 三 行 同 今 高 金 時 手 見 市 力 米 自 前 円 合 立 内 二 事 社 者 地 京 間 田 体 学 下 目 五 後 新 明 方 部 女 八 心 四 民 対 主 正 代 言 九 小 思 七 山 実 入 回 場 野 開 万 全 定 家 北 六 問 話 文 動 度 県 水 安 氏 和 政 保 表 道 相 意 発 不 党) #⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ ### Functions #### Main main() { cat /dev/urandom | print-line-fragment ;} print-line-fragment() while read -n "$((1 + RANDOM % cols))" line do sleep 0.5 maybe-goto-Y inject-matrix tput dim print-string-slowly "$line" & done #⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ #### Kanji inject-matrix() if ((RANDOM % 3 == 0)) then tput el else maybe-goto-Y color-me-matrix print-kanji fi print-kanji() for ((i=0; i++ < 1 + RANDOM % cols;)) do sleep 0.05 print-a-random-kanji & done print-a-random-kanji() { printf "%s " "${ohck[RANDOM % ${#ohck[@]}]}" ;} #⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ #### Slow-printing print-string-slowly() { <<<"$1" parse-chars | print-chars-slowly ;} parse-chars() { LANG="en_US.UTF-8" sed -E 's/(.)/\1\n/g' &} print-chars-slowly() while read char do printf "%q" "$char" | sed "s/''/ /g" & done #⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ #### Color color-me-matrix() { maybe-dim; tput setaf 2 ;} maybe-dim() if ((RANDOM % 3 == 0)) then tput dim else tput sgr0 fi #⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ #### Position maybe-goto-Y() if ((RANDOM % 2 == 0)) then tput cup "$((RANDOM % rows))" 0 fi #⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ ### Run it! main exit 0 # Local Variables: # coding: utf-8 # indent-tabs-mode: nil # sentence-end-double-space: nil # outline-regexp: "###* " # End: ## Bad Matrix Reloaded ends here
I thought about also changing something to make it rain from the top, instead of from the left; and that maybe we could replace the kanji with mirrored half-width kana. But better not: that would make it come dangerously close to the original, thereby running the risk of it actually looking good — which would be bad.
📆 2026-W17-1📆 2026-04-20