KnowFlux is a self-published fiction & poetry platform β a literary hub with a bold, Nintendo-inspired visual identity. Two serialized books (Exploded and The Pinnacle of Reality), an ever-growing poetry archive, and an interactive character database called the Omni-Dex.
π Live site: knowflux.ink
- Two serialized books: Exploded and The Pinnacle of Reality
- Fully dynamic β there are no per-page HTML files. Every page lives in
books.jsonand is rendered byreader.html?book=<id>&page=<n>
- Curated poetry archive with sections (Haikus, Triplets, β¦)
- Unlike books, each poem is a standalone static HTML file in
Poetry/, listed bypoetry.html
- Interactive character/universe database (
omni-dex.html):- Universe & type filtering (tabs + pills)
- Animated stat bars
- Modal detail view with stats sidebar and keyboard navigation (
β/β/Esc)
- Lore Lens β site-wide hover popovers that scan the rendered page for Omni-Dex entry names and show that card inline
- Both features read from
omni-dex-data.json
- Customizable display: text size, font family (Normal / Garamond / Lora), line width
- Dark mode & Focus mode
- Bookmarks β "Continue reading" links adapt to where you left off
- Word count + estimated reading time per page
- Scroll progress bar, keyboard navigation (
β/β), chapter-completion toast - Drop caps on chapter-open pages
- Instant client-side search powered by Algolia
- The SDK is loaded from a CDN in
search.html(v4); keys are inlined there - The index is built from
sitemap.xmlbyBackend/algolia-build-index.pyintoalgolia_records.json
- Password-protected content generator at
/admin - Add book pages or poems without touching the filesystem:
- Book pages β parsed with
[dream],[thought],[underline]markers and written tobooks.json - Poems β generates a static HTML page in
Poetry/and updates thepoetry.htmlgrid
- Book pages β parsed with
- Regenerates
sitemap.xmland auto-commits & pushes to GitHub
A static Jamstack site with a thin Python dev/ops layer. Nothing renders on a server at request time β the backend exists purely to author content.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Browser β
β index Β· reader Β· poetry Β· contents Β· omni-dex Β· search Β· admin β
ββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ¬ββββββββ
β static HTML + CSS + JS β form posts / fetch
βΌ βΌ
ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
β Static Assets β β Backend (Python stdlib)β
β HTML / CSS / JS / JSON β β server.py β dev server β
β books.json Β· poetry.htmlβ β + admin content API β
ββββββββββββββββ¬ββββββββββββ ββββββββββββββ¬ββββββββββββββ
β β
βΌ βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β External Services β
β Algolia (search) Β· Kit (newsletter) Β· GitHub (host + commits) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Books used to be generated from exploded-page*.html files on disk. They aren't anymore β those files are gone. books.json is the database, and the admin panel is the only thing that should write to it.
Never let a script rebuild books.json from HTML. save_books_json() in server.py deliberately loads the existing file, rebuilds only the poetry section, and writes it back. That distinction is the difference between an edit and a data-loss event.
| Layer | Technology |
|---|---|
| Frontend | Zero frameworks β pure HTML5, CSS3, Vanilla JS |
| CSS | Modular system under css/ (main.css aggregates the rest) |
| JS | ES5-style modules concatenated into js/bundle.js by Backend/build.py |
| Backend | Python standard library only (http.server, socketserver, json, re) |
| Search | Algolia β algoliasearch v4 from CDN in search.html |
| Newsletter | Kit (ConvertKit) |
| Hosting | GitHub Pages (CNAME β knowflux.ink) + auto-commit content pipeline |
auto_commit()still honours aRENDER_GIT_BRANCHenv var from an earlier Render deployment. Harmless β it defaults tomain.
- Python 3.12+
- No npm step. No external Python packages are required (see
requirements.txt).β οΈ Exception:Backend/algolia-build-index.pyimportscertifi, which is neither installed nor declared. That script fails on import today.
cd Backend
python build.pyConcatenates the modules listed in JS_MODULES into js/bundle.js (and mirrors the output to root script.js for the legacy poetry pages).
js/omni-dex.jsis not in that list β it is loaded separately withdeferonomni-dex.htmlonly, so the rest of the site doesn't pay for it.
cd Backend
python server.pyServes on http://localhost:5001 (override with PORT).
To unlock the admin panel, create a .env in the repo root:
ADMIN_PASSWORD=your_password_here
GITHUB_TOKEN=your_token_here # optional: enables auto-commit on publishπ If
ADMIN_PASSWORDis unset,/admin/loginaccepts an empty password. The env var defaults to""and the check is a plain==. Always set it before exposing the server.
python Backend/generate_books_json.py # β οΈ currently broken β see Known Issues
python Backend/algolia-build-index.py # β οΈ currently broken β missing certifiKnowFlux/
βββ index.html # Home page
βββ reader.html # Dynamic book reader (?book=<id>&page=<n>)
βββ aboutbook.html # Book overview
βββ contents.html # Chapter contents (tabbed by book)
βββ poetry.html # Poetry grid β the index AND the source for books.json poetry
βββ omni-dex.html # Interactive character database
βββ search.html # Algolia-powered search (SDK from CDN)
βββ feedback.html # Reader feedback
βββ admin.html # Password-protected content generator
βββ comingsoon.html # Legacy splash page β linked from nothing
βββ 404.html # Custom error page (GitHub Pages serves this automatically)
βββ books.json # π THE content source β all book pages live here
βββ omni-dex-data.json # Character/universe data for Omni-Dex + Lore Lens
βββ sitemap.xml # Regenerated on publish
βββ algolia_records.json # Generated search records
βββ CNAME # knowflux.ink
βββ css/ # Modular CSS, aggregated by main.css
β βββ main.css # β imports everything below
β βββ base.css
β βββ layout.css
β βββ components.css
β βββ navigation.css
β βββ reading.css
β βββ poetry.css
β βββ omni-dex.css
β βββ lore-lens.css
β βββ search.css
β βββ about.css
β βββ 404.css
β βββ darkmode.css
β βββ responsive.css
βββ js/
β βββ bundle.js # Built output β do not edit by hand
β βββ reader.js # Fetches books.json, renders a page
β βββ navigation.js # Menu, mobile overlay, promo cycling
β βββ reading.js # Reading experience controller
β βββ contents.js # Contents tabs + bookmark-aware links
β βββ main.js # Shared bootstrap
β βββ random.js # "Random poem/book" buttons
β βββ footer.js # Copyright year (CST) + footer reveal
β βββ lore-lens.js # Site-wide Omni-Dex hover popovers
β βββ omni-dex.js # Omni-Dex grid, filters, modal (page-specific)
βββ Backend/
β βββ server.py # Dev server + admin content API
β βββ build.py # JS bundler
β βββ generate_books_json.py # Poetry regeneration (β οΈ broken path)
β βββ algolia-build-index.py # Algolia records from sitemap (β οΈ missing certifi)
β βββ config.py # Shared ROOT_DIR constant
βββ Images/ # Static images
βββ Poetry/ # Generated poem HTML files (static, one per poem)
- Log into
/admin, enter the password. - Pick a tab β Pinnacle, Exploded, or Poetry.
- Fill in the form:
- Book pages: page number, chapter title, content (with markers)
- Poems: title, section (existing or new), stanzas separated by blank lines
- Hit Generate β the server:
- Writes to
books.jsonviaadd_page_to_books_json(), or creates a poem HTML file and rewrites thepoetry.htmlgrid - Regenerates
sitemap.xml - Auto-commits and pushes to GitHub (if
GITHUB_TOKENis set)
- Writes to
- GitHub Pages redeploys. π
| Marker | Renders as |
|---|---|
[thought]β¦[/thought] |
Blue italic inline thought (works anywhere, including inside other blocks) |
[dream]β¦[/dream] |
Horizontal rule + styled italic memory card |
[underline] / [/underline] |
Orange horizontal divider |
β οΈ Known bug:[underline]is parsed as an opening tag but rendered as a divider. Any paragraphs written after a bare[underline]are silently discarded, because the renderer never emits them. Always close it with[/underline].
{
"page_number": 13,
"chapter_title": "Ch. 2 | Scarlet",
"content": " <p>β¦</p>\n\n <div class=\"underline\"></div>\n\n",
"file": "",
"url": "reader.html?book=exploded&page=13"
}content is pre-rendered HTML, not markdown. Marker parsing happens once, at save time, through parse_content_blocks() β render_content_blocks().
| Variable | Purpose |
|---|---|
PORT |
Server port (default 5001) |
ADMIN_PASSWORD |
Admin panel password. Unset = no protection. |
GITHUB_TOKEN |
Enables auto-commit/push on publish |
GIT_REPO_URL |
Override repo URL for auto-commit (defaults to origin) |
GIT_NAME / GIT_EMAIL |
Commit author (defaults to KnowFlux Bot <bot@knowflux.ink>) |
Algolia keys are inlined in search.html β swap them for your own fork.
Β© 2026 KnowFlux β Keep Blooming, Keep Flying