Early prototype — usable as a portfolio start point, but expect rough edges, missing features, and breaking changes. Feedback and contributions welcome.
A content-first terminal portfolio template. Add your text and files, adjust a few settings, deploy — no code required for a complete site.
Visitors boot into a BIOS screen, then explore your work with shell commands: ls, cat, wget, and more.
- How it is organised
- Quick start
- Content checklist
- Your content
- Site settings
- Writing tips
- Preview and publish
- What visitors can do
- File reference
- Resources used
- License
- Contributing
TTYfolio separates what you say from how the terminal works. Each layer has one job — change only the layer you need.
| Layer | You edit | Purpose |
|---|---|---|
| Content | src/data/vfs/*.md |
Bio, projects, contact, certs — what visitors read |
| Assets | assets/documents/ |
Photo, CV, social preview image |
| Identity | src/data/config.js |
Domain, shell username, status bar |
| Intro | src/data/boot.js |
Boot screen copy and timing (optional) |
| Engine | src/ TypeScript |
Terminal UI, shell, rendering (template code — rarely touched) |
| Build | scripts/ |
Turns content into a deployable site (template code) |
Content and assets are enough to go live. Identity takes five fields. Everything else is optional polish.
Generated files in src/data/generated/ are rebuilt automatically — never edit them by hand.
You need Node.js 18 or newer.
npm install
npm run devOpen http://localhost:3000. Save a file and the page reloads automatically.
If port 3000 is already in use:
fuser -k 3000/tcp 2>/dev/null; lsof -ti :3000 | xargs -r kill -9
npm run devWork through this list — each step is independent:
- Replace text in
src/data/vfs/about.txt.md - Replace text in
src/data/vfs/contact.txt.md - Replace text in
src/data/vfs/projects.txt.md - Update
src/data/vfs/certs.txt.md(optional) - Drop in
assets/documents/profile.jpg(or.png),cv.pdf,site.jpg(or.png) - Set your domain and username in
src/data/config.js - Run
npm run buildand uploaddist/
That is a complete portfolio.
All copy lives in src/data/vfs/. Each .md file becomes a file in the virtual home folder.
Edit the body below the front matter (--- block at the top). The front matter controls the filename and shell alias — leave it unless you are adding a new file.
File: src/data/vfs/about.txt.md
Write who you are and what you do. Use **bold** for headings. Link to other files with markdown, for example [see certs.txt](certs.txt).
Optional — add to the front matter for search engines and the browser tab title:
displayName: Your Name
jobTitle: Developer
location: EarthVisitors open this with cat about.txt or the [ABOUT] menu button.
File: src/data/vfs/projects.txt.md
List your projects. A simple pattern:
# Projects
> My App [live demo](https://example.com)
Short description of what it does.
[GitHub](https://github.com/you/my-app)Repeat the block for each project. Lines starting with > are shown as titles.
File: src/data/vfs/contact.txt.md
Edit the list items directly — links live here, not in config.js:
- **Email:** [you@example.com](mailto:you@example.com)
- **GitHub:** [github.com/you](https://github.com/you)
- **CV:** [DOWNLOAD CV](cv.pdf)Links become clickable in the terminal. cv.pdf triggers a download; .txt files open with cat.
File: src/data/vfs/certs.txt.md
A simple bullet list. Link to it from your about page if you like.
Replace files in assets/documents/:
| File | Used for |
|---|---|
profile.jpg or profile.png |
Shown when visitors run cat profile_pic.jpg (build outputs optimized .jpg) |
cv.pdf |
Downloaded via wget cv.pdf or the contact link |
site.jpg or site.png |
Preview image when your link is shared on social media (build outputs optimized .jpg) |
The vfs entries (profile_pic.jpg.md, cv.pdf.md) already point at these paths — swap the files, not the config.
File: src/data/config.js
Shell identity only — no bio, no contact links:
| Setting | Example | Purpose |
|---|---|---|
url |
https://yoursite.com |
Canonical URL for SEO and sitemap |
hostname |
yoursite.com |
Shown in the shell prompt and boot text |
handle |
guest |
Username in the prompt (guest@yoursite.com) |
statusBar.value |
AVAILABLE FOR HIRE |
Short status line at the bottom |
statusBar.menu |
[ABOUT], etc. |
Quick-action buttons |
profileRedaction |
(optional) | Glitchy censor band on cat profile_pic.jpg — see below |
Boot screen text and timing: src/data/boot.js.
Add profileRedaction to src/data/config.js to draw a horizontal black censor band over part of your profile photo when visitors run cat profile_pic.jpg. Each view picks a random band position and width within your ranges, with slight per-line drift for a glitchy look.
Redaction applies only to the profile image in normal scanline mode. Other images are untouched.
enhance pipe — append | enhance to any cat of an image file to reveal it without redaction and at full resolution (no retro pixelation). The scanline reveal runs slower for effect.
cat profile_pic.jpg # pixelated terminal look + redaction band (if configured)
cat profile_pic.jpg | enhance # full image, no censor bandenhance is not a separate command; it only works as a pipe after cat on image files. Works on any image in the vfs, not just the profile photo.
All row values are pixels in the source image (check dimensions in an image editor). Band position and width use fractions from 0 to 1 across the image width.
| Field | Meaning |
|---|---|
lineStart |
Top row of the censored band (y pixel) |
lineEnd |
Bottom row of the censored band (y pixel) |
visibleMin / visibleMax |
Min and max width of the black bar as a fraction of image width |
startMin / startMax |
Min and max left edge of the bar as a fraction of image width |
lineJitter |
Optional per-row drift (default 0.015; lower = tighter band) |
Example — censor a band across the middle third of a ~300 px-tall portrait:
profileRedaction: {
lineStart: 100,
lineEnd: 200,
visibleMin: 0.2,
visibleMax: 0.4,
startMin: 0.15,
startMax: 0.45,
lineJitter: 0.01,
},Omit profileRedaction entirely to show the photo without censorship.
- Bold with
**double asterisks**. - Headings with
# Titleor**Title**on their own line. - Links:
[label](url)for web and email,[label](file.txt)for other terminal files. - Contact lines:
- **Label:** valueor- **Label:** [text](url).
Run cat help.txt in the terminal for a short command list.
npm run dev # local preview with auto-reload
npm run build # production files in dist/Upload the dist/ folder to any static host (GitHub Pages, Netlify, Cloudflare Pages, etc.).
Before going live, update assets/robots.txt with your real domain if you use it.
| Command | What it does |
|---|---|
ls |
List files in the home folder |
ls -h |
Also show hidden files (e.g. .bashrc) |
cat about.txt |
Read a text file |
wget cv.pdf |
Download your CV |
help |
Show available commands |
clear |
Clear the screen |
Shortcuts like about, contact, and projects work as aliases for cat ….
| Path | Layer | Role |
|---|---|---|
src/data/vfs/*.md |
Content | All terminal file text |
assets/documents/ |
Assets | Photo, CV, social preview |
src/data/config.js |
Identity | Domain, username, status bar |
src/data/boot.js |
Intro | Boot screen |
src/ (TypeScript) |
Engine | Terminal app — see CONTRIBUTING.md |
scripts/ |
Build | Compile content → static site |
dist/ |
Output | Deploy this folder |
- Phaser — terminal rendering and input
- VT323 and Press Start 2P — terminal fonts (Fontsource)
- gray-matter — reads content file headers at build time
- esbuild — bundles the app
- BetterCRT shader — bundled in
assets/shaders/bettercrt.glsl
PolyForm Noncommercial License 1.0.0 — free for personal and non-commercial use; commercial use requires separate permission.
Your code is under this license. Dependencies (Phaser, fonts, etc.) remain under their own licenses — see THIRD_PARTY_NOTICES.md. Phaser’s full MIT text ships at dist/assets/vendor/phaser.LICENSE.md.
See CONTRIBUTING.md for architecture, coding standards, and pull request guidelines.






