chore: capture homepage baseline
10
.dockerignore
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
.git
|
||||
.gitignore
|
||||
.idea
|
||||
.cache
|
||||
dist
|
||||
node_modules
|
||||
npm-debug.log*
|
||||
.DS_Store
|
||||
.env
|
||||
DEPLOY.md
|
||||
11
.editorconfig
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
4
.env.example
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
DOMAIN=fiwlabs.dev
|
||||
TRAEFIK_NETWORK=proxy
|
||||
TRAEFIK_HTTPS_ENTRYPOINT=websecure
|
||||
TRAEFIK_CERT_RESOLVER=porkbun
|
||||
194
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
## GITATTRIBUTES FOR WEB PROJECTS
|
||||
#
|
||||
# These settings are for any web project.
|
||||
#
|
||||
# Details per file setting:
|
||||
# text These files should be normalized (i.e. convert CRLF to LF).
|
||||
# binary These files are binary and should be left untouched.
|
||||
#
|
||||
# Note that binary is a macro for -text -diff.
|
||||
######################################################################
|
||||
|
||||
## AUTO-DETECT
|
||||
## Handle line endings automatically for files detected as
|
||||
## text and leave all files detected as binary untouched.
|
||||
## This will handle all files NOT defined below.
|
||||
* text=auto
|
||||
|
||||
## SOURCE CODE
|
||||
*.bat text eol=crlf
|
||||
*.coffee text
|
||||
*.css text
|
||||
*.htm text
|
||||
*.html text
|
||||
*.inc text
|
||||
*.ini text
|
||||
*.js text
|
||||
*.json text
|
||||
*.jsx text
|
||||
*.less text
|
||||
*.od text
|
||||
*.onlydata text
|
||||
*.php text
|
||||
*.pl text
|
||||
*.py text
|
||||
*.rb text
|
||||
*.sass text
|
||||
*.scm text
|
||||
*.scss text
|
||||
*.sh text eol=lf
|
||||
*.sql text
|
||||
*.styl text
|
||||
*.tag text
|
||||
*.ts text
|
||||
*.tsx text
|
||||
*.xml text
|
||||
*.xhtml text
|
||||
|
||||
## DOCKER
|
||||
*.dockerignore text
|
||||
Dockerfile text
|
||||
|
||||
## DOCUMENTATION
|
||||
*.markdown text
|
||||
*.md text
|
||||
*.mdwn text
|
||||
*.mdown text
|
||||
*.mkd text
|
||||
*.mkdn text
|
||||
*.mdtxt text
|
||||
*.mdtext text
|
||||
*.txt text
|
||||
AUTHORS text
|
||||
CHANGELOG text
|
||||
CHANGES text
|
||||
CONTRIBUTING text
|
||||
COPYING text
|
||||
copyright text
|
||||
*COPYRIGHT* text
|
||||
INSTALL text
|
||||
license text
|
||||
LICENSE text
|
||||
NEWS text
|
||||
readme text
|
||||
*README* text
|
||||
TODO text
|
||||
|
||||
## TEMPLATES
|
||||
*.dot text
|
||||
*.ejs text
|
||||
*.haml text
|
||||
*.handlebars text
|
||||
*.hbs text
|
||||
*.hbt text
|
||||
*.jade text
|
||||
*.latte text
|
||||
*.mustache text
|
||||
*.njk text
|
||||
*.phtml text
|
||||
*.tmpl text
|
||||
*.tpl text
|
||||
*.twig text
|
||||
|
||||
## LINTERS
|
||||
.babelrc text
|
||||
.csslintrc text
|
||||
.eslintrc text
|
||||
.htmlhintrc text
|
||||
.jscsrc text
|
||||
.jshintrc text
|
||||
.jshintignore text
|
||||
.prettierrc text
|
||||
.stylelintrc text
|
||||
|
||||
## CONFIGS
|
||||
*.bowerrc text
|
||||
*.cnf text
|
||||
*.conf text
|
||||
*.config text
|
||||
.browserslistrc text
|
||||
.editorconfig text
|
||||
.gitattributes text
|
||||
.gitconfig text
|
||||
.gitignore text
|
||||
.htaccess text
|
||||
*.npmignore text
|
||||
*.yaml text
|
||||
*.yml text
|
||||
browserslist text
|
||||
Makefile text
|
||||
makefile text
|
||||
|
||||
## HEROKU
|
||||
Procfile text
|
||||
.slugignore text
|
||||
|
||||
## GRAPHICS
|
||||
*.ai binary
|
||||
*.bmp binary
|
||||
*.eps binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.jng binary
|
||||
*.jp2 binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.jpx binary
|
||||
*.jxr binary
|
||||
*.pdf binary
|
||||
*.png binary
|
||||
*.psb binary
|
||||
*.psd binary
|
||||
*.svg text
|
||||
*.svgz binary
|
||||
*.tif binary
|
||||
*.tiff binary
|
||||
*.wbmp binary
|
||||
*.webp binary
|
||||
|
||||
## AUDIO
|
||||
*.kar binary
|
||||
*.m4a binary
|
||||
*.mid binary
|
||||
*.midi binary
|
||||
*.mp3 binary
|
||||
*.ogg binary
|
||||
*.ra binary
|
||||
|
||||
## VIDEO
|
||||
*.3gpp binary
|
||||
*.3gp binary
|
||||
*.as binary
|
||||
*.asf binary
|
||||
*.asx binary
|
||||
*.fla binary
|
||||
*.flv binary
|
||||
*.m4v binary
|
||||
*.mng binary
|
||||
*.mov binary
|
||||
*.mp4 binary
|
||||
*.mpeg binary
|
||||
*.mpg binary
|
||||
*.ogv binary
|
||||
*.swc binary
|
||||
*.swf binary
|
||||
*.webm binary
|
||||
|
||||
## ARCHIVES
|
||||
*.7z binary
|
||||
*.gz binary
|
||||
*.jar binary
|
||||
*.rar binary
|
||||
*.tar binary
|
||||
*.zip binary
|
||||
|
||||
## FONTS
|
||||
*.ttf binary
|
||||
*.eot binary
|
||||
*.otf binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
|
||||
## EXECUTABLES
|
||||
*.exe binary
|
||||
*.pyc binary
|
||||
7
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
node_modules
|
||||
dist
|
||||
.cache
|
||||
.idea/
|
||||
*.iml
|
||||
.DS_Store
|
||||
.env
|
||||
28
404.html
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>404 - Fi3w0</title>
|
||||
<meta name="robots" content="noindex">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/style.css?v=4">
|
||||
<link rel="stylesheet" href="/css/editorial.css?v=4">
|
||||
<link rel="icon" href="/icon.svg" type="image/svg+xml">
|
||||
<meta name="theme-color" content="#101a21">
|
||||
</head>
|
||||
|
||||
<body class="error-page">
|
||||
<div class="page-grid" aria-hidden="true"></div>
|
||||
<main class="error-shell">
|
||||
<p class="error-code">HTTP 404 / route not found</p>
|
||||
<h1>Wrong path. Good terminal.</h1>
|
||||
<p>The requested route is not running on this host. Return to the system index and try another direction.</p>
|
||||
<a class="button button-primary" href="/">Back to fi3w0 <span aria-hidden="true">→</span></a>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
50
DEPLOY.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# Server deployment
|
||||
|
||||
The production image builds the Webpack site with Node and serves the generated `dist/` directory with Nginx. The container does not publish a host port; Traefik reaches it over an external Docker network.
|
||||
|
||||
## Defaults
|
||||
|
||||
| Setting | Default |
|
||||
| --- | --- |
|
||||
| Domain | `fiwlabs.dev` |
|
||||
| Traefik network | `proxy` |
|
||||
| HTTPS entrypoint | `websecure` |
|
||||
| Certificate resolver | `porkbun` |
|
||||
|
||||
Compose reads overrides from `.env`. The available keys and defaults are documented in `.env.example`.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Point the `A` and optional `AAAA` records for `fiwlabs.dev` to the server.
|
||||
2. Ensure Traefik has its Docker provider enabled.
|
||||
3. Attach Traefik to the same external network configured by `TRAEFIK_NETWORK`.
|
||||
4. Ensure the configured certificate resolver exists in Traefik.
|
||||
|
||||
Create the default shared network once if the Traefik stack has not already created it:
|
||||
|
||||
```sh
|
||||
docker network create proxy
|
||||
```
|
||||
|
||||
## Deploy
|
||||
|
||||
Validate the resolved Compose configuration:
|
||||
|
||||
```sh
|
||||
docker compose -f docker-compose.yml config
|
||||
```
|
||||
|
||||
Build and start the site:
|
||||
|
||||
```sh
|
||||
docker compose -f docker-compose.yml up --build -d
|
||||
```
|
||||
|
||||
Check container health and logs:
|
||||
|
||||
```sh
|
||||
docker compose -f docker-compose.yml ps
|
||||
docker compose -f docker-compose.yml logs -f fiws-page
|
||||
```
|
||||
|
||||
The container exposes `/healthz` internally for Docker health checks. Traefik serves the site at `https://fiwlabs.dev`; the server's `web` entrypoint redirects HTTP requests to HTTPS globally.
|
||||
21
Dockerfile
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# syntax=docker/dockerfile:1.7
|
||||
|
||||
FROM node:22-alpine AS build
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci --ignore-scripts
|
||||
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx:1.27-alpine AS runtime
|
||||
|
||||
COPY deploy/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget -q -O /dev/null http://127.0.0.1/healthz || exit 1
|
||||
19
LICENSE.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) HTML5 Boilerplate
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1816
css/editorial.css
Normal file
2747
css/style.css
Normal file
47
deploy/nginx.conf
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
charset utf-8;
|
||||
server_tokens off;
|
||||
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "DENY" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; base-uri 'self'; form-action 'none'; frame-ancestors 'none'; script-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'" always;
|
||||
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css application/javascript application/json application/manifest+json image/svg+xml;
|
||||
|
||||
location = /healthz {
|
||||
access_log off;
|
||||
default_type text/plain;
|
||||
return 200 "ok\n";
|
||||
}
|
||||
|
||||
location = /index.html {
|
||||
expires -1;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* \.(?:css|js|png|jpe?g|gif|svg|ico|webmanifest)$ {
|
||||
expires 1h;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
error_page 404 /404.html;
|
||||
|
||||
location = /404.html {
|
||||
internal;
|
||||
}
|
||||
}
|
||||
39
docker-compose.yml
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
name: fiws-page
|
||||
|
||||
services:
|
||||
fiws-page:
|
||||
image: fiws-page:latest
|
||||
container_name: fiws-page
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: runtime
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
read_only: true
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
tmpfs:
|
||||
- /var/cache/nginx
|
||||
- /var/run
|
||||
- /tmp
|
||||
expose:
|
||||
- "80"
|
||||
networks:
|
||||
- proxy
|
||||
labels:
|
||||
traefik.enable: "true"
|
||||
traefik.docker.network: "${TRAEFIK_NETWORK:-proxy}"
|
||||
|
||||
traefik.http.services.fiws-page.loadbalancer.server.port: "80"
|
||||
|
||||
traefik.http.routers.fiws-page.rule: "Host(`${DOMAIN:-fiwlabs.dev}`)"
|
||||
traefik.http.routers.fiws-page.entrypoints: "${TRAEFIK_HTTPS_ENTRYPOINT:-websecure}"
|
||||
traefik.http.routers.fiws-page.service: "fiws-page"
|
||||
traefik.http.routers.fiws-page.tls: "true"
|
||||
traefik.http.routers.fiws-page.tls.certresolver: "${TRAEFIK_CERT_RESOLVER:-porkbun}"
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
name: "${TRAEFIK_NETWORK:-proxy}"
|
||||
BIN
favicon.ico
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
icon.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
8
icon.svg
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 192 192" role="img" aria-labelledby="title">
|
||||
<title id="title">Fi3w0 terminal mark</title>
|
||||
<rect width="192" height="192" rx="42" fill="#0b1014"/>
|
||||
<rect x="17" y="17" width="158" height="158" rx="28" fill="none" stroke="#27343c" stroke-width="4"/>
|
||||
<path d="M43 57l40 39-40 39" fill="none" stroke="#f0996e" stroke-linecap="round" stroke-linejoin="round" stroke-width="15"/>
|
||||
<path d="M96 135h53" fill="none" stroke="#8fd4d0" stroke-linecap="round" stroke-width="15"/>
|
||||
<circle cx="146" cy="49" r="8" fill="#c8ee80"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 611 B |
BIN
img/avatar.png
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
img/flux-icon.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
img/flux-overview.jpg
Normal file
|
After Width: | Height: | Size: 141 KiB |
BIN
img/moonlit-shell.jpg
Normal file
|
After Width: | Height: | Size: 234 KiB |
BIN
img/tidewm-logo.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
420
index.html
Normal file
|
|
@ -0,0 +1,420 @@
|
|||
<!doctype html>
|
||||
<html class="no-js" lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Fi3w0 / Alex - Systems Builder</title>
|
||||
<meta name="description" content="Alex, also known as Fi3w0, builds Linux and macOS desktop tools, homelab infrastructure, server tooling, and configurable Minecraft frameworks.">
|
||||
|
||||
<meta property="og:title" content="Fi3w0 / Alex - Systems Builder">
|
||||
<meta property="og:description" content="Linux, homelabs, server tooling, and the systems holding everything up.">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://fiwlabs.dev/">
|
||||
<meta property="og:image" content="https://fiwlabs.dev/img/moonlit-shell.jpg">
|
||||
<meta property="og:image:alt" content="Moonlit Shell running across a custom Arch Linux desktop">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
|
||||
<link rel="canonical" href="https://fiwlabs.dev/">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=IBM+Plex+Mono:ital,wght@0,400;0,500;0,600;1,400&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="css/style.css?v=4">
|
||||
<link rel="stylesheet" href="css/editorial.css?v=4">
|
||||
|
||||
<link rel="icon" href="/favicon.ico" sizes="any">
|
||||
<link rel="icon" href="/icon.svg" type="image/svg+xml">
|
||||
<link rel="apple-touch-icon" href="icon.png">
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<meta name="theme-color" content="#101a21">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a class="skip-link" href="#main">Skip to content</a>
|
||||
<div class="page-grid" aria-hidden="true"></div>
|
||||
|
||||
<header class="site-header">
|
||||
<a class="brand" href="#top" aria-label="Fi3w0 home">
|
||||
<span class="brand-mark" aria-hidden="true">>_</span>
|
||||
<span>fi3w0</span>
|
||||
</a>
|
||||
|
||||
<nav class="site-nav" aria-label="Primary navigation">
|
||||
<span class="nav-gooey" aria-hidden="true">
|
||||
<span class="nav-gooey-blob nav-gooey-blob--trail"></span>
|
||||
<span class="nav-gooey-blob nav-gooey-blob--lead"></span>
|
||||
</span>
|
||||
<a href="#about">About</a>
|
||||
<a href="#work">Work</a>
|
||||
<a href="#stack">Stack</a>
|
||||
<a href="#contact">Contact</a>
|
||||
<a class="nav-pill" href="https://github.com/Fi3w0" target="_blank" rel="noreferrer">
|
||||
GitHub <span aria-hidden="true">↗</span>
|
||||
</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main id="main">
|
||||
<section class="hero" id="top" aria-labelledby="hero-title">
|
||||
<div class="hero-liquid" id="hero-liquid" aria-hidden="true">
|
||||
<pre class="hero-liquid-pre"></pre>
|
||||
<p class="hero-liquid-hint">click and drag to push the water</p>
|
||||
</div>
|
||||
<div class="hero-copy reveal is-visible">
|
||||
<p class="eyebrow"><span class="status-dot" aria-hidden="true"></span> alex@fiw:~ $ cat about.txt</p>
|
||||
<h1 id="hero-title">Alex <span id="glitch-name" data-text="/ Fi3w0">/ Fi3w0</span></h1>
|
||||
<p class="hero-intro">
|
||||
I make Linux and macOS desktop tools, run a homelab, and publish Minecraft server mods.
|
||||
Most of my projects start as something I wanted for my own machine or server,
|
||||
then grow until they are useful to somebody else too.
|
||||
</p>
|
||||
|
||||
<div class="hero-actions">
|
||||
<a class="button button-primary" href="#work">What I am building <span aria-hidden="true">↓</span></a>
|
||||
<a class="button button-ghost" href="https://modrinth.com/user/Fi3w0" target="_blank" rel="noreferrer">My Modrinth mods <span aria-hidden="true">↗</span></a>
|
||||
</div>
|
||||
|
||||
<ul class="hero-signals" aria-label="Profile details">
|
||||
<li><span>01</span> Arch at the desk</li>
|
||||
<li><span>02</span> Ubuntu on the server</li>
|
||||
<li><span>03</span> break it, learn, repeat</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<aside class="terminal-card reveal is-visible" aria-label="A snapshot of Alex's current work">
|
||||
<div class="terminal-chrome">
|
||||
<span>~/workbench</span>
|
||||
<span class="terminal-state">LOCAL</span>
|
||||
</div>
|
||||
<div class="terminal-body">
|
||||
<p><span class="prompt">$</span> git status --short</p>
|
||||
<p class="terminal-output"><span>M</span> homelab/<br><span>M</span> minecraft-mods/<br><span>??</span> desktop-experiments/</p>
|
||||
<p><span class="prompt">$</span> cat NOTES</p>
|
||||
<p class="terminal-output">linux + macos / servers / modding<br>automation / config / self-hosting</p>
|
||||
<p class="terminal-note"># there is always something unfinished</p>
|
||||
</div>
|
||||
|
||||
<div class="profile-chip">
|
||||
<img src="img/avatar.png" alt="Fi3w0's GitHub avatar" width="460" height="460">
|
||||
<div><strong>Alex / Fi3w0</strong><span>Linux, servers, mods</span></div>
|
||||
</div>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
<div class="signal-strip" aria-label="Core interests">
|
||||
<div class="signal-track">
|
||||
<div class="signal-set">
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/archlinux/11171a" alt="" loading="lazy" onerror="this.remove()">Arch Linux</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/ubuntu/11171a" alt="" loading="lazy" onerror="this.remove()">Ubuntu Server</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/docker/11171a" alt="" loading="lazy" onerror="this.remove()">Docker</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/modrinth/11171a" alt="" loading="lazy" onerror="this.remove()">Minecraft tooling</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/wayland/11171a" alt="" loading="lazy" onerror="this.remove()">Wayland</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22%2311171a%22%3E%3Cpath%20d%3D%22M12%202C7.03%202%203%203.34%203%205s4.03%203%209%203%209-1.34%209-3-4.03-3-9-3z%22%2F%3E%3Cpath%20d%3D%22M3%208.2v3.3c0%201.66%204.03%203%209%203s9-1.34%209-3V8.2c-1.6%201.28-5.1%202.3-9%202.3s-7.4-1.02-9-2.3z%22%2F%3E%3Cpath%20d%3D%22M3%2013.7V17c0%201.66%204.03%203%209%203s9-1.34%209-3v-3.3c-1.6%201.28-5.1%202.3-9%202.3s-7.4-1.02-9-2.3z%22%2F%3E%3C%2Fsvg%3E" alt="">Self-hosting</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/json/11171a" alt="" loading="lazy" onerror="this.remove()">Things configured with JSON</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/gnubash/11171a" alt="" loading="lazy" onerror="this.remove()">Bash</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/rust/11171a" alt="" loading="lazy" onerror="this.remove()">Rust</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/go/11171a" alt="" loading="lazy" onerror="this.remove()">Go</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/lua/11171a" alt="" loading="lazy" onerror="this.remove()">Lua</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/kotlin/11171a" alt="" loading="lazy" onerror="this.remove()">Kotlin</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/typescript/11171a" alt="" loading="lazy" onerror="this.remove()">TypeScript</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/githubactions/11171a" alt="" loading="lazy" onerror="this.remove()">GitHub Actions</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/ffmpeg/11171a" alt="" loading="lazy" onerror="this.remove()">FFmpeg</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%229.6%22%20fill%3D%22none%22%20stroke%3D%22%2311171a%22%20stroke-width%3D%221.4%22%2F%3E%3Cpath%20d%3D%22M12%2C2.4%20A9.6%2C9.6%200%200%2C1%2012%2C21.6%20Z%22%20fill%3D%22%2311171a%22%2F%3E%3Ccircle%20cx%3D%228%22%20cy%3D%229.6%22%20r%3D%221.15%22%20fill%3D%22%2311171a%22%2F%3E%3Cpath%20d%3D%22M6.4%2013.8%20Q8.3%2016.6%2010.6%2014.5%22%20fill%3D%22none%22%20stroke%3D%22%2311171a%22%20stroke-width%3D%221.4%22%20stroke-linecap%3D%22round%22%2F%3E%3C%2Fsvg%3E" alt="">macOS</span><i></i>
|
||||
</div>
|
||||
<div class="signal-set" aria-hidden="true">
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/archlinux/11171a" alt="" loading="lazy" onerror="this.remove()">Arch Linux</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/ubuntu/11171a" alt="" loading="lazy" onerror="this.remove()">Ubuntu Server</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/docker/11171a" alt="" loading="lazy" onerror="this.remove()">Docker</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/modrinth/11171a" alt="" loading="lazy" onerror="this.remove()">Minecraft tooling</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/wayland/11171a" alt="" loading="lazy" onerror="this.remove()">Wayland</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22%2311171a%22%3E%3Cpath%20d%3D%22M12%202C7.03%202%203%203.34%203%205s4.03%203%209%203%209-1.34%209-3-4.03-3-9-3z%22%2F%3E%3Cpath%20d%3D%22M3%208.2v3.3c0%201.66%204.03%203%209%203s9-1.34%209-3V8.2c-1.6%201.28-5.1%202.3-9%202.3s-7.4-1.02-9-2.3z%22%2F%3E%3Cpath%20d%3D%22M3%2013.7V17c0%201.66%204.03%203%209%203s9-1.34%209-3v-3.3c-1.6%201.28-5.1%202.3-9%202.3s-7.4-1.02-9-2.3z%22%2F%3E%3C%2Fsvg%3E" alt="">Self-hosting</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/json/11171a" alt="" loading="lazy" onerror="this.remove()">Things configured with JSON</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/gnubash/11171a" alt="" loading="lazy" onerror="this.remove()">Bash</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/rust/11171a" alt="" loading="lazy" onerror="this.remove()">Rust</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/go/11171a" alt="" loading="lazy" onerror="this.remove()">Go</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/lua/11171a" alt="" loading="lazy" onerror="this.remove()">Lua</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/kotlin/11171a" alt="" loading="lazy" onerror="this.remove()">Kotlin</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/typescript/11171a" alt="" loading="lazy" onerror="this.remove()">TypeScript</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/githubactions/11171a" alt="" loading="lazy" onerror="this.remove()">GitHub Actions</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="https://cdn.simpleicons.org/ffmpeg/11171a" alt="" loading="lazy" onerror="this.remove()">FFmpeg</span><i></i>
|
||||
<span class="signal-item"><img class="signal-icon" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%229.6%22%20fill%3D%22none%22%20stroke%3D%22%2311171a%22%20stroke-width%3D%221.4%22%2F%3E%3Cpath%20d%3D%22M12%2C2.4%20A9.6%2C9.6%200%200%2C1%2012%2C21.6%20Z%22%20fill%3D%22%2311171a%22%2F%3E%3Ccircle%20cx%3D%228%22%20cy%3D%229.6%22%20r%3D%221.15%22%20fill%3D%22%2311171a%22%2F%3E%3Cpath%20d%3D%22M6.4%2013.8%20Q8.3%2016.6%2010.6%2014.5%22%20fill%3D%22none%22%20stroke%3D%22%2311171a%22%20stroke-width%3D%221.4%22%20stroke-linecap%3D%22round%22%2F%3E%3C%2Fsvg%3E" alt="">macOS</span><i></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="section about-section" id="about" aria-labelledby="about-title">
|
||||
<header class="section-heading reveal">
|
||||
<p class="section-index">01 / About</p>
|
||||
<h2 id="about-title">What I actually do.</h2>
|
||||
</header>
|
||||
|
||||
<div class="about-layout">
|
||||
<blockquote class="about-quote reveal">
|
||||
<span class="quote-mark" aria-hidden="true">“</span>
|
||||
<p>I care more about the whole machine than winning an argument about one language.</p>
|
||||
<footer>Design it, configure it, deploy it, then fix the boring parts.</footer>
|
||||
</blockquote>
|
||||
|
||||
<div class="about-copy reveal">
|
||||
<p class="lead">
|
||||
Some weeks I am building a Minecraft framework. Other weeks I replace half my desktop
|
||||
shell or add something unnecessary to the mini PC under my desk.
|
||||
</p>
|
||||
<p>
|
||||
My projects jump between low-level desktop work and data-driven server tools, but the part I enjoy
|
||||
is the same: turning rough pieces into something I can run and maintain myself.
|
||||
</p>
|
||||
<p>
|
||||
Linux, systemd, Docker, Traefik, backups, and CI pipelines are familiar territory. I like
|
||||
hot reload, readable config files, updates that can fail safely, and logs that say what went wrong.
|
||||
</p>
|
||||
<p>
|
||||
I write Bash, Go, Lua, and modify Java directly. For Rust, Swift, and larger Kotlin, TypeScript, Python,
|
||||
and QML builds, I use AI agents heavily, then review, test, and integrate the result myself.
|
||||
</p>
|
||||
<div class="language-line">
|
||||
<span>Ukrainian + Russian</span><span>Spanish</span><span>English C1</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="method-grid">
|
||||
<article class="method-card reveal">
|
||||
<span>01</span><h3>Start with the mess</h3><p>Work out the data, failure cases, and who has to maintain it before choosing the clever part.</p>
|
||||
</article>
|
||||
<article class="method-card reveal">
|
||||
<span>02</span><h3>Automate repeats</h3><p>If I have to do it twice, it probably needs a script, an installer, or a CI job.</p>
|
||||
</article>
|
||||
<article class="method-card reveal">
|
||||
<span>03</span><h3>Make it recoverable</h3><p>Reboots, bad input, old versions, and my own mistakes are normal operating conditions.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section work-section" id="work" aria-labelledby="work-title">
|
||||
<header class="section-heading section-heading-row reveal">
|
||||
<div><p class="section-index">02 / Work</p><h2 id="work-title">Projects, tools, experiments.</h2></div>
|
||||
<p>Public repositories, installable mods, and rougher ideas that started on my own machines.</p>
|
||||
</header>
|
||||
|
||||
<article class="current-project reveal" aria-labelledby="tidewm-title">
|
||||
<div class="current-project-main">
|
||||
<div class="current-meta"><span><i aria-hidden="true"></i> Daily-driver compositor</span><span>AI-assisted / evolving</span></div>
|
||||
<p class="current-kicker">Wayland compositor / Rust</p>
|
||||
<div class="tide-heading">
|
||||
<img class="tide-mark" src="img/tidewm-logo.png" alt="" width="48" height="48" loading="lazy">
|
||||
<h3 id="tidewm-title">TideWM</h3>
|
||||
</div>
|
||||
<p>A water-themed Wayland compositor built on Smithay, made because I wanted to see how far I could take it. Tiling (BSP and master/stack), multi-monitor, XWayland, workspaces, and IPC already run as my daily driver; the signature aqua render effects are next.</p>
|
||||
<div class="tag-row current-tags"><span>AI-assisted</span><span>Smithay</span><span>Rust</span><span>Wayland</span></div>
|
||||
<a class="text-link current-repo-link" href="https://github.com/Fi3w0/TideWM" target="_blank" rel="noreferrer">View repository <span aria-hidden="true">↗</span></a>
|
||||
</div>
|
||||
<div class="current-roadmap">
|
||||
<p>Project shape</p>
|
||||
<ol>
|
||||
<li><span>01</span><div><strong>Foundation</strong><small>Rust compositor built directly on Smithay</small></div><b>base</b></li>
|
||||
<li><span>02</span><div><strong>Tiling & compat</strong><small>BSP/master-stack layouts, multi-monitor, XWayland</small></div><b>done</b></li>
|
||||
<li><span>03</span><div><strong>Visual direction</strong><small>Water/aqua render effects, still pending</small></div><b>next</b></li>
|
||||
<li><span>04</span><div><strong>Development method</strong><small>AI-assisted implementation, tested and reviewed by me</small></div><b>method</b></li>
|
||||
</ol>
|
||||
</div>
|
||||
<span class="current-watermark" aria-hidden="true">TIDE</span>
|
||||
<div class="tide-ascii" id="tide-ascii" aria-hidden="true"></div>
|
||||
</article>
|
||||
|
||||
<article class="project-feature reveal" data-repo="Flux">
|
||||
<a class="project-visual project-visual-flux" href="https://github.com/Fi3w0/Flux" target="_blank" rel="noreferrer" aria-label="View Flux on GitHub">
|
||||
<span class="flux-chrome" aria-hidden="true"><i></i><i></i><i></i></span>
|
||||
<img class="flux-icon" src="img/flux-icon.png" alt="" width="256" height="256" loading="lazy">
|
||||
<span class="flux-tags" aria-hidden="true"><span>SwiftUI</span><span>AppKit</span><span>Local-first</span></span>
|
||||
<span class="flux-stack" aria-hidden="true">
|
||||
<b>Tool stack</b>
|
||||
<span class="flux-stack-row"><span>01</span><span>FFmpeg<small>transcode + inspect</small></span></span>
|
||||
<span class="flux-stack-row"><span>02</span><span>yt-dlp<small>downloads</small></span></span>
|
||||
<span class="flux-stack-row"><span>03</span><span>Apple Vision<small>subject isolation</small></span></span>
|
||||
<span class="flux-stack-row"><span>04</span><span>Sparkle<small>auto updates</small></span></span>
|
||||
</span>
|
||||
<span class="flux-status" aria-hidden="true"><i></i> pre-flight checks passed</span>
|
||||
<span class="flux-watermark" aria-hidden="true">FLUX</span>
|
||||
<div class="flux-ascii" id="flux-ascii" aria-hidden="true"></div>
|
||||
<span class="image-label">macOS Tahoe / Apple silicon</span>
|
||||
</a>
|
||||
<div class="project-feature-copy">
|
||||
<div class="project-meta"><span>Latest project</span><span>SwiftUI / AppKit / macOS</span></div>
|
||||
<h3>Flux</h3>
|
||||
<p>A native macOS media workbench: convert, download, edit, and compose media in one focused app. FFmpeg, yt-dlp, and Apple Vision underneath, pre-flight checks that explain failures before a job ever starts, and everything processed locally.</p>
|
||||
<ul class="project-facts">
|
||||
<li><strong>7</strong><span>media engines</span></li>
|
||||
<li><strong>0</strong><span>telemetry</span></li>
|
||||
<li><strong>100%</strong><span>local processing</span></li>
|
||||
</ul>
|
||||
<a class="text-link" href="https://github.com/Fi3w0/Flux" target="_blank" rel="noreferrer">View repository <span aria-hidden="true">↗</span></a>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="project-feature reveal" data-repo="Moonlit-shell">
|
||||
<a class="project-visual" href="https://github.com/Fi3w0/Moonlit-shell" target="_blank" rel="noreferrer" aria-label="View Moonlit Shell on GitHub">
|
||||
<img src="img/moonlit-shell.jpg" alt="Moonlit Shell desktop with its top bar over a nocturnal landscape" width="1600" height="900">
|
||||
<span class="image-label">Daily driver / ThinkPad T14</span>
|
||||
</a>
|
||||
<div class="project-feature-copy">
|
||||
<div class="project-meta"><span>Featured system</span><span>QML / Go / Linux</span></div>
|
||||
<h3>Moonlit Shell</h3>
|
||||
<p>This is the desktop I actually use: Arch, Hyprland, and Quickshell with twelve panels, a live settings app, safe dotfile updates, and no monitoring daemon between the UI and <code>/proc</code>.</p>
|
||||
<ul class="project-facts">
|
||||
<li><strong>12</strong><span>native panels</span></li>
|
||||
<li><strong>1</strong><span>live config</span></li>
|
||||
<li><strong>0</strong><span>glue daemons</span></li>
|
||||
</ul>
|
||||
<a class="text-link" href="https://github.com/Fi3w0/Moonlit-shell" target="_blank" rel="noreferrer">View repository <span aria-hidden="true">↗</span></a>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div class="project-grid">
|
||||
<article class="project-card project-card-warm reveal" data-repo="Fiw-Bosses">
|
||||
<div class="project-card-top"><span class="project-number">01</span><span class="repo-live"><i></i> published</span></div>
|
||||
<div>
|
||||
<p class="project-kicker">Framework / Java</p>
|
||||
<h3>FIW Bosses</h3>
|
||||
<p>A JSON-driven, multi-loader boss framework with HP phases, custom minions, dialogue, loot, hot reload, and more than 50 configurable abilities.</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="tag-row"><span>Fabric</span><span>NeoForge</span><span>Forge</span></div>
|
||||
<a href="https://github.com/Fi3w0/Fiw-Bosses" target="_blank" rel="noreferrer" aria-label="View FIW Bosses on GitHub">↗</a>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="project-card project-card-cool reveal" data-repo="Fiw-Tools">
|
||||
<div class="project-card-top"><span class="project-number">02</span><span class="repo-live"><i></i> published</span></div>
|
||||
<div>
|
||||
<p class="project-kicker">Framework / Kotlin</p>
|
||||
<h3>FIW Custom Items</h3>
|
||||
<p>Server-side custom weapons, armor, crafting, curses, set bonuses, charges, and abilities built entirely through JSON. Vanilla clients can connect.</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="tag-row"><span>JSON</span><span>Hot reload</span><span>Server-side</span></div>
|
||||
<a href="https://github.com/Fi3w0/Fiw-Tools" target="_blank" rel="noreferrer" aria-label="View FIW Custom Items on GitHub">↗</a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="project-list">
|
||||
<article class="project-row reveal" data-repo="Fiw-Anticheat">
|
||||
<span class="row-index">03</span>
|
||||
<div><p>Security tooling</p><h3>FIW AntiCheat</h3></div>
|
||||
<p>Nonce challenges, mod signatures, resource-pack auditing, and honest limits across six loader/version targets.</p>
|
||||
<span class="row-tech">Java / SHA-256</span>
|
||||
<a href="https://github.com/Fi3w0/Fiw-Anticheat" target="_blank" rel="noreferrer" aria-label="View FIW AntiCheat on GitHub">↗</a>
|
||||
</article>
|
||||
<article class="project-row reveal" data-repo="Fiw-Graves">
|
||||
<span class="row-index">04</span>
|
||||
<div><p>Reliability</p><h3>FIW Graves</h3></div>
|
||||
<p>Packet-only grave markers, world-native persistence, rollback history, and a second loot safety net.</p>
|
||||
<span class="row-tech">Java / Packets</span>
|
||||
<a href="https://github.com/Fi3w0/Fiw-Graves" target="_blank" rel="noreferrer" aria-label="View FIW Graves on GitHub">↗</a>
|
||||
</article>
|
||||
<article class="project-row reveal">
|
||||
<span class="row-index">05</span>
|
||||
<div><p>Server operations</p><h3>FIW Admin Utilities</h3></div>
|
||||
<p>Maintenance mode, lag watchdog, entity sweeping, vanish, freeze, and item bans in one lightweight admin mod.</p>
|
||||
<span class="row-tech">Fabric / NeoForge</span>
|
||||
<a href="https://modrinth.com/mod/fiw-admin-utilitys" target="_blank" rel="noreferrer" aria-label="View FIW Admin Utilities on Modrinth">↗</a>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="modrinth-panel reveal">
|
||||
<header class="modrinth-heading">
|
||||
<div>
|
||||
<p class="modrinth-label"><span aria-hidden="true"></span> Published on Modrinth</p>
|
||||
<h3>Mods people can install.</h3>
|
||||
</div>
|
||||
<a class="text-link" href="https://modrinth.com/user/Fi3w0" target="_blank" rel="noreferrer">View creator profile <span aria-hidden="true">↗</span></a>
|
||||
</header>
|
||||
|
||||
<p class="modrinth-summary">Every mod above (plus Warp, Graves, and Tickwatch from the archive) ships through one Modrinth profile — same JSON-config philosophy, same hot reload, across Fabric, Forge, and NeoForge.</p>
|
||||
|
||||
<div class="modrinth-stats">
|
||||
<div><strong>7</strong><span>mods published</span></div>
|
||||
<div><strong>3</strong><span>loaders supported</span></div>
|
||||
<div><strong>1</strong><span>creator profile</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section archive-section" aria-labelledby="archive-title">
|
||||
<header class="section-heading section-heading-row reveal">
|
||||
<div><p class="section-index">03 / Repositories</p><h2 id="archive-title">Other things I made.</h2></div>
|
||||
<a class="text-link" href="https://github.com/Fi3w0?tab=repositories" target="_blank" rel="noreferrer">All repositories <span aria-hidden="true">↗</span></a>
|
||||
</header>
|
||||
|
||||
<div class="archive-grid">
|
||||
<a class="archive-item reveal" href="https://github.com/Fi3w0/Fiw-Warp" target="_blank" rel="noreferrer"><span>Fiw Warp</span><small>Kotlin / server teleports</small><b>↗</b></a>
|
||||
<a class="archive-item reveal" href="https://github.com/Fi3w0/Fiw-Clock" target="_blank" rel="noreferrer"><span>Tickwatch</span><small>Crash-safe player stats</small><b>↗</b></a>
|
||||
<a class="archive-item reveal" href="https://github.com/Fi3w0/Firefox-Privacy" target="_blank" rel="noreferrer"><span>Firefox Privacy</span><small>Cross-platform hardening</small><b>↗</b></a>
|
||||
<a class="archive-item reveal" href="https://github.com/Fi3w0/HomePage" target="_blank" rel="noreferrer"><span>HomePage</span><small>Live homelab dashboard</small><b>↗</b></a>
|
||||
<a class="archive-item reveal" href="https://github.com/Fi3w0/FiwStoryMod" target="_blank" rel="noreferrer"><span>Fiw Story Mod</span><small>SMP artifacts + lore</small><b>↗</b></a>
|
||||
<a class="archive-item reveal" href="https://github.com/Fi3w0/Naoya-Mod" target="_blank" rel="noreferrer"><span>Naoya Mod</span><small>Fabric ability system</small><b>↗</b></a>
|
||||
<a class="archive-item reveal" href="https://github.com/Fi3w0/DevourerPlugin" target="_blank" rel="noreferrer"><span>Devourer Plugin</span><small>Asymmetric Paper PvP</small><b>↗</b></a>
|
||||
<a class="archive-item reveal" href="https://github.com/Fi3w0/Fi3w0-Hyprland" target="_blank" rel="noreferrer"><span>Fi3w0 Hyprland</span><small>The original daily dots</small><b>↗</b></a>
|
||||
<a class="archive-item reveal" href="https://github.com/Fi3w0/Fiw-ModChecklist" target="_blank" rel="noreferrer"><span>Fiw ModChecklist</span><small>Whitelist prototype</small><b>↗</b></a>
|
||||
<a class="archive-item reveal" href="https://github.com/Fi3w0/VeeBotV4.2" target="_blank" rel="noreferrer"><span>VeeBot V4.2</span><small>Python / Discord</small><b>↗</b></a>
|
||||
<a class="archive-item reveal archive-item-paused" href="https://github.com/Fi3w0/Brota" target="_blank" rel="noreferrer"><span>Brota</span><small>Paused mobile prototype</small><b>↗</b></a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section stack-section" id="stack" aria-labelledby="stack-title">
|
||||
<header class="section-heading reveal">
|
||||
<p class="section-index">04 / Tools</p>
|
||||
<h2 id="stack-title">What is usually open in my terminal.</h2>
|
||||
<p class="stack-intro">Kitty as the daily emulator, running on a MacBook (macOS) — my main device — SSH'd out to the Arch desktop and the Ubuntu server for everything else.</p>
|
||||
</header>
|
||||
|
||||
<div class="stack-layout">
|
||||
<article class="stack-card stack-card-main reveal">
|
||||
<p class="stack-label">Home turf</p>
|
||||
<h3>Linux / systems</h3>
|
||||
<div class="stack-tags"><span class="tag-strong">Arch Linux</span><span class="tag-strong">Bash</span><span>Ubuntu Server</span><span>systemd</span><span>SSH</span><span>Networking</span></div>
|
||||
</article>
|
||||
<article class="stack-card reveal">
|
||||
<p class="stack-label">Ship + operate</p>
|
||||
<h3>Infrastructure</h3>
|
||||
<div class="stack-tags"><span class="tag-strong">Docker</span><span class="tag-strong">Compose</span><span>Traefik</span><span>Portainer</span><span>GitHub Actions</span><span>Backups</span></div>
|
||||
</article>
|
||||
<article class="stack-card reveal">
|
||||
<p class="stack-label">Build surface</p>
|
||||
<h3>Code + config</h3>
|
||||
<div class="stack-tags"><span class="tag-strong">Go</span><span class="tag-strong">Lua</span><span>Rust / AI-assisted</span><span>Java</span><span>Kotlin</span><span>TypeScript</span><span>QML</span><span>JSON</span></div>
|
||||
</article>
|
||||
<article class="stack-card stack-card-learning reveal">
|
||||
<p class="stack-label">Learning next</p>
|
||||
<h3>Kubernetes, Terraform, Ansible</h3>
|
||||
<p>I am learning these when a real problem gives me a reason, not just to collect more logos.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="contact-section" id="contact" aria-labelledby="contact-title">
|
||||
<div class="contact-orbit" aria-hidden="true"><span></span><span></span><span></span></div>
|
||||
<p class="section-index reveal">05 / Contact</p>
|
||||
<h2 id="contact-title" class="reveal">Say hello.</h2>
|
||||
<p class="contact-copy reveal">Linux, infrastructure, self-hosting, Minecraft tooling, or a strange project you cannot stop thinking about are all good reasons to message me.</p>
|
||||
<div class="contact-links reveal">
|
||||
<a href="https://github.com/Fi3w0" target="_blank" rel="noreferrer"><span>GitHub</span><small>@Fi3w0</small><b>↗</b></a>
|
||||
<a href="https://t.me/fi3w0" target="_blank" rel="noreferrer"><span>Telegram</span><small>@fi3w0</small><b>↗</b></a>
|
||||
<button type="button" id="copy-discord"><span>Discord</span><small id="discord-label">fi3w0 - click to copy</small><b aria-hidden="true">+</b></button>
|
||||
</div>
|
||||
<p class="copy-status" id="copy-status" role="status" aria-live="polite"></p>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
<a class="brand" href="#top"><span class="brand-mark" aria-hidden="true">>_</span><span>fi3w0</span></a>
|
||||
<p><a href="https://git.fiwlabs.dev/" target="_blank" rel="noreferrer">git.fiwlabs.dev</a> / self-hosted Git</p>
|
||||
<p class="footer-prompt" aria-hidden="true"><span class="prompt">$</span> exit 0<span class="cursor-blink">_</span></p>
|
||||
<p>© <span id="year">2026</span> Alex / Fi3w0</p>
|
||||
</footer>
|
||||
|
||||
<script src="js/app.js?v=4" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
5116
package-lock.json
generated
Normal file
26
package.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "fi3w0-portfolio",
|
||||
"version": "1.0.0",
|
||||
"description": "Personal systems and development portfolio for Alex (Fi3w0).",
|
||||
"private": true,
|
||||
"keywords": [
|
||||
"portfolio",
|
||||
"devops",
|
||||
"systems",
|
||||
"homelab"
|
||||
],
|
||||
"license": "MIT",
|
||||
"author": "Alex (Fi3w0)",
|
||||
"scripts": {
|
||||
"start": "webpack serve --open --config webpack.config.dev.js",
|
||||
"build": "webpack --config webpack.config.prod.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"html-webpack-plugin": "^5.6.0",
|
||||
"webpack": "^5.91.0",
|
||||
"webpack-cli": "^5.1.4",
|
||||
"webpack-dev-server": "^5.0.4",
|
||||
"webpack-merge": "^5.10.0"
|
||||
}
|
||||
}
|
||||
5
robots.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# www.robotstxt.org/
|
||||
|
||||
# Allow crawling of all content
|
||||
User-agent: *
|
||||
Disallow:
|
||||
15
site.webmanifest
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"short_name": "Fi3w0",
|
||||
"name": "Fi3w0 / Alex - Systems Builder",
|
||||
"icons": [
|
||||
{
|
||||
"src": "icon.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
}
|
||||
],
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#101a21",
|
||||
"theme_color": "#101a21"
|
||||
}
|
||||
12
webpack.common.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
app: './js/app.js',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
clean: true,
|
||||
filename: './js/app.js',
|
||||
},
|
||||
};
|
||||
13
webpack.config.dev.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'development',
|
||||
devtool: 'inline-source-map',
|
||||
devServer: {
|
||||
liveReload: true,
|
||||
hot: true,
|
||||
open: true,
|
||||
static: ['./'],
|
||||
},
|
||||
});
|
||||
26
webpack.config.prod.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
template: './index.html',
|
||||
inject: false,
|
||||
}),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: 'img', to: 'img' },
|
||||
{ from: 'css', to: 'css' },
|
||||
{ from: 'icon.svg', to: 'icon.svg' },
|
||||
{ from: 'favicon.ico', to: 'favicon.ico' },
|
||||
{ from: 'robots.txt', to: 'robots.txt' },
|
||||
{ from: 'icon.png', to: 'icon.png' },
|
||||
{ from: '404.html', to: '404.html' },
|
||||
{ from: 'site.webmanifest', to: 'site.webmanifest' },
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||