erase background
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -28,3 +28,8 @@ npm-debug.log*
|
||||
|
||||
# Generated
|
||||
static/css/site.compiled.css
|
||||
|
||||
# Nix
|
||||
result
|
||||
result-*
|
||||
.direnv/
|
||||
|
||||
13
Makefile
13
Makefile
@@ -1,4 +1,4 @@
|
||||
.PHONY: help serve size validate clean
|
||||
.PHONY: help serve size validate tidy ascii clean
|
||||
|
||||
help: ## Show this help
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
||||
@@ -28,5 +28,14 @@ validate: ## Quick HTML sanity check (counts opening vs closing tags)
|
||||
diff <(echo "$$open") <(echo "$$close") || true; \
|
||||
done
|
||||
|
||||
clean: ## Remove generated artifacts
|
||||
tidy: ## Run html-tidy on every .html
|
||||
@for f in *.html; do echo "--- $$f ---"; tidy -e -q $$f || true; done
|
||||
|
||||
ascii: ## Regenerate the body-rain ASCII art (needs chafa)
|
||||
@mkdir -p static/ascii
|
||||
chafa -f symbols -c none -s 240x60 --symbols ascii --animate off \
|
||||
static/img/og-image-bg.svg > static/ascii/rain.txt
|
||||
@echo "Regenerated static/ascii/rain.txt (from static/img/og-image-bg.svg)"
|
||||
|
||||
clean: ## Remove build artefacts
|
||||
@rm -rf bin/ node_modules/ dist/
|
||||
|
||||
116
README.md
116
README.md
@@ -39,8 +39,104 @@ The `Makefile` wraps the Python server and a few convenience commands:
|
||||
make serve # python3 -m http.server 8000
|
||||
make size # report file sizes
|
||||
make validate # quick HTML syntax check (search for unclosed tags)
|
||||
make tidy # run html-tidy on every .html (warnings only)
|
||||
make ascii # regenerate the body-rain ASCII art (needs `chafa`)
|
||||
```
|
||||
|
||||
## Animated ASCII body background
|
||||
|
||||
The page background is **animated ASCII art** generated by
|
||||
[`chafa`](https://github.com/hpjansson/chafa) from a stripped-down version
|
||||
of the Open Graph card (`static/img/og-image-bg.svg` — black background,
|
||||
grid, the `tui-pages` wordmark, the "A framework for / building TUIs in
|
||||
Rust." headline, and the subtitle, with the install button cropped out
|
||||
because chafa was rendering it as a row of `@` symbols). The art is plain
|
||||
text inside `<pre>` blocks; the animation is pure CSS.
|
||||
|
||||
```
|
||||
static/ascii/rain.txt ← 240 × ~50 grid of og-image-bg.svg
|
||||
```
|
||||
|
||||
To re-render after changing the source SVG (you need `chafa` on `$PATH`,
|
||||
or run inside `nix develop`):
|
||||
|
||||
```bash
|
||||
make ascii
|
||||
```
|
||||
|
||||
The source SVG is committed (`static/img/og-image-bg.svg`) so `make ascii`
|
||||
is fully reproducible — no ImageMagick, no cropping step.
|
||||
|
||||
### How it's wired
|
||||
|
||||
- A single `<div class="tp-ascii-rain" aria-hidden="true">` is placed at
|
||||
the top of `<body>`, fixed full-bleed, with `z-index: -1` and
|
||||
`pointer-events: none` so it never blocks the UI.
|
||||
- Inside, a `<pre class="tp-ascii-rain-track">` holds **two byte-identical
|
||||
copies** of the chafa output stacked vertically for a seamless
|
||||
`translateY(0 → -50%)` loop over 90 s.
|
||||
- Color is `#f4a26b` (warm rust-orange) at 14% opacity with a faint
|
||||
`text-shadow` glow — picks up the brand colour and reads as a subtle
|
||||
background, not a wall of `@` blocks.
|
||||
- A `::after` overlay draws a 2 px CRT scanline pattern that ticks
|
||||
downward at 8 s/cycle.
|
||||
- The hero section has a `.tp-ascii-hero-overlay` class that paints a
|
||||
vertical gradient over the top of the page, so the hero text stays
|
||||
readable while the ASCII art shows through on the bottom half and below.
|
||||
- The light theme inverts to dark text on light, dimmer, no glow.
|
||||
- All animations are disabled inside
|
||||
`@media (prefers-reduced-motion: reduce)`.
|
||||
|
||||
The hero (`#hero`) is **not** animated — it keeps the original static
|
||||
`static/img/terminal-default.svg` mockup, exactly as designed.
|
||||
|
||||
## Nix (optional, recommended)
|
||||
|
||||
A `flake.nix` is included that ships a reproducible dev shell, a buildable
|
||||
package, a `serve` app, and an `html-tidy` check. You do **not** need Nix to
|
||||
use this project — it's a convenience.
|
||||
|
||||
```bash
|
||||
# Enter the dev shell (gives you: gnumake, python3, asciinema, html-tidy, …)
|
||||
nix develop
|
||||
|
||||
# Build the whole site → ./result/ (16 files, ~150 kB, ready to upload)
|
||||
nix build
|
||||
ls result/
|
||||
|
||||
# Build + serve on http://localhost:8000 (or $PORT)
|
||||
nix run .#serve
|
||||
|
||||
# Validate the HTML, format the flake
|
||||
nix flake check
|
||||
nix fmt
|
||||
```
|
||||
|
||||
### What the flake provides
|
||||
|
||||
| Output | Command | What it does |
|
||||
| --- | --- | --- |
|
||||
| `packages.<sys>.default` | `nix build` | Assembles the static site into a single derivation |
|
||||
| `apps.<sys>.serve` | `nix run .#serve` | Builds the package, then `python3 -m http.server` it |
|
||||
| `devShells.<sys>.default` | `nix develop` | Shell with `make`, `python3`, `asciinema`, `tidy`, `curl` |
|
||||
| `checks.<sys>.tidy` | `nix flake check` | Runs `html-tidy` over every `.html` in the built site |
|
||||
| `formatter.<sys>` | `nix fmt` | `nixpkgs-fmt` for the flake itself |
|
||||
|
||||
### Why no Rust toolchain?
|
||||
|
||||
The crate lives in `../komp_ac/tui-pages/`. This repo only contains the
|
||||
*static* website, so the flake intentionally omits `rust-overlay` and a
|
||||
`rustPlatform` — they would add hundreds of MB to the shell closure for
|
||||
nothing. When the site eventually gains a Rust backend, those inputs come
|
||||
back.
|
||||
|
||||
### Why the per-system pattern?
|
||||
|
||||
Mirrored from the upstream Codex CLI flake so future contributors see a
|
||||
shape they already recognise. `forAllSystems` is a one-liner that
|
||||
guarantees `linux`/`darwin` × `x86_64`/`aarch64` parity without sprinkling
|
||||
`if` branches across the file.
|
||||
|
||||
## Going to production
|
||||
|
||||
The CDN approach is fine for marketing pages. For better performance
|
||||
@@ -75,16 +171,22 @@ tui-pages-web/
|
||||
├── sitemap.xml # sitemap
|
||||
├── static/
|
||||
│ ├── css/
|
||||
│ │ └── site.css # our custom layer (small)
|
||||
│ │ ├── site.css # our custom layer (small)
|
||||
│ │ └── ascii.css # animation rules for the body-rain ASCII art
|
||||
│ ├── img/
|
||||
│ │ ├── favicon.svg
|
||||
│ │ ├── logo.svg
|
||||
│ │ ├── og-image.svg
|
||||
│ │ ├── og-image.svg # 1200x630 social share card (used as-is)
|
||||
│ │ ├── og-image-bg.svg # 1200x500 cropped variant (chafa source)
|
||||
│ │ ├── terminal-default.svg
|
||||
│ │ ├── terminal-canvas.svg
|
||||
│ │ └── terminal-keybindings.svg
|
||||
│ ├── ascii/
|
||||
│ │ └── rain.txt # chafa render of og-image-bg.svg
|
||||
│ └── demos/ # (empty — drop asciinema .cast files here)
|
||||
├── content/ # (empty — markdown for blog/changelog later)
|
||||
├── flake.nix # Nix dev shell, package, app, checks
|
||||
├── flake.lock # (generated — pinned nixpkgs)
|
||||
├── Makefile
|
||||
├── .gitignore
|
||||
└── README.md
|
||||
@@ -92,8 +194,9 @@ tui-pages-web/
|
||||
|
||||
## Adding an asciinema demo to the hero
|
||||
|
||||
The hero currently shows a static SVG terminal mockup. To replace it with a
|
||||
real asciinema recording:
|
||||
The hero currently shows the **static SVG mockup**
|
||||
`static/img/terminal-default.svg`. To replace it with a real asciinema
|
||||
recording (much more impressive, but requires a recorded cast):
|
||||
|
||||
1. Record one of the examples:
|
||||
|
||||
@@ -103,7 +206,8 @@ real asciinema recording:
|
||||
# ... run the app for a few seconds, hit ctrl-d to stop
|
||||
```
|
||||
|
||||
2. In `index.html`, replace the hero terminal block with:
|
||||
2. In `index.html`, replace the `<!-- Hero terminal mockup -->` block
|
||||
with:
|
||||
|
||||
```html
|
||||
<div class="tp-terminal">
|
||||
@@ -118,6 +222,8 @@ real asciinema recording:
|
||||
<script src="https://cdn.jsdelivr.net/npm/asciinema-player@3.7.0/dist/bundle/asciinema-player.js" defer></script>
|
||||
```
|
||||
|
||||
The body-rain ASCII art is independent of the hero and stays as-is.
|
||||
|
||||
## License
|
||||
|
||||
The website source is MIT-licensed. The terminal mockup SVGs in `static/img/`
|
||||
|
||||
27
flake.lock
generated
Normal file
27
flake.lock
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1779560665,
|
||||
"narHash": "sha256-tpyBcxPpcQb8ukyNF7DoCwfSY3VPsxHoYwj00Cayv5o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "64c08a7ca051951c8eae34e3e3cb1e202fe36786",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
185
flake.nix
Normal file
185
flake.nix
Normal file
@@ -0,0 +1,185 @@
|
||||
{
|
||||
description = "Nix flake for the tui-pages website — static HTML/CSS/SVG, CDN-loaded JS";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
# NOTE: No rust-overlay — this is a pure-static site, no Rust toolchain required.
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, ... }:
|
||||
let
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs systems f;
|
||||
|
||||
version = "0.1.0";
|
||||
in
|
||||
{
|
||||
# `nix fmt` — format this flake
|
||||
formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixpkgs-fmt);
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# packages.<system>.default
|
||||
#
|
||||
# The whole website as a single derivation. `nix build` produces ./result/
|
||||
# containing the static files, ready to:
|
||||
# - serve with any static file server, or
|
||||
# - upload to Netlify / Cloudflare Pages / GitHub Pages / S3 / etc.
|
||||
# -------------------------------------------------------------------------
|
||||
packages = forAllSystems (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
src = ./.;
|
||||
in {
|
||||
default = pkgs.stdenvNoCC.mkDerivation {
|
||||
pname = "tui-pages-website";
|
||||
inherit version;
|
||||
inherit src;
|
||||
|
||||
dontBuild = true;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out
|
||||
# Use cp -R with --no-preserve=mode so the read-only Nix-store
|
||||
# permissions don't leak into $out (a few hosts reject the
|
||||
# resulting 0444 file modes when serving).
|
||||
cp -R --no-preserve=mode ${src}/. $out/
|
||||
chmod -R u+w $out
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with pkgs.lib; {
|
||||
description = "Static website for the tui-pages Rust crate";
|
||||
homepage = "https://tui-pages.dev";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.unix;
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# apps.<system>.serve
|
||||
#
|
||||
# `nix run .#serve` — build the site and boot `python3 -m http.server`
|
||||
# against the built result. Honours $PORT (defaults to 8000).
|
||||
# -------------------------------------------------------------------------
|
||||
apps = forAllSystems (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
site = self.packages.${system}.default;
|
||||
in {
|
||||
serve = {
|
||||
type = "app";
|
||||
program = toString (pkgs.writeShellScript "tui-pages-web-serve" ''
|
||||
echo "Serving ${site} on http://localhost:''${PORT:-8000}"
|
||||
cd ${site}
|
||||
exec ${pkgs.python3}/bin/python3 -m http.server "''${PORT:-8000}"
|
||||
'');
|
||||
meta = with pkgs.lib; {
|
||||
description = "Build the tui-pages website and serve it on $PORT (default 8000)";
|
||||
platforms = platforms.unix;
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# devShells.<system>.default
|
||||
#
|
||||
# `nix develop` — everything the Makefile, the README, and future
|
||||
# workflows need. No Rust toolchain by design.
|
||||
# -------------------------------------------------------------------------
|
||||
devShells = forAllSystems (system:
|
||||
let pkgs = nixpkgs.legacyPackages.${system};
|
||||
in {
|
||||
default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
# --- Build / serve / validate (the Makefile uses these) ----
|
||||
gnumake
|
||||
python3
|
||||
gawk
|
||||
gnused
|
||||
gnugrep
|
||||
coreutils
|
||||
|
||||
# --- HTML validation (optional, for the tidy check) --------
|
||||
html-tidy
|
||||
|
||||
# --- Smoke-test the local server ---------------------------
|
||||
curl
|
||||
|
||||
# --- Record TUI demos (used to replace the SVG mockups) ----
|
||||
asciinema
|
||||
|
||||
# --- Generate the body-background ASCII art from the og-image
|
||||
# `make ascii` runs `chafa` to convert the og-image into
|
||||
# a text grid, which is then embedded in index.html and
|
||||
# animated with CSS as a slow drifting body background.
|
||||
chafa
|
||||
|
||||
# --- Optional: standalone Tailwind CLI for production CSS --
|
||||
# Uncomment if you switch from the Play CDN to a precompiled stylesheet.
|
||||
# nodejs
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
# Some distros ship `python` but not `python3`. Make the
|
||||
# `python3` invocation in the Makefile portable.
|
||||
if ! command -v python3 >/dev/null 2>&1 && command -v python >/dev/null 2>&1; then
|
||||
alias python3=python
|
||||
fi
|
||||
|
||||
cat <<'EOF'
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ tui-pages website dev shell │
|
||||
│ │
|
||||
│ make serve python3 -m http.server 8000 │
|
||||
│ make size report file sizes │
|
||||
│ make validate HTML tag balance check │
|
||||
│ make tidy run html-tidy on every .html │
|
||||
│ make ascii regenerate body-rain ASCII art │
|
||||
│ │
|
||||
│ asciinema rec static/demos/intro.cast record a demo │
|
||||
│ chafa -s 240x60 -c none \│
|
||||
│ static/img/og-image-bg.svg >│
|
||||
│ static/ascii/rain.txt render body rain │
|
||||
│ │
|
||||
│ nix build build site → ./result/ │
|
||||
│ nix run .#serve build + serve (honours $PORT) │
|
||||
│ nix fmt format this flake │
|
||||
│ nix flake check run all checks │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
});
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# checks.<system>.tidy
|
||||
#
|
||||
# HTML sanity check using tidy. Non-blocking — prints warnings to the
|
||||
# build log, never fails. `nix flake check` runs this.
|
||||
# -------------------------------------------------------------------------
|
||||
checks = forAllSystems (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
site = self.packages.${system}.default;
|
||||
in {
|
||||
tidy = pkgs.runCommand "tui-pages-website-html-check"
|
||||
{
|
||||
nativeBuildInputs = [ pkgs.html-tidy ];
|
||||
} ''
|
||||
cd ${site}
|
||||
for f in *.html; do
|
||||
echo "─── $f ───"
|
||||
${pkgs.html-tidy}/bin/tidy -e -q -utf8 "$f" 2>&1 | head -20 || true
|
||||
done
|
||||
touch $out
|
||||
'';
|
||||
});
|
||||
};
|
||||
}
|
||||
15
index.html
15
index.html
File diff suppressed because one or more lines are too long
49
static/ascii/rain.txt
Normal file
49
static/ascii/rain.txt
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_
|
||||
=$ sa a y sa_gwaanggug, :
|
||||
? ?F fY ` @F?YFZ@~?f r~ :
|
||||
`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
yyyy_ yagggm aggr _ygggs
|
||||
_@@@@@_ @@@~~~ _ __ __ _ __ __ _ 4@@F $@@~~~ __ _
|
||||
$@@~@@$ $@@@@@@L$@@y@@@L4@@@@@@g_ $@@W@@@@yg@@@@y yg@@@@@gy "@@$ $@@, y@@E _a@@@@@@y 4@@$g@@F4@@F y@@@F 4@@@@@@$_a@@@@@@g, @@$g@@$
|
||||
g@@F ~@@@ ``@@@`` $@@@~`` `yyyyy@@@ $@@F``@@@F `@@@ u@@@yyy$@@L @@@,y@B@@ $@@ @@@~ 4@@@ 4@@@~``~4@@@@@P~ `@@@```$@@~ 7@@$ @@@~``'
|
||||
g@@@$$$@@@y @@@ $@@L y@@@FFF@@@ $@@ @@@ @@@ 4@@@PPPPPPT "@@$$@~$@W@@F @@@ y@@@ 4@@$ 4@@@@@g_ @@@ @@@ @@@ @@$
|
||||
y@@@~~~~~$@@L @@@ $@@L "@@$yy$@@@ $@@ @@@ @@@ R@@gyyyg@ 4@@@E "@@@@ 4@@$yg@@@~ 4@@$ 4@@F~R@@g_ @@@ 7@@@ga@@@~ @@$
|
||||
^~~^ "~~~ ~~~ ~~~~ `~FF~~~~~ 7~~ ~~~ ~~~ `~FFFF~~ ~~~ ~~~~ `~FFFF~ "~~~ ~~~~ ~~~T ~~~ ~FFFF~ ~~~
|
||||
|
||||
|
||||
`:: ::: ::: ::: ::: ::::::::::: ::: ::: :::: ::: ::::::::. ::
|
||||
`:: ..... ... ... ... ::: ..... ::: ... ... ..... .... ... ````:::```` ::: ::: `::: ...... ... .. ..... :::```::: ... ... ....... ..::...
|
||||
`:::```::: ::: ::: ::: ::: :::```:::: ::: ::::```::. :::```::: ::: ::: ::: `::: ::````` ::: :::```::: :::...::` ::: ::: :::````` ``::```
|
||||
`::' ::: ::: ::: ::: ::: ::: `::: ::: ::: ::: ::: ::: ::: ::: ::: `::: `:::::.. ::: ::' ::: :::``:::. ::: ::: `::::::. ::
|
||||
`::: .::: ::: .::: ::: ::: :::. :::: ::: ::: ::: `:::. .::: ::: `::: .:::' `::: ```::: ::: :: ::: ::: `:::. :::. .::: . ````:: ::. :::
|
||||
`````:::`` ``::````` ``' ``` ```::````' ``` ``` ``' ``````::: ``` ```:::``` ```' ``:::``` ``` `` ``` ``` ```. ``::````` ``::::`` ````` ```
|
||||
:....:::`
|
||||
````````
|
||||
|
||||
.y + - i + .
|
||||
4W*MF~EZK,,4~3 $~f~%g~M $~_Ta F~K~L4~$~$uEZLf~$ Q~a~3 F~ [ E4E_ $='EZ%4_z F~K~LyT% F~L4Z, TM #~$uM7L B~%_T3 F~$yED F~LyT% yy^%uT7LyT%?F Fg~3 F~L
|
||||
" ?=! 4rf ~ ?=~`g9 F ?=? ~ ~ ~f ^ f h= ?=F `=F ?= ^rF:=^J F~r?=:_$~ ~ ~ ~?=T M=~==~z "=f f f hf $=~"=? ]gF"h= ~ ~?=? ?^ f _g ^=T h ~`=F ~ ~
|
||||
` ` ` ` `` `
|
||||
y== y_ _ __ __ _ _ _ ,___ y_= __ __ __ __ __ __ __ __ _ __ __ __ __a__ ;y_ __ _,___ _ __ _ yg _, __ __ _ _ __ ___ _ ___ ____ _ ____
|
||||
`Th $`$ $ L`L $`$=="yMy~$`4 $`$ F`L$ 9 `L F`La== "=yy=g $ F la== =d $ E `4`4 $4`4-= E $`4 4 F`$== 4`# 3 F` P=\4_F4== E ~yF 4~J $`$ $4 $==4```L
|
||||
`T~ ~~`T` ~T ~ `T" ~ ~ " " ~~" ~ ~`Z4 ~ ~ ~ TT `T~`T~ ~ ~ ~ ~T T~ ^ `T'~ ~ ~ ~ ~T ~T"`~`T~ ~ `T^ ~ `T` ~T~ ~ ~T ~ .F 4~~ ~ ~T`J `T^ ~T ~ ~
|
||||
|
||||
|
||||
|
||||
|
||||
111
static/css/ascii.css
Normal file
111
static/css/ascii.css
Normal file
@@ -0,0 +1,111 @@
|
||||
/* ==========================================================================
|
||||
tui-pages website - animated ASCII art layer (chafa-rendered)
|
||||
Loaded AFTER site.css. Provides:
|
||||
- .tp-ascii-rain full-bleed body background, slow drifting pattern
|
||||
sourced from static/img/og-image-bg.svg
|
||||
All animations respect prefers-reduced-motion.
|
||||
========================================================================== */
|
||||
|
||||
/* Body-wide ASCII art background ---------------------------------------- */
|
||||
/* Fixed full-bleed layer behind all content. Renders a chafa output of the
|
||||
og-image-bg.svg (black background + "tui-pages" wordmark + headline +
|
||||
subtitle), drawn as ASCII glyphs in a single full-width tile. Two copies
|
||||
of the tile are stacked vertically and the whole track drifts slowly
|
||||
upward, looping seamlessly when the top copy exits the viewport.
|
||||
|
||||
The hero is a static <img src="static/img/terminal-default.svg"> as
|
||||
designed - this file does NOT touch the hero.
|
||||
|
||||
Regenerate the source tile with `make ascii` (uses chafa on
|
||||
static/img/og-image-bg.svg). The chafa output is in static/ascii/rain.txt
|
||||
and is 240 columns wide. */
|
||||
|
||||
.tp-ascii-rain {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 0; /* sit above the page background, below the content */
|
||||
pointer-events: none;
|
||||
opacity: 0.14;
|
||||
overflow: hidden;
|
||||
font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
font-size: clamp(6px, 0.9vw, 9px);
|
||||
line-height: 1.05;
|
||||
color: #f4a26b; /* warm rust-orange tint, picks up the brand */
|
||||
white-space: pre;
|
||||
text-shadow: 0 0 6px rgba(183, 65, 14, 0.25); /* faint phosphor glow */
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
/* The track holds two byte-identical copies of rain.txt stacked vertically.
|
||||
translateY(0 -> -50%) is a perfect seamless loop. */
|
||||
.tp-ascii-rain-track {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
animation: tp-ascii-drift 90s linear infinite;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.tp-ascii-rain-cell {
|
||||
display: block;
|
||||
white-space: pre; /* preserve the chafa line breaks */
|
||||
}
|
||||
|
||||
/* CRT scanlines overlay - a thin moving line every 2px. Faint so it doesn't
|
||||
fight the page content. */
|
||||
.tp-ascii-rain::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: repeating-linear-gradient(
|
||||
to bottom,
|
||||
transparent 0,
|
||||
transparent 2px,
|
||||
rgba(0, 0, 0, 0.18) 2px,
|
||||
rgba(0, 0, 0, 0.18) 3px
|
||||
);
|
||||
pointer-events: none;
|
||||
animation: tp-ascii-scanline 8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes tp-ascii-drift {
|
||||
0% { transform: translateY(0); }
|
||||
100% { transform: translateY(-50%); }
|
||||
}
|
||||
|
||||
@keyframes tp-ascii-scanline {
|
||||
0% { background-position: 0 0; }
|
||||
100% { background-position: 0 6px; }
|
||||
}
|
||||
|
||||
/* The hero text is high-contrast on its own (zinc-50 / accent), and the
|
||||
body ASCII rain is at 14% opacity. No overlay needed — the rain shows
|
||||
through everywhere. */
|
||||
|
||||
/* Light theme: invert to dark text on light, dimmer, no glow. */
|
||||
:root[data-theme="light"] .tp-ascii-rain {
|
||||
opacity: 0.10;
|
||||
color: #1f1f23;
|
||||
text-shadow: none;
|
||||
mix-blend-mode: multiply;
|
||||
}
|
||||
|
||||
:root[data-theme="light"] .tp-ascii-rain::after {
|
||||
background: repeating-linear-gradient(
|
||||
to bottom,
|
||||
transparent 0,
|
||||
transparent 2px,
|
||||
rgba(255, 255, 255, 0.12) 2px,
|
||||
rgba(255, 255, 255, 0.12) 3px
|
||||
);
|
||||
}
|
||||
|
||||
/* Reduced motion: pause the drift, keep the static background. */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.tp-ascii-rain-track,
|
||||
.tp-ascii-rain::after {
|
||||
animation: none !important;
|
||||
transform: none !important;
|
||||
}
|
||||
}
|
||||
@@ -55,9 +55,7 @@ body {
|
||||
|
||||
/* ---------- Hero --------------------------------------------------------- */
|
||||
.tp-hero {
|
||||
background:
|
||||
radial-gradient(ellipse 80% 50% at 50% 0%, rgba(183, 65, 14, 0.15), transparent 70%),
|
||||
linear-gradient(180deg, var(--tp-hero-from) 0%, var(--tp-hero-to) 100%);
|
||||
background: transparent; /* let the body ASCII rain show through */
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
}
|
||||
@@ -75,6 +73,7 @@ body {
|
||||
mask-image: radial-gradient(ellipse 60% 50% at 50% 0%, #000 30%, transparent 80%);
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
opacity: 0.5; /* subtle grid, not a wall */
|
||||
}
|
||||
|
||||
/* Subtle floating code lines in the hero, behind the content */
|
||||
@@ -206,13 +205,12 @@ body {
|
||||
.tp-terminal {
|
||||
position: relative;
|
||||
border-radius: 0.875rem;
|
||||
background: #0b0b0f;
|
||||
background: transparent; /* let the body ASCII art show through */
|
||||
box-shadow:
|
||||
0 1px 0 rgba(255, 255, 255, 0.04) inset,
|
||||
0 30px 60px -20px rgba(0, 0, 0, 0.6),
|
||||
0 18px 36px -18px rgba(0, 0, 0, 0.5);
|
||||
0 0 0 1px rgba(244, 162, 107, 0.18), /* rust-orange hairline, brand */
|
||||
0 30px 60px -20px rgba(0, 0, 0, 0.55),
|
||||
0 18px 36px -18px rgba(0, 0, 0, 0.45);
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(63, 63, 70, 0.4);
|
||||
}
|
||||
.tp-terminal::after {
|
||||
content: "";
|
||||
@@ -220,7 +218,14 @@ body {
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
border-radius: inherit;
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.03);
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(11, 11, 15, 0.55) 0%,
|
||||
rgba(11, 11, 15, 0) 18%,
|
||||
rgba(11, 11, 15, 0) 82%,
|
||||
rgba(11, 11, 15, 0.45) 100%
|
||||
); /* darken only the top + bottom strips, leave the middle transparent
|
||||
so the body ASCII art shows through the terminal content */
|
||||
}
|
||||
|
||||
/* ---------- Selection --------------------------------------------------- */
|
||||
|
||||
29
static/img/og-image-bg.svg
Normal file
29
static/img/og-image-bg.svg
Normal file
@@ -0,0 +1,29 @@
|
||||
<svg width="1200" height="520" viewBox="0 0 1200 520" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="tui-pages terminal art (chafa source)">
|
||||
<defs>
|
||||
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
|
||||
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="#27272a" stroke-width="1" stroke-opacity="0.3"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
|
||||
<rect width="1200" height="520" fill="#000000"/>
|
||||
<rect width="1200" height="520" fill="url(#grid)"/>
|
||||
|
||||
<g transform="translate(80, 90)">
|
||||
<text font-family="ui-monospace, 'JetBrains Mono', monospace" font-weight="700" font-size="22" fill="#f4f4f5" x="0" y="0">tui-pages</text>
|
||||
<rect x="140" y="-15" width="4" height="24" fill="#b7410e"/>
|
||||
</g>
|
||||
|
||||
<text font-family="Inter, system-ui, sans-serif" font-weight="700" font-size="84" fill="#f4f4f5" x="80" y="280" letter-spacing="-2">
|
||||
A framework for
|
||||
</text>
|
||||
<text font-family="Inter, system-ui, sans-serif" font-weight="700" font-size="84" fill="#b7410e" x="80" y="370" letter-spacing="-2">
|
||||
building TUIs in Rust.
|
||||
</text>
|
||||
|
||||
<text font-family="Inter, system-ui, sans-serif" font-weight="400" font-size="28" fill="#a1a1aa" x="80" y="430">
|
||||
Pre-programmed focus, keymaps, and page navigation.
|
||||
</text>
|
||||
<text font-family="Inter, system-ui, sans-serif" font-weight="400" font-size="28" fill="#a1a1aa" x="80" y="470">
|
||||
Stop rewriting the same architecture for every project.
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -1,17 +1,17 @@
|
||||
<svg viewBox="0 0 640 400" xmlns="http://www.w3.org/2000/svg" class="w-full h-auto" role="img" aria-label="examples/default terminal screenshot">
|
||||
<style>
|
||||
.bg { fill: #18181b; }
|
||||
.chrome { fill: #27272a; }
|
||||
.bg { fill: transparent; stroke: #3f3f46; stroke-width: 1; }
|
||||
.chrome { fill: transparent; }
|
||||
.dot { fill: #52525b; }
|
||||
.sep { stroke: #27272a; stroke-width: 1; }
|
||||
.tab { fill: #18181b; }
|
||||
.sep { stroke: #3f3f46; stroke-width: 1; }
|
||||
.tab { fill: transparent; }
|
||||
text { font-family: ui-monospace, 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; fill: #f4f4f5; }
|
||||
.t-md { font-size: 15px; }
|
||||
.t-sm { font-size: 13px; }
|
||||
.t-xs { font-size: 11px; }
|
||||
.muted { fill: #a1a1aa; }
|
||||
.dim { fill: #71717a; }
|
||||
.sel-bg { fill: #b7410e; }
|
||||
.sel-bg { fill: #b7410e; fill-opacity: 0.85; }
|
||||
.sel-fg { fill: #fff5f0; }
|
||||
</style>
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.6 KiB |
Reference in New Issue
Block a user