~/fanaperana · PortfolioSystems tinkerer · Rust · TypeScript · agentic AI, tiny shells, and interesting OSes.
A handwritten, open-source portfolio site that doubles as a live demo: a real pipeline shell written in Rust, compiled to WebAssembly, embedded in a Svelte 5 + Vite app, and driven from an in-page terminal you can actually type into.
If you're a recruiter or hiring manager — this repo is the portfolio. Browse the site, or read on.
A handwritten portfolio — no template, no headless CMS.
An in-browser terminal where help, ls, open <slug>, theme <name> and a tiny pipeline
language all work.
The pipeline language is parsed and evaluated by a Rust crate (mini-shell) compiled to WASM.
Example pipelines you can type on the live site:
sh "projects | lang rust | count"
sh "projects | grep chess | names"
sh "projects | stars >= 3 | sort stars desc"
Press ? anywhere on the page to jump focus into the terminal.
Three colour themes baked in: matrix, amber, mono — run theme amber inside the terminal.
| Layer | Tech |
|---|---|
| Shell | Rust → wasm-bindgen → wasm-pack · crates/mini-shell |
| Frontend | Svelte 5 (runes) + TypeScript + Vite 8 |
| Styling | Tailwind CSS v4 + shadcn-svelte primitives + bits-ui |
| Icons | @lucide/svelte + custom SVG |
| Content | Statically typed project list in src/lib/data/projects.ts |
| Hosting | Static build — deployable anywhere (GitHub Pages / Cloudflare Pages / Netlify / Vercel) |
I ship at the boundaries — Rust doing heavy lifting, the web doing presentation, everything glued with small, hand-rolled tools. My GitHub is basically a sketchbook of that boundary:
Full curated list, including private projects with thumbnails, lives in
src/lib/data/projects.ts.
I'm currently open to full-time, contract, and research roles in systems programming, Rust, applied AI / agentic systems, and developer-tool engineering. Remote-first, happy to travel.
public/resume.pdf and it will appear in the hero.The site renders this information from
PROFILEinsrc/lib/data/projects.ts— swap the placeholder values there and everything (hero, footer,whoami, SEO metadata) updates at once.
Requires Node 20+, pnpm, and the Rust toolchain (rustup) plus wasm-pack.
# 1. install JS deps
pnpm install
# 2. install the Rust → WASM toolchain (once)
cargo install wasm-pack
# 3. build the Rust shell to WASM (dev or release)
pnpm wasm:dev # or: pnpm wasm
# 4. run the dev server
pnpm dev
| Script | What it does |
|---|---|
pnpm build |
WASM + build-time GitHub fetch + production Vite bundle |
pnpm preview |
Preview the production build |
pnpm fetch:github |
Refresh src/lib/data/github.generated.ts |
pnpm check |
svelte-check + tsc on the Node-side config |
pnpm test:rust |
cargo test -p mini-shell |
scripts/fetch-github.mjs runs on every build and bakes live data into the bundle:
It reads a token from GH_TOKEN / GITHUB_TOKEN, and falls back to
gh auth token when you run locally. The generated file
src/lib/data/github.generated.ts is committed so private READMEs you
fetched locally stay baked into the deployed site — no CI secrets needed.
CI uses the default GITHUB_TOKEN to refresh public stats; the fetch
script merges, preserving any README it can't re-fetch.
To refresh before pushing:
pnpm fetch:github # pulls fresh stats + private READMEs via `gh auth`
git add src/lib/data/github.generated.ts && git commit -m "data: refresh github snapshot"
| Keys | What it does |
|---|---|
| ⌘ / Ctrl + K | open the command palette |
| / | open the palette (when not typing) |
| Esc | close palette or project modal |
Project cards open a case-study modal (URL-addressable via #/p/<slug>)
that renders the repo's README with sanitized HTML (marked + DOMPurify).
crates/mini-shell/ # Rust pipeline-language crate, compiled to WASM
public/ # favicon, og-image, resume.pdf, thumbnails/
src/
App.svelte # Page composition
app.css # Tailwind v4 theme + keyframe animations
lib/components/ # Hero, About, Terminal, Projects, Nav, Footer, ui/*, AnimatedBackdrop
lib/terminal/ # Command definitions + dispatch for the in-page shell
lib/data/projects.ts # Source of truth: PROFILE + curated projects
lib/wasm/shell.ts # Thin wrapper around the wasm-pack output
When publishing, add these topics to the repo's About panel — helps SEO and discovery:
portfolio svelte svelte5 rust webassembly wasm tauri typescript
vite tailwindcss terminal developer-portfolio open-to-work
agentic-ai systems-programming resume hacker-aesthetic
Code in this repo is released under the MIT License. Project descriptions, thumbnails, and the curated project list are personal content — please don't reuse them as-is to represent yourself.
cargo build --release.
Systems tinkerer · Rust · TypeScript · agentic AI, tiny shells, and interesting OSes.
This repo is my portfolio site. It doubles as a showcase and as a demo of the kind of thing I like building: a real pipeline shell written in Rust, compiled to WebAssembly, embedded in a Svelte 5 app, and driven from an in-page terminal you can actually type into.
GitHub: https://github.com/Fanaperana
A handwritten portfolio — no template, no headless CMS.
An in-browser terminal where help, ls, open <slug>, theme <name> and a tiny pipeline
language all work.
The pipeline language is parsed and evaluated by a Rust crate (mini-shell) compiled to WASM.
Example pipelines you can type on the live site:
sh "projects | lang rust | count"
sh "projects | grep chess | names"
sh "projects | stars >= 3 | sort stars desc"
Press ? anywhere on the page to jump focus into the terminal.
| Layer | Tech |
|---|---|
| Shell | Rust → wasm-bindgen → wasm-pack (crates/mini-shell) |
| Frontend | Svelte 5 (runes) + TypeScript + Vite 8 |
| Styling | Tailwind CSS v4 + shadcn-svelte primitives + bits-ui |
| Content | Statically typed project list in src/lib/data/projects.ts |
The full curated list lives in src/lib/data/projects.ts. Highlights:
Some entries point at private repos; those are surfaced here as proof-of-work with descriptions and thumbnails but intentionally not linkable to source.
Requires Node 20+, pnpm, and the Rust toolchain (rustup) plus wasm-pack.
# 1. install JS deps
pnpm install
# 2. install the Rust → WASM toolchain (once)
cargo install wasm-pack
# 3. build the Rust shell to WASM (dev or release)
pnpm wasm:dev # or: pnpm wasm
# 4. run the dev server
pnpm dev
Other scripts:
| Script | What it does |
|---|---|
pnpm build |
Build the WASM crate + the production Vite bundle |
pnpm preview |
Preview the production build |
pnpm check |
svelte-check + tsc on the Node-side config |
pnpm test:rust |
cargo test -p mini-shell |
crates/mini-shell/ # Rust pipeline-language crate, compiled to WASM
public/thumbnails/ # Project thumbnails (so private repos still ship art)
src/
App.svelte # Page composition
lib/components/ # Hero, About, Terminal, Projects, ProjectCard, Nav, Footer, ui/*
lib/terminal/ # Command definitions + dispatch for the in-page shell
lib/data/projects.ts # Source of truth for the project list + profile
lib/wasm/shell.ts # Thin wrapper around the wasm-pack output
Code in this repo is released under the MIT License. Project descriptions, thumbnails, and the curated project list are personal content — please don't reuse them as-is to represent yourself.
This template should help get you started developing with Svelte and TypeScript in Vite.
Check out SvelteKit, which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more.
Why use this over SvelteKit?
This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other create-vite templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project.
Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate.
Why global.d.ts instead of compilerOptions.types inside jsconfig.json or tsconfig.json?
Setting compilerOptions.types shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding svelte and vite/client type information.
Why include .vscode/extensions.json?
Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project.
Why enable allowJs in the TS template?
While allowJs: false would indeed prevent the use of .js files in the project, it does not prevent the use of JavaScript syntax in .svelte files. In addition, it would force checkJs: false, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant.
Why is HMR not preserving my local component state?
HMR state preservation comes with a number of gotchas! It has been disabled by default in both svelte-hmr and @sveltejs/vite-plugin-svelte due to its often surprising behavior. You can read the details here.
If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR.
// store.ts
// An extremely simple external store
import { writable } from 'svelte/store'
export default writable(0)