12 CSS Retro UI Designs08 / 12
ASCII Art Web Interface Code
A live, typeable bash shell with an ASCII logo, ANSI-coloured output and a blinking caret — type real commands (help, ls, neofetch, cowsay, echo, clear) and watch them execute. The phosphor look, window chrome and caret are pure CSS; a tiny vanilla-JS interpreter drives the interactivity. IBM Plex Mono on a hatched dark room.
Published
The code
<div class="ret-08">
<div class="ret-08__term">
<div class="ret-08__bar"><i></i><i></i><i></i><span>guest@codefronts: ~/retro — bash</span></div>
<div class="ret-08__body" id="ret-08-body">
<pre> ___ _ ___ _
/ __|___ ___| |___ / __|_ _ ___ _ _| |_ ___
| (__/ _ \/ _` / -_) _/ '_/ _ \ ' \ _(_-<
\___\___/\__,_\___\__|_| \___/_||_\__/__/</pre>
<div class="l"><span class="d">Last login: Tue Jun 03 on ttys001</span></div>
<div class="l"><span class="d"># Type a command and hit Enter. Try: <span class="y">help</span>, <span class="y">ls</span>, <span class="y">neofetch</span>, <span class="y">cowsay hi</span></span></div>
<div id="ret-08-out"></div>
<div class="ret-08__input-line">
<span class="ret-08__ps1">guest@codefronts<span class="p">:~$</span></span>
<span class="ret-08__typed" id="ret-08-typed"></span><span class="ret-08__cur"></span>
</div>
</div>
</div>
</div><div class="ret-08">
<div class="ret-08__term">
<div class="ret-08__bar"><i></i><i></i><i></i><span>guest@codefronts: ~/retro — bash</span></div>
<div class="ret-08__body" id="ret-08-body">
<pre> ___ _ ___ _
/ __|___ ___| |___ / __|_ _ ___ _ _| |_ ___
| (__/ _ \/ _` / -_) _/ '_/ _ \ ' \ _(_-<
\___\___/\__,_\___\__|_| \___/_||_\__/__/</pre>
<div class="l"><span class="d">Last login: Tue Jun 03 on ttys001</span></div>
<div class="l"><span class="d"># Type a command and hit Enter. Try: <span class="y">help</span>, <span class="y">ls</span>, <span class="y">neofetch</span>, <span class="y">cowsay hi</span></span></div>
<div id="ret-08-out"></div>
<div class="ret-08__input-line">
<span class="ret-08__ps1">guest@codefronts<span class="p">:~$</span></span>
<span class="ret-08__typed" id="ret-08-typed"></span><span class="ret-08__cur"></span>
</div>
</div>
</div>
</div>@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;700&display=swap');
.ret-08,
.ret-08 *,
.ret-08 *::before,
.ret-08 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ret-08 ::selection {
background: #ffaf00;
color: #0c0c0c;
}
.ret-08 {
--bg: #0c0c0c;
--panel: #161616;
--fg: #e4e4e4;
--green: #33d17a;
--blue: #5c9eff;
--yellow: #ffaf00;
--red: #f25f5c;
--magenta: #c264f0;
--dim: #6a6a6a;
font-family: 'IBM Plex Mono',monospace;
background: repeating-linear-gradient(45deg,#0a0a0a 0 12px,#0c0c0c 12px 24px);
min-height: 100vh;
display: grid;
place-items: center;
padding: clamp(12px,3vw,40px);
color: var(--fg);
}
.ret-08__term {
width: min(780px,100%);
height: min(560px,82vh);
display: flex;
flex-direction: column;
background: var(--bg);
border-radius: 10px;
overflow: hidden;
box-shadow: 0 24px 60px rgba(0,0,0,.7),0 0 0 1px rgba(255,255,255,.06);
}
.ret-08__bar {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 14px;
background: linear-gradient(180deg,#2a2a2a,#1c1c1c);
border-bottom: 1px solid #000;
}
.ret-08__bar i {
width: 12px;
height: 12px;
border-radius: 50%;
}
.ret-08__bar i:nth-child(1) {
background: #ff5f56;
}
.ret-08__bar i:nth-child(2) {
background: #ffbd2e;
}
.ret-08__bar i:nth-child(3) {
background: #27c93f;
}
.ret-08__bar span {
margin-left: 10px;
font-size: .78rem;
color: var(--dim);
}
.ret-08__body {
flex: 1;
overflow-y: auto;
padding: 16px 18px;
font-size: clamp(12px,1.5vw,14px);
line-height: 1.55;
}
.ret-08__body::-webkit-scrollbar {
width: 8px;
}
.ret-08__body::-webkit-scrollbar-thumb {
background: #2a2a2a;
border-radius: 4px;
}
.ret-08 pre {
white-space: pre;
font-family: inherit;
color: var(--magenta);
line-height: 1.1;
font-size: clamp(8px,1.4vw,12px);
margin-bottom: 8px;
}
.ret-08 .l {
white-space: pre-wrap;
word-break: break-word;
}
.ret-08 .g {
color: var(--green);
}
.ret-08 .b {
color: var(--blue);
}
.ret-08 .y {
color: var(--yellow);
}
.ret-08 .r {
color: var(--red);
}
.ret-08 .m {
color: var(--magenta);
}
.ret-08 .d {
color: var(--dim);
}
.ret-08__prompt-l {
color: var(--green);
font-weight: 700;
}
.ret-08__prompt-l .p {
color: var(--blue);
}
.ret-08__input-line {
display: flex;
align-items: baseline;
gap: 8px;
margin-top: 4px;
}
.ret-08__ps1 {
color: var(--green);
font-weight: 700;
white-space: nowrap;
}
.ret-08__ps1 .p {
color: var(--blue);
}
.ret-08__typed {
color: var(--fg);
}
.ret-08__cur {
display: inline-block;
width: 8px;
height: 1.05em;
background: var(--fg);
transform: translateY(2px);
animation: ret-08-bl 1.1s steps(2) infinite;
}
@keyframes ret-08-bl {
50% {
opacity: 0;
}
}
.ret-08__hint {
margin-top: 10px;
color: var(--dim);
font-size: .74rem;
}
.ret-08 a {
color: var(--blue);
text-decoration: underline;
}
@media (prefers-reduced-motion: reduce) {
.ret-08__cur {
animation: none;
}
}@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;700&display=swap');
.ret-08,
.ret-08 *,
.ret-08 *::before,
.ret-08 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ret-08 ::selection {
background: #ffaf00;
color: #0c0c0c;
}
.ret-08 {
--bg: #0c0c0c;
--panel: #161616;
--fg: #e4e4e4;
--green: #33d17a;
--blue: #5c9eff;
--yellow: #ffaf00;
--red: #f25f5c;
--magenta: #c264f0;
--dim: #6a6a6a;
font-family: 'IBM Plex Mono',monospace;
background: repeating-linear-gradient(45deg,#0a0a0a 0 12px,#0c0c0c 12px 24px);
min-height: 100vh;
display: grid;
place-items: center;
padding: clamp(12px,3vw,40px);
color: var(--fg);
}
.ret-08__term {
width: min(780px,100%);
height: min(560px,82vh);
display: flex;
flex-direction: column;
background: var(--bg);
border-radius: 10px;
overflow: hidden;
box-shadow: 0 24px 60px rgba(0,0,0,.7),0 0 0 1px rgba(255,255,255,.06);
}
.ret-08__bar {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 14px;
background: linear-gradient(180deg,#2a2a2a,#1c1c1c);
border-bottom: 1px solid #000;
}
.ret-08__bar i {
width: 12px;
height: 12px;
border-radius: 50%;
}
.ret-08__bar i:nth-child(1) {
background: #ff5f56;
}
.ret-08__bar i:nth-child(2) {
background: #ffbd2e;
}
.ret-08__bar i:nth-child(3) {
background: #27c93f;
}
.ret-08__bar span {
margin-left: 10px;
font-size: .78rem;
color: var(--dim);
}
.ret-08__body {
flex: 1;
overflow-y: auto;
padding: 16px 18px;
font-size: clamp(12px,1.5vw,14px);
line-height: 1.55;
}
.ret-08__body::-webkit-scrollbar {
width: 8px;
}
.ret-08__body::-webkit-scrollbar-thumb {
background: #2a2a2a;
border-radius: 4px;
}
.ret-08 pre {
white-space: pre;
font-family: inherit;
color: var(--magenta);
line-height: 1.1;
font-size: clamp(8px,1.4vw,12px);
margin-bottom: 8px;
}
.ret-08 .l {
white-space: pre-wrap;
word-break: break-word;
}
.ret-08 .g {
color: var(--green);
}
.ret-08 .b {
color: var(--blue);
}
.ret-08 .y {
color: var(--yellow);
}
.ret-08 .r {
color: var(--red);
}
.ret-08 .m {
color: var(--magenta);
}
.ret-08 .d {
color: var(--dim);
}
.ret-08__prompt-l {
color: var(--green);
font-weight: 700;
}
.ret-08__prompt-l .p {
color: var(--blue);
}
.ret-08__input-line {
display: flex;
align-items: baseline;
gap: 8px;
margin-top: 4px;
}
.ret-08__ps1 {
color: var(--green);
font-weight: 700;
white-space: nowrap;
}
.ret-08__ps1 .p {
color: var(--blue);
}
.ret-08__typed {
color: var(--fg);
}
.ret-08__cur {
display: inline-block;
width: 8px;
height: 1.05em;
background: var(--fg);
transform: translateY(2px);
animation: ret-08-bl 1.1s steps(2) infinite;
}
@keyframes ret-08-bl {
50% {
opacity: 0;
}
}
.ret-08__hint {
margin-top: 10px;
color: var(--dim);
font-size: .74rem;
}
.ret-08 a {
color: var(--blue);
text-decoration: underline;
}
@media (prefers-reduced-motion: reduce) {
.ret-08__cur {
animation: none;
}
}(() => {
const root = document.querySelector('.ret-08');
if (!root) return;
const body = root.querySelector('#ret-08-body');
const out = root.querySelector('#ret-08-out');
const typedEl = root.querySelector('#ret-08-typed');
let buf = '';
const esc = s => s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
const cmds = {
help: () => `<span class="g">Available:</span> help · ls · pwd · whoami · date · neofetch · cowsay <text> · echo <text> · clear`,
ls: () => `<span class="b">projects/</span> <span class="b">art/</span> readme.md <span class="g">retro.sh</span> .secret`,
pwd: () => `/home/guest/retro`,
whoami: () => `guest <span class="d">(uid=1000 groups=demos,retro)</span>`,
date: () => new Date().toString(),
neofetch: () => `<span class="m"> ___ </span> <span class="g">guest</span>@<span class="g">codefronts</span>
<span class="m"> / _ \\ </span> <span class="y">OS:</span> RetroLinux 8.6 "Phosphor"
<span class="m">| | | | </span> <span class="y">Shell:</span> bash 5.1 · pure CSS+JS
<span class="m">| |_| | </span> <span class="y">Term:</span> codefronts-term
<span class="m"> \\___/ </span> <span class="y">Theme:</span> ANSI green-on-black`,
clear: () => { out.innerHTML=''; return null; }
};
function run(raw){
const line = `<div class="l"><span class="ret-08__ps1">guest@codefronts<span class="p">:~$</span></span> ${esc(raw)}</div>`;
let res = '';
const trimmed = raw.trim();
const [c, ...rest] = trimmed.split(/\s+/);
const arg = rest.join(' ');
if (trimmed === '') { res=''; }
else if (c === 'echo') res = esc(arg);
else if (c === 'cowsay') {
const t = esc(arg || 'moo');
const bar = '_'.repeat(t.length + 2);
const bar2 = '-'.repeat(t.length + 2);
res = `<span class="y"> ${bar}\n< ${t} >\n ${bar2}\n \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n ||----w |\n || ||</span>`;
}
else if (cmds[c]) { const r = cmds[c](); if (r===null){return;} res = r; }
else res = `<span class="r">bash: ${esc(c)}: command not found</span> <span class="d">(try 'help')</span>`;
out.insertAdjacentHTML('beforeend', line + (res!=='' ? `<div class="l">${res}</div>` : ''));
body.scrollTop = body.scrollHeight;
}
window.addEventListener('keydown', (e) => {
if (e.metaKey || e.ctrlKey || e.altKey) return;
if (e.key === 'Enter') { run(buf); buf=''; }
else if (e.key === 'Backspace') { buf = buf.slice(0,-1); e.preventDefault(); }
else if (e.key.length === 1) { buf += e.key; }
else return;
typedEl.textContent = buf;
});
// seed one example
run('neofetch');
})();(() => {
const root = document.querySelector('.ret-08');
if (!root) return;
const body = root.querySelector('#ret-08-body');
const out = root.querySelector('#ret-08-out');
const typedEl = root.querySelector('#ret-08-typed');
let buf = '';
const esc = s => s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
const cmds = {
help: () => `<span class="g">Available:</span> help · ls · pwd · whoami · date · neofetch · cowsay <text> · echo <text> · clear`,
ls: () => `<span class="b">projects/</span> <span class="b">art/</span> readme.md <span class="g">retro.sh</span> .secret`,
pwd: () => `/home/guest/retro`,
whoami: () => `guest <span class="d">(uid=1000 groups=demos,retro)</span>`,
date: () => new Date().toString(),
neofetch: () => `<span class="m"> ___ </span> <span class="g">guest</span>@<span class="g">codefronts</span>
<span class="m"> / _ \\ </span> <span class="y">OS:</span> RetroLinux 8.6 "Phosphor"
<span class="m">| | | | </span> <span class="y">Shell:</span> bash 5.1 · pure CSS+JS
<span class="m">| |_| | </span> <span class="y">Term:</span> codefronts-term
<span class="m"> \\___/ </span> <span class="y">Theme:</span> ANSI green-on-black`,
clear: () => { out.innerHTML=''; return null; }
};
function run(raw){
const line = `<div class="l"><span class="ret-08__ps1">guest@codefronts<span class="p">:~$</span></span> ${esc(raw)}</div>`;
let res = '';
const trimmed = raw.trim();
const [c, ...rest] = trimmed.split(/\s+/);
const arg = rest.join(' ');
if (trimmed === '') { res=''; }
else if (c === 'echo') res = esc(arg);
else if (c === 'cowsay') {
const t = esc(arg || 'moo');
const bar = '_'.repeat(t.length + 2);
const bar2 = '-'.repeat(t.length + 2);
res = `<span class="y"> ${bar}\n< ${t} >\n ${bar2}\n \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n ||----w |\n || ||</span>`;
}
else if (cmds[c]) { const r = cmds[c](); if (r===null){return;} res = r; }
else res = `<span class="r">bash: ${esc(c)}: command not found</span> <span class="d">(try 'help')</span>`;
out.insertAdjacentHTML('beforeend', line + (res!=='' ? `<div class="l">${res}</div>` : ''));
body.scrollTop = body.scrollHeight;
}
window.addEventListener('keydown', (e) => {
if (e.metaKey || e.ctrlKey || e.altKey) return;
if (e.key === 'Enter') { run(buf); buf=''; }
else if (e.key === 'Backspace') { buf = buf.slice(0,-1); e.preventDefault(); }
else if (e.key.length === 1) { buf += e.key; }
else return;
typedEl.textContent = buf;
});
// seed one example
run('neofetch');
})();Here's a working CSS Retro UI Design from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: ASCII Art Web Interface Code
Source: https://codefronts.com/design-styles/css-retro-designs/ascii-art-web-interface-code/
A live, typeable bash shell with an ASCII logo, ANSI-coloured output and a blinking caret — type real commands (help, ls, neofetch, cowsay, echo, clear) and watch them execute. The phosphor look, window chrome and caret are pure CSS; a tiny vanilla-JS interpreter drives the interactivity. IBM Plex Mono on a hatched dark room.
## HTML
```html
<div class="ret-08">
<div class="ret-08__term">
<div class="ret-08__bar"><i></i><i></i><i></i><span>guest@codefronts: ~/retro — bash</span></div>
<div class="ret-08__body" id="ret-08-body">
<pre> ___ _ ___ _
/ __|___ ___| |___ / __|_ _ ___ _ _| |_ ___
| (__/ _ \/ _` / -_) _/ '_/ _ \ ' \ _(_-<
\___\___/\__,_\___\__|_| \___/_||_\__/__/</pre>
<div class="l"><span class="d">Last login: Tue Jun 03 on ttys001</span></div>
<div class="l"><span class="d"># Type a command and hit Enter. Try: <span class="y">help</span>, <span class="y">ls</span>, <span class="y">neofetch</span>, <span class="y">cowsay hi</span></span></div>
<div id="ret-08-out"></div>
<div class="ret-08__input-line">
<span class="ret-08__ps1">guest@codefronts<span class="p">:~$</span></span>
<span class="ret-08__typed" id="ret-08-typed"></span><span class="ret-08__cur"></span>
</div>
</div>
</div>
</div>
```
## CSS
```css
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;700&display=swap');
.ret-08,
.ret-08 *,
.ret-08 *::before,
.ret-08 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ret-08 ::selection {
background: #ffaf00;
color: #0c0c0c;
}
.ret-08 {
--bg: #0c0c0c;
--panel: #161616;
--fg: #e4e4e4;
--green: #33d17a;
--blue: #5c9eff;
--yellow: #ffaf00;
--red: #f25f5c;
--magenta: #c264f0;
--dim: #6a6a6a;
font-family: 'IBM Plex Mono',monospace;
background: repeating-linear-gradient(45deg,#0a0a0a 0 12px,#0c0c0c 12px 24px);
min-height: 100vh;
display: grid;
place-items: center;
padding: clamp(12px,3vw,40px);
color: var(--fg);
}
.ret-08__term {
width: min(780px,100%);
height: min(560px,82vh);
display: flex;
flex-direction: column;
background: var(--bg);
border-radius: 10px;
overflow: hidden;
box-shadow: 0 24px 60px rgba(0,0,0,.7),0 0 0 1px rgba(255,255,255,.06);
}
.ret-08__bar {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 14px;
background: linear-gradient(180deg,#2a2a2a,#1c1c1c);
border-bottom: 1px solid #000;
}
.ret-08__bar i {
width: 12px;
height: 12px;
border-radius: 50%;
}
.ret-08__bar i:nth-child(1) {
background: #ff5f56;
}
.ret-08__bar i:nth-child(2) {
background: #ffbd2e;
}
.ret-08__bar i:nth-child(3) {
background: #27c93f;
}
.ret-08__bar span {
margin-left: 10px;
font-size: .78rem;
color: var(--dim);
}
.ret-08__body {
flex: 1;
overflow-y: auto;
padding: 16px 18px;
font-size: clamp(12px,1.5vw,14px);
line-height: 1.55;
}
.ret-08__body::-webkit-scrollbar {
width: 8px;
}
.ret-08__body::-webkit-scrollbar-thumb {
background: #2a2a2a;
border-radius: 4px;
}
.ret-08 pre {
white-space: pre;
font-family: inherit;
color: var(--magenta);
line-height: 1.1;
font-size: clamp(8px,1.4vw,12px);
margin-bottom: 8px;
}
.ret-08 .l {
white-space: pre-wrap;
word-break: break-word;
}
.ret-08 .g {
color: var(--green);
}
.ret-08 .b {
color: var(--blue);
}
.ret-08 .y {
color: var(--yellow);
}
.ret-08 .r {
color: var(--red);
}
.ret-08 .m {
color: var(--magenta);
}
.ret-08 .d {
color: var(--dim);
}
.ret-08__prompt-l {
color: var(--green);
font-weight: 700;
}
.ret-08__prompt-l .p {
color: var(--blue);
}
.ret-08__input-line {
display: flex;
align-items: baseline;
gap: 8px;
margin-top: 4px;
}
.ret-08__ps1 {
color: var(--green);
font-weight: 700;
white-space: nowrap;
}
.ret-08__ps1 .p {
color: var(--blue);
}
.ret-08__typed {
color: var(--fg);
}
.ret-08__cur {
display: inline-block;
width: 8px;
height: 1.05em;
background: var(--fg);
transform: translateY(2px);
animation: ret-08-bl 1.1s steps(2) infinite;
}
@keyframes ret-08-bl {
50% {
opacity: 0;
}
}
.ret-08__hint {
margin-top: 10px;
color: var(--dim);
font-size: .74rem;
}
.ret-08 a {
color: var(--blue);
text-decoration: underline;
}
@media (prefers-reduced-motion: reduce) {
.ret-08__cur {
animation: none;
}
}
```
## JavaScript
```js
(() => {
const root = document.querySelector('.ret-08');
if (!root) return;
const body = root.querySelector('#ret-08-body');
const out = root.querySelector('#ret-08-out');
const typedEl = root.querySelector('#ret-08-typed');
let buf = '';
const esc = s => s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
const cmds = {
help: () => `<span class="g">Available:</span> help · ls · pwd · whoami · date · neofetch · cowsay <text> · echo <text> · clear`,
ls: () => `<span class="b">projects/</span> <span class="b">art/</span> readme.md <span class="g">retro.sh</span> .secret`,
pwd: () => `/home/guest/retro`,
whoami: () => `guest <span class="d">(uid=1000 groups=demos,retro)</span>`,
date: () => new Date().toString(),
neofetch: () => `<span class="m"> ___ </span> <span class="g">guest</span>@<span class="g">codefronts</span>
<span class="m"> / _ \\ </span> <span class="y">OS:</span> RetroLinux 8.6 "Phosphor"
<span class="m">| | | | </span> <span class="y">Shell:</span> bash 5.1 · pure CSS+JS
<span class="m">| |_| | </span> <span class="y">Term:</span> codefronts-term
<span class="m"> \\___/ </span> <span class="y">Theme:</span> ANSI green-on-black`,
clear: () => { out.innerHTML=''; return null; }
};
function run(raw){
const line = `<div class="l"><span class="ret-08__ps1">guest@codefronts<span class="p">:~$</span></span> ${esc(raw)}</div>`;
let res = '';
const trimmed = raw.trim();
const [c, ...rest] = trimmed.split(/\s+/);
const arg = rest.join(' ');
if (trimmed === '') { res=''; }
else if (c === 'echo') res = esc(arg);
else if (c === 'cowsay') {
const t = esc(arg || 'moo');
const bar = '_'.repeat(t.length + 2);
const bar2 = '-'.repeat(t.length + 2);
res = `<span class="y"> ${bar}\n< ${t} >\n ${bar2}\n \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n ||----w |\n || ||</span>`;
}
else if (cmds[c]) { const r = cmds[c](); if (r===null){return;} res = r; }
else res = `<span class="r">bash: ${esc(c)}: command not found</span> <span class="d">(try 'help')</span>`;
out.insertAdjacentHTML('beforeend', line + (res!=='' ? `<div class="l">${res}</div>` : ''));
body.scrollTop = body.scrollHeight;
}
window.addEventListener('keydown', (e) => {
if (e.metaKey || e.ctrlKey || e.altKey) return;
if (e.key === 'Enter') { run(buf); buf=''; }
else if (e.key === 'Backspace') { buf = buf.slice(0,-1); e.preventDefault(); }
else if (e.key.length === 1) { buf += e.key; }
else return;
typedEl.textContent = buf;
});
// seed one example
run('neofetch');
})();
```Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Retro UI Design from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: ASCII Art Web Interface Code
Source: https://codefronts.com/design-styles/css-retro-designs/ascii-art-web-interface-code/
A live, typeable bash shell with an ASCII logo, ANSI-coloured output and a blinking caret — type real commands (help, ls, neofetch, cowsay, echo, clear) and watch them execute. The phosphor look, window chrome and caret are pure CSS; a tiny vanilla-JS interpreter drives the interactivity. IBM Plex Mono on a hatched dark room.
## HTML
```html
<div class="ret-08">
<div class="ret-08__term">
<div class="ret-08__bar"><i></i><i></i><i></i><span>guest@codefronts: ~/retro — bash</span></div>
<div class="ret-08__body" id="ret-08-body">
<pre> ___ _ ___ _
/ __|___ ___| |___ / __|_ _ ___ _ _| |_ ___
| (__/ _ \/ _` / -_) _/ '_/ _ \ ' \ _(_-<
\___\___/\__,_\___\__|_| \___/_||_\__/__/</pre>
<div class="l"><span class="d">Last login: Tue Jun 03 on ttys001</span></div>
<div class="l"><span class="d"># Type a command and hit Enter. Try: <span class="y">help</span>, <span class="y">ls</span>, <span class="y">neofetch</span>, <span class="y">cowsay hi</span></span></div>
<div id="ret-08-out"></div>
<div class="ret-08__input-line">
<span class="ret-08__ps1">guest@codefronts<span class="p">:~$</span></span>
<span class="ret-08__typed" id="ret-08-typed"></span><span class="ret-08__cur"></span>
</div>
</div>
</div>
</div>
```
## CSS
```css
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;700&display=swap');
.ret-08,
.ret-08 *,
.ret-08 *::before,
.ret-08 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ret-08 ::selection {
background: #ffaf00;
color: #0c0c0c;
}
.ret-08 {
--bg: #0c0c0c;
--panel: #161616;
--fg: #e4e4e4;
--green: #33d17a;
--blue: #5c9eff;
--yellow: #ffaf00;
--red: #f25f5c;
--magenta: #c264f0;
--dim: #6a6a6a;
font-family: 'IBM Plex Mono',monospace;
background: repeating-linear-gradient(45deg,#0a0a0a 0 12px,#0c0c0c 12px 24px);
min-height: 100vh;
display: grid;
place-items: center;
padding: clamp(12px,3vw,40px);
color: var(--fg);
}
.ret-08__term {
width: min(780px,100%);
height: min(560px,82vh);
display: flex;
flex-direction: column;
background: var(--bg);
border-radius: 10px;
overflow: hidden;
box-shadow: 0 24px 60px rgba(0,0,0,.7),0 0 0 1px rgba(255,255,255,.06);
}
.ret-08__bar {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 14px;
background: linear-gradient(180deg,#2a2a2a,#1c1c1c);
border-bottom: 1px solid #000;
}
.ret-08__bar i {
width: 12px;
height: 12px;
border-radius: 50%;
}
.ret-08__bar i:nth-child(1) {
background: #ff5f56;
}
.ret-08__bar i:nth-child(2) {
background: #ffbd2e;
}
.ret-08__bar i:nth-child(3) {
background: #27c93f;
}
.ret-08__bar span {
margin-left: 10px;
font-size: .78rem;
color: var(--dim);
}
.ret-08__body {
flex: 1;
overflow-y: auto;
padding: 16px 18px;
font-size: clamp(12px,1.5vw,14px);
line-height: 1.55;
}
.ret-08__body::-webkit-scrollbar {
width: 8px;
}
.ret-08__body::-webkit-scrollbar-thumb {
background: #2a2a2a;
border-radius: 4px;
}
.ret-08 pre {
white-space: pre;
font-family: inherit;
color: var(--magenta);
line-height: 1.1;
font-size: clamp(8px,1.4vw,12px);
margin-bottom: 8px;
}
.ret-08 .l {
white-space: pre-wrap;
word-break: break-word;
}
.ret-08 .g {
color: var(--green);
}
.ret-08 .b {
color: var(--blue);
}
.ret-08 .y {
color: var(--yellow);
}
.ret-08 .r {
color: var(--red);
}
.ret-08 .m {
color: var(--magenta);
}
.ret-08 .d {
color: var(--dim);
}
.ret-08__prompt-l {
color: var(--green);
font-weight: 700;
}
.ret-08__prompt-l .p {
color: var(--blue);
}
.ret-08__input-line {
display: flex;
align-items: baseline;
gap: 8px;
margin-top: 4px;
}
.ret-08__ps1 {
color: var(--green);
font-weight: 700;
white-space: nowrap;
}
.ret-08__ps1 .p {
color: var(--blue);
}
.ret-08__typed {
color: var(--fg);
}
.ret-08__cur {
display: inline-block;
width: 8px;
height: 1.05em;
background: var(--fg);
transform: translateY(2px);
animation: ret-08-bl 1.1s steps(2) infinite;
}
@keyframes ret-08-bl {
50% {
opacity: 0;
}
}
.ret-08__hint {
margin-top: 10px;
color: var(--dim);
font-size: .74rem;
}
.ret-08 a {
color: var(--blue);
text-decoration: underline;
}
@media (prefers-reduced-motion: reduce) {
.ret-08__cur {
animation: none;
}
}
```
## JavaScript
```js
(() => {
const root = document.querySelector('.ret-08');
if (!root) return;
const body = root.querySelector('#ret-08-body');
const out = root.querySelector('#ret-08-out');
const typedEl = root.querySelector('#ret-08-typed');
let buf = '';
const esc = s => s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
const cmds = {
help: () => `<span class="g">Available:</span> help · ls · pwd · whoami · date · neofetch · cowsay <text> · echo <text> · clear`,
ls: () => `<span class="b">projects/</span> <span class="b">art/</span> readme.md <span class="g">retro.sh</span> .secret`,
pwd: () => `/home/guest/retro`,
whoami: () => `guest <span class="d">(uid=1000 groups=demos,retro)</span>`,
date: () => new Date().toString(),
neofetch: () => `<span class="m"> ___ </span> <span class="g">guest</span>@<span class="g">codefronts</span>
<span class="m"> / _ \\ </span> <span class="y">OS:</span> RetroLinux 8.6 "Phosphor"
<span class="m">| | | | </span> <span class="y">Shell:</span> bash 5.1 · pure CSS+JS
<span class="m">| |_| | </span> <span class="y">Term:</span> codefronts-term
<span class="m"> \\___/ </span> <span class="y">Theme:</span> ANSI green-on-black`,
clear: () => { out.innerHTML=''; return null; }
};
function run(raw){
const line = `<div class="l"><span class="ret-08__ps1">guest@codefronts<span class="p">:~$</span></span> ${esc(raw)}</div>`;
let res = '';
const trimmed = raw.trim();
const [c, ...rest] = trimmed.split(/\s+/);
const arg = rest.join(' ');
if (trimmed === '') { res=''; }
else if (c === 'echo') res = esc(arg);
else if (c === 'cowsay') {
const t = esc(arg || 'moo');
const bar = '_'.repeat(t.length + 2);
const bar2 = '-'.repeat(t.length + 2);
res = `<span class="y"> ${bar}\n< ${t} >\n ${bar2}\n \\ ^__^\n \\ (oo)\\_______\n (__)\\ )\\/\\\n ||----w |\n || ||</span>`;
}
else if (cmds[c]) { const r = cmds[c](); if (r===null){return;} res = r; }
else res = `<span class="r">bash: ${esc(c)}: command not found</span> <span class="d">(try 'help')</span>`;
out.insertAdjacentHTML('beforeend', line + (res!=='' ? `<div class="l">${res}</div>` : ''));
body.scrollTop = body.scrollHeight;
}
window.addEventListener('keydown', (e) => {
if (e.metaKey || e.ctrlKey || e.altKey) return;
if (e.key === 'Enter') { run(buf); buf=''; }
else if (e.key === 'Backspace') { buf = buf.slice(0,-1); e.preventDefault(); }
else if (e.key.length === 1) { buf += e.key; }
else return;
typedEl.textContent = buf;
});
// seed one example
run('neofetch');
})();
```