Compare commits

...

59 commits
pages ... main

Author SHA1 Message Date
Tolaria
1261e55c4a Update nourishing-the-body
All checks were successful
Deploy Docs / deploy (push) Successful in 30s
2026-06-06 13:17:26 +08:00
Tolaria
8cf676f049 Update index, daily-sadhana 2026-06-06 12:02:38 +08:00
Tolaria
e0415e0f66 remove repo link as it is in the conrtibuting page which explains how to use it better
All checks were successful
Deploy Docs / deploy (push) Successful in 15s
Signed-off-by: Tolaria <vault@tolaria.md>
2026-06-05 21:26:37 +08:00
Tolaria
09ba589a00 Update daily-sadhana
All checks were successful
Deploy Docs / deploy (push) Successful in 14s
2026-06-05 21:20:48 +08:00
Tolaria
1de4aa798c Pages updates with references and edits
All checks were successful
Deploy Docs / deploy (push) Successful in 14s
2026-06-05 21:18:41 +08:00
Tolaria
51b4c7ca97 Pages updates with references and edits
All checks were successful
Deploy Docs / deploy (push) Successful in 14s
2026-06-05 13:49:57 +08:00
Tolaria
de2d06d3a1 Pages updates with references and edits
All checks were successful
Deploy Docs / deploy (push) Successful in 14s
2026-06-05 13:29:55 +08:00
Tolaria
6bd35e5160 Pages updates with references and edits
All checks were successful
Deploy Docs / deploy (push) Successful in 29s
2026-06-05 12:21:31 +08:00
Tolaria
458dc41147 Pages updates
All checks were successful
Deploy Docs / deploy (push) Successful in 14s
2026-06-04 21:51:52 +08:00
Tolaria
e8a54bd396 Add action items + mark sprout read checkboxes to all article pages; fix 9 typos; regenerate manifest
All checks were successful
Deploy Docs / deploy (push) Successful in 14s
2026-06-04 20:54:48 +08:00
Tolaria
b9975435c2 Pages updates
All checks were successful
Deploy Docs / deploy (push) Successful in 14s
2026-06-04 20:29:39 +08:00
Tolaria
9f179b1ead Pages and keep in touch updates
All checks were successful
Deploy Docs / deploy (push) Successful in 14s
2026-06-04 20:22:49 +08:00
Tolaria
7db03ad35e edits to daily sadhana text
All checks were successful
Deploy Docs / deploy (push) Successful in 28s
2026-06-04 13:33:40 +08:00
Tolaria
11921aa07a fix the menu blur overlay issue 2026-06-04 13:33:25 +08:00
Tolaria
ec88d58e05 gitignore 2026-06-04 12:44:31 +08:00
Tolaria
9fa33e81c2 update pyproject 2026-06-04 12:43:46 +08:00
Tolaria
1b1e4dc154 update contributing docs 2026-06-04 12:43:21 +08:00
Tolaria
4421378529 Merge action-points feature: interactive checklist w/ kill switch
All checks were successful
Deploy Docs / deploy (push) Successful in 14s
Brings in the interactive action-points checklist (nav badges, heading
pills, first-load totals manifest, confetti) with:
- a zensical.toml kill switch ([project.extra.action_points] enabled)
- perf fixes (store cache, in-place badge updates, pooled confetti)
- white-on-green legibility fix

Conflicts resolved below.

# Conflicts:
#	.forgejo/workflows/docs.yml
#	docs/stylesheets/extra.css
2026-06-03 23:48:33 +08:00
Tolaria
c7a3fe9412 feat(action-points): add zensical.toml kill switch + perf + legibility
Feature flag:
- [project.extra.action_points] enabled (default true) in zensical.toml.
- overrides/main.html exposes it as window.TOA_ACTION_POINTS_ENABLED in
  <head>, before extra_javascript loads.
- extra.js bails at the top of the IIFE when the flag is false: no
  storage, no nav badges, no heading pills, no confetti, no per-click
  work. Checkboxes fall back to Material's read-only tasklist.
  Verified inert when disabled (0 badges/pills/canvases, no localStorage,
  no JS errors).

Perf:
- In-memory write-through cache for the parsed store: a single toggle
  went from 15 localStorage JSON.parse reads to 0.
- updateNavBadges() updates badges in place (reuse span, only write on
  change) instead of removing+rebuilding every badge each toggle, which
  forced a full Material nav relayout. JS/toggle ~0.37->0.26ms,
  layout delta ~0.73->0.63ms.

Legibility:
- Override -webkit-text-fill-color (headings set it; pseudo-elements
  inherit it and it beats `color`) to #fff on completed green pills and
  nav badges, so the count/checkmark is white on green. h2 text color
  itself untouched.
2026-06-03 23:46:14 +08:00
Tolaria
5e0f482db1 ci: use uv to provision Python 3.12, fixing zensical build on py3.9 runner
All checks were successful
Deploy Docs / deploy (push) Successful in 14s
2026-06-03 23:24:07 +08:00
Tolaria
fbc488cc95 perf(action-points): pool confetti into one shared canvas + single rAF
Each section/page completion previously appended a new full-viewport
(100vw x 100vh, z-index 99999) canvas with its own requestAnimationFrame
loop. Completing several sections in a row stacked multiple fullscreen
layers, each independently repainting the whole viewport at 60fps — the
real cause of click-induced slowdown (the change handler itself is ~1ms).

Now: one shared canvas, one rAF loop, particles pooled across completions.
The loop stops and the canvas is removed once no particles remain, so
there is no idle fullscreen compositing layer. Resize keeps it sized.

Verified live: 1 canvas after two back-to-back section completions,
0 canvases after the animation ends, green pills still white-on-green.
2026-06-03 23:17:44 +08:00
Tolaria
69f69be5e4 fix(action-points): correct nav badges, first-load totals, legibility
- Fix nav badge mis-targeting: scope to .md-nav--primary, skip #anchor
  (TOC) links so 'On this page' entries no longer show the page total;
  detect active-leaf sections via md-nav__item--nested instead of the
  secondary (TOC) nav, so the active page gets its own badge.
- Add build-time totals manifest (main.py -> docs/javascripts/toa-totals.json)
  so nav badges show correct totals on first load before a user has
  visited each page. Fetched once, browser-cached, zero runtime cost.
  Wired into CI before zensical build.
- Exclude fenced code blocks when counting tasks, so the Markdown
  reference doc's example checkboxes don't produce a phantom 0/3 badge.
- Force white text (#fff !important) on completed green pills/badges,
  incl. badge-inside-complete-link, to beat the nav link's green color.
- Convert prose practice/strategy steps into interactive tasklist items.
- Add action-points PRD under planning/.
2026-06-03 23:03:17 +08:00
Tolaria
4b4425a2d9 chore: relax Python requirement to >=3.9 for runner compatibility
Some checks failed
Deploy Docs / deploy (push) Failing after 25s
2026-06-03 23:01:24 +08:00
Tolaria
f7abb6bf42 ci: install python3-venv inside python:3.12 container
Some checks failed
Deploy Docs / deploy (push) Failing after 26s
2026-06-03 22:56:04 +08:00
Tolaria
6e1cdf4018 ci: use python:3.12 container to satisfy >=3.12
Some checks failed
Deploy Docs / deploy (push) Failing after 17s
2026-06-03 22:55:03 +08:00
Tolaria
a3ec22a70a ci: pin runner to node:22 and drop apt-get bootstrap
Some checks are pending
Deploy Docs / deploy (push) Waiting to run
2026-06-03 22:54:09 +08:00
Tolaria
3aade4630b card design
Some checks failed
Deploy Docs / deploy (push) Failing after 23s
2026-06-03 22:36:25 +08:00
Tolaria
06f0c739df card design 2026-06-03 22:24:49 +08:00
Tolaria
c4d21b72ea fix: repair corrupted markdown.md brackets; grounding adds wiki link to Nourishing the Body
Some checks failed
Deploy Docs / deploy (push) Failing after 24s
2026-06-03 20:47:55 +08:00
Tolaria
aac22735e4 fix: wiki links now display clean page title instead of raw path
Some checks failed
Deploy Docs / deploy (push) Failing after 23s
[[docs/contributing/index]] → displays as 'Contributing' (not 'docs/contributing/index')
[[docs/strategies/collective-awakening]] → displays as 'Collective Awakening'
Pipe syntax still overrides: [[page|custom text]] uses the custom text.
Images keep raw filename as alt text.
2026-06-03 20:42:06 +08:00
Tolaria
a1db08f32e fix: wiki links now root-relative — handles Tolaria [[docs/path/to/page]] format
Some checks failed
Deploy Docs / deploy (push) Failing after 23s
Strips docs/ prefix from Tolaria-generated links, collapses /index suffixes,
removes .md extensions, and produces root-relative URLs (/page/path/) that
work from any page regardless of depth. Images get root-relative asset paths.
2026-06-03 20:38:15 +08:00
Tolaria
fa0b34c3c2 fix: correct wiki link in markdown.md — use [[Contributing]] not [[docs/contributing/index]]
Some checks failed
Deploy Docs / deploy (push) Failing after 23s
2026-06-03 20:32:47 +08:00
Tolaria
2b2edc7505 Merge: Cusdis comments on every page + instant-nav fix
Some checks failed
Deploy Docs / deploy (push) Failing after 24s
2026-06-03 20:28:42 +08:00
Tolaria
5b0ff60ac8 feat: add Cusdis comments to every page, fix instant-navigation re-render 2026-06-03 20:28:34 +08:00
Tolaria
69119f347d feat: add wiki link support ([[page]]) via custom Python-Markdown extension
Some checks failed
Deploy Docs / deploy (push) Failing after 24s
- New package _extensions/wikilinks.py: preprocessor that converts
  [[Page Name]], [[Page|Text]], [[Page#anchor|Text]], and ![[img]]
  to standard Markdown links before parsing
- Skips wiki links inside fenced/inline code blocks
- Slugifies targets: lowercase, spaces→hyphens
- Registered as markdown extension in zensical.toml
- Updated CI workflow to pip install -e . for the _extensions package
- First usage: [[docs/contributing/index]] in markdown.md
2026-06-03 20:07:25 +08:00
Tolaria
d1f405bde1 fix: force comments iframe to 500px min-height
All checks were successful
Deploy Docs / deploy (push) Successful in 24s
2026-06-03 19:44:45 +08:00
Tolaria
0871b22709 refactor: rewrite homepage, rename Teachings→Strategies, move Spiritual Hygiene
- Rewrite index.md with human intro on consciousness, ascension, group origins
- Rename docs/teachings/ → docs/strategies/
- Move Spiritual Hygiene from strategies to practices
- Update all cross-references (teachings→strategies, inter-practice links)
- Update both index pages with new content and card grids
2026-06-03 19:40:40 +08:00
Tolaria
a31d6ac095 update comments plugin display
All checks were successful
Deploy Docs / deploy (push) Successful in 23s
2026-06-03 19:34:36 +08:00
Tolaria
f6f7bd7115 fix: update Cusdis app_id to new instance
All checks were successful
Deploy Docs / deploy (push) Successful in 39s
2026-06-03 19:26:31 +08:00
Tolaria
95d04f7a0e fix: remove broken hero.jpg reference from homepage 2026-06-03 19:03:06 +08:00
Tolaria
7d58c330a6 update comments plugin
All checks were successful
Deploy Docs / deploy (push) Successful in 23s
2026-06-03 18:52:11 +08:00
Tolaria
2537e4d5af fix: switch Cusdis to iframe embed to avoid CORS
All checks were successful
Deploy Docs / deploy (push) Successful in 24s
- Replace <script src> approach with programmatic iframe creation
- No cross-origin script loading — avoids CORS blocks entirely
- Guard against missing container with null check
2026-06-03 18:40:04 +08:00
Tolaria
0fbe169815 update
All checks were successful
Deploy Docs / deploy (push) Successful in 23s
2026-06-03 18:29:35 +08:00
Tolaria
dd37f2ea40 contributing heart icon 2026-06-03 18:29:22 +08:00
Tolaria
7c1143befc fix: use venv for pip install to avoid externally-managed-environment
All checks were successful
Deploy Docs / deploy (push) Successful in 23s
2026-06-03 18:17:17 +08:00
Tolaria
cff4e8c8ee merge: pages → main — images, Cusdis comments, footer polish, cleanup
Some checks failed
Deploy Docs / deploy (push) Failing after 12s
2026-06-03 18:12:52 +08:00
Tolaria
9bc2a55251 merge: images-work — hero images, footer polish, caption overlays 2026-06-03 18:12:06 +08:00
Tolaria
b1e129ed6e chore: add Cusdis comments, clean up build artifacts
- Add Cusdis comment integration (zensical.toml + overrides partial)
- Add comments:true to homepage frontmatter
- Gitignore codedb.snapshot and old root build artifacts
- Remove tracked old build files (site/ is the new build output)
2026-06-03 18:12:01 +08:00
Tolaria
bc94fb954c ci: trigger forgejo runner test
Some checks failed
Deploy Docs / deploy (push) Failing after 17s
2026-06-03 18:10:23 +08:00
Tolaria
8491b0f751 fix: install python3 via apt in node:22 runner image
Some checks failed
Deploy Docs / deploy (push) Failing after 11s
2026-06-03 17:59:43 +08:00
Tolaria
2eb1170992 refactor: remove all AI-generated images, use nature_bathing.jpg
- Delete all AI-generated PNGs (hero images + infographics)
- Strip <figure> references from 5 pages that had AI hero images
- Strip <figure> references from 4 pages that had AI infographics
- Grounding in Nature now uses nature_bathing.jpg (credit: Adamu)
- Remaining images are Unsplash-sourced only
2026-06-03 17:58:58 +08:00
Tolaria
b042f43cdd fix: use system python3 instead of setup-python action
Some checks failed
Deploy Docs / deploy (push) Failing after 4s
2026-06-03 17:40:53 +08:00
Tolaria
1ca6266464 fix: change runs-on to ubuntu-latest to match runner label
Some checks failed
Deploy Docs / deploy (push) Failing after 41s
2026-06-03 17:37:06 +08:00
Tolaria
6fea770e71 feat: add zensical config and theme overrides
Some checks are pending
Deploy Docs / deploy (push) Waiting to run
2026-06-03 17:35:10 +08:00
Tolaria
d399f510b7 feat: port zensical source content from pages branch 2026-06-03 17:32:27 +08:00
Tolaria
54e74a0f04 ci: forgejo actions workflow to build zensical and deploy to pages 2026-06-03 17:31:53 +08:00
Tolaria
4e9e16b735 feat: overlay image captions on bottom-right corner
- Captions now positioned over the image (absolute, bottom-right)
- Semi-transparent white background with subtle blur
- Smaller text (0.68rem), no emojis
- Remove markdown='1' from figure tags so img is direct child
- Merged .page-hero and .page-infographic styles
2026-06-03 17:30:24 +08:00
Tolaria
12494bf0f0 feat: full-width images, Grebedoc badge, footer polish
- Make hero and infographic images full-width with minimal caption area
- Remove frosted glass card chrome from image figures (cleaner look)
- Add Grebedoc 88x31 banner to footer next to Zensical link
- Change 'Made with' to 'Built with Zensical'
- Right-align image captions, reduce font size for subtlety
- Add footer badge flex layout CSS
2026-06-03 17:06:41 +08:00
Tolaria
8b0a086d37 feat: add hero images and infographics to all content pages
- Add Unsplash hero images with photographer credits to 4 pages:
  collective-awakening, community-sovereignty, daily-sadhana, digital-wellness
- Add AI-generated hero images (GPT-5.4-Image-2) to 5 pages:
  finding-purpose, spiritual-hygiene, digital-sovereignty,
  nourishing-body, grounding-nature
- Add AI-generated infographics to 4 content-rich pages:
  collective-awakening (4-step circle practice + compass),
  community-sovereignty (freedom network wheel),
  spiritual-hygiene (frequency chart + rhythm),
  daily-sadhana (sadhana mandala)
- Add CSS for .page-hero, .page-infographic, and .ai-credit styling
- All images include alt text, lazy loading, and proper credits
- Created empty overrides directory for Zensical build compatibility
2026-06-03 16:45:05 +08:00
57 changed files with 3724 additions and 1964 deletions

View file

@ -0,0 +1,58 @@
name: Deploy Docs
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: Install Python 3.12 via uv
run: |
export PATH="$HOME/.local/bin:$PATH"
uv python install 3.12
- name: Build site
run: |
export PATH="$HOME/.local/bin:$PATH"
uv venv --python 3.12 /tmp/venv
. /tmp/venv/bin/activate
python --version
uv pip install zensical
uv pip install -e .
python3 main.py
zensical build --clean
- name: Deploy to pages branch
run: |
set -e
git config user.name "forgejo-actions"
git config user.email "forgejo-actions@noreply.local"
git fetch origin pages
git worktree add /tmp/pages-deploy origin/pages
cd /tmp/pages-deploy
git rm -rf --ignore-unmatch .
cp -r "$GITHUB_WORKSPACE"/site/* .
cp "$GITHUB_WORKSPACE"/site/.[!.]* . 2>/dev/null || true
git add .
if ! git diff --staged --quiet; then
git commit -m "deploy: zensical build from ${GITHUB_SHA::7}"
git push origin HEAD:pages
else
echo "No changes to deploy"
fi
env:
GITHUB_WORKSPACE: ${{ github.workspace }}
GITHUB_SHA: ${{ github.sha }}

10
.gitignore vendored
View file

@ -162,3 +162,13 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder. # option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/ #.idea/
PASSWORD.txt PASSWORD.txt
.hermes
codedb.snapshot
# Old build artifacts (now in site/)
/404.html
/index.html
/search.json
/sitemap.xml
/objects.inv
TODO.md

367
404.html
View file

@ -1,367 +0,0 @@
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Tools for a more conscious and free humanity">
<meta name="author" content="aja">
<link rel="icon" href="/assets/images/favicon.png">
<meta name="generator" content="zensical-0.0.43">
<title>up</title>
<link rel="stylesheet" href="/assets/stylesheets/modern/main.fba56155.min.css">
<link rel="stylesheet" href="/assets/stylesheets/modern/palette.dfe2e883.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&amp;display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style>
<script>__md_scope=new URL("/",location),__md_scope.pathname.endsWith("/")||(__md_scope=new URL(__md_scope.pathname+"/",location)),__md_hash=e=>[...e].reduce(((e,t)=>(e<<5)-e+t.charCodeAt(0)),0),__md_get=(e,t=localStorage,_=__md_scope)=>JSON.parse(t.getItem(_.pathname+"."+e)),__md_set=(e,t,_=localStorage,a=__md_scope)=>{try{_.setItem(a.pathname+"."+e,JSON.stringify(t))}catch(e){}},document.documentElement.setAttribute("data-platform",navigator.platform)</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer" aria-label="Navigation"></label>
<div data-md-component="skip">
<a href="#__skip" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="/" title="up" class="md-header__button md-logo" aria-label="up" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-book-open" viewBox="0 0 24 24"><path d="M12 7v14M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer" aria-label="Navigation">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-menu" viewBox="0 0 24 24"><path d="M4 5h16M4 12h16M4 19h16"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
up
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="none" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-sun" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg>
</label>
<input class="md-option" data-md-color-media="none" data-md-color-scheme="slate" data-md-color-primary="indigo" data-md-color-accent="indigo" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-moon" viewBox="0 0 24 24"><path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/></svg>
</label>
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search" aria-label="Search">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-search" viewBox="0 0 24 24"><path d="m21 21-4.34-4.34"/><circle cx="11" cy="11" r="8"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog" aria-label="Search">
<button type="button" class="md-search__button">
Search
</button>
</div>
<div class="md-header__source">
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="/" title="up" class="md-nav__button md-logo" aria-label="up" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-book-open" viewBox="0 0 24 24"><path d="M12 7v14M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/></svg>
</a>
up
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="/" class="md-nav__link">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-rocket" viewBox="0 0 24 24"><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09"/><path d="M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05"/></svg>
<span class="md-ellipsis">
Welcome!
</span>
</a>
</li>
<li class="md-nav__item">
<a href="/markdown/" class="md-nav__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M22.27 19.385H1.73A1.73 1.73 0 0 1 0 17.655V6.345a1.73 1.73 0 0 1 1.73-1.73h20.54A1.73 1.73 0 0 1 24 6.345v11.308a1.73 1.73 0 0 1-1.73 1.731zM5.769 15.923v-4.5l2.308 2.885 2.307-2.885v4.5h2.308V8.078h-2.308l-2.307 2.885-2.308-2.885H3.46v7.847zM21.232 12h-2.309V8.077h-2.307V12h-2.308l3.461 4.039z"/></svg>
<span class="md-ellipsis">
Markdown in 5min
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="On this page">
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1>404 - Not found</h1>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-circle-arrow-up" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="m16 12-4-4-4 4M12 16V8"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2026 The authors
</div>
Made with
<a href="https://zensical.org/" target="_blank" rel="noopener">
Zensical
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate":null,"base":"/","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.sections","navigation.top","navigation.tracking","search.highlight"],"search":"/assets/javascripts/workers/search.e2d2d235.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null}</script>
<script src="/assets/javascripts/bundle.6e5f0216.min.js"></script>
</body>
</html>

194
_extensions/wikilinks.py Normal file
View file

@ -0,0 +1,194 @@
"""
Python-Markdown extension: converts [[Wikilinks]] to standard Markdown links.
Mirrors the behavior of mkdocs-ezlinks-plugin's WikiLinkScanner, but as a
pure Markdown preprocessor (no MkDocs plugin API needed). Zensical handles
the resulting links natively.
Syntax:
[[Page Name]] [Page Name](/page-name/)
[[Page Name|Display Text]] [Display Text](/page-name/)
[[Page Name#anchor]] → [Page Name](/page-name/#anchor)
[[Page Name#anchor|Text]] → [Text](/page-name/#anchor)
![[image.png]] ![image.png](/image.png)
Tolaria-compatible: when the vault root is the project root, links like
``[[docs/contributing/index]]`` are stripped of the ``docs/`` prefix and
converted to root-relative URLs (e.g. ``/contributing/``) that work from
any page regardless of depth.
Code blocks (fenced and inline) are skipped wiki links inside them pass
through unchanged.
"""
from __future__ import annotations
import re
from markdown.preprocessors import Preprocessor
from markdown.extensions import Extension
# Regex for a wiki link. Borrowed from mkdocs-ezlinks-plugin's
# WikiLinkScanner with minor adjustments.
_WIKILINK_RE = re.compile(
r"""
(?P<image>\!?) # optional ! for image embeds
\[\[ # opening [[
(?P<link>[^#\|\]]*?) # target (everything before #, |, or ]])
(?:\#(?P<anchor>[^\|\]]+)?)? # optional #anchor
(?:\|(?P<text>[^\]]+)?)? # optional |display text
\]\] # closing ]]
""",
re.VERBOSE,
)
# Match fenced code blocks or inline code spans (single capture group).
_CODE_RE = re.compile(
r"(```.*?```|`[^`\n]+`)",
re.DOTALL,
)
# Prefix to strip from Tolaria-generated links when the vault root is
# the project root (so links look like [[docs/foo/bar]]).
_DOCS_PREFIX = "docs/"
def _slugify(text: str) -> str:
"""Convert a human page name into a filename slug.
Mirrors ezlinks: lowercase, spaces hyphens, strip unsupported chars.
Keeps forward slashes for subdirectory paths, dots for extensions, and CJK.
"""
slug = text.strip().lower()
slug = re.sub(r"\s+", "-", slug)
# Keep: word chars, hyphens, dots, forward slashes, CJK
slug = re.sub(r"[^\w./\u4e00-\u9fff\-]", "", slug)
return slug
def _url_from_link(link: str) -> str:
"""Convert a wiki link target to a root-relative URL.
Handles Tolaria-style full paths: strips ``docs/`` prefix,
removes ``.md`` extension, collapses ``/index`` suffixes,
slugifies each component, and prepends ``/``.
"""
raw = link.strip()
# Strip .md extension
raw = re.sub(r"\.md$", "", raw, flags=re.IGNORECASE)
# Strip docs/ prefix (Tolaria vault root = project root)
if raw.lower().startswith(_DOCS_PREFIX):
raw = raw[len(_DOCS_PREFIX) :]
# Collapse trailing /index — section index pages resolve to the dir
raw = re.sub(r"/index$", "", raw)
if not raw:
return "/"
# Slugify each path component
parts = [_slugify(p) for p in raw.split("/") if p]
return "/" + "/".join(parts) + "/"
def _display_name(link: str) -> str:
"""Derive a human-readable title from a wiki link path.
``[[docs/contributing/index]]`` ``Contributing``
``[[docs/strategies/collective-awakening]]`` ``Collective Awakening``
``[[Contributing]]`` ``Contributing``
"""
raw = link.strip()
# Strip .md extension
raw = re.sub(r"\.md$", "", raw, flags=re.IGNORECASE)
# Strip docs/ prefix
if raw.lower().startswith(_DOCS_PREFIX):
raw = raw[len(_DOCS_PREFIX) :]
parts = [p for p in raw.split("/") if p]
if not parts:
return link
# If the last component is "index", use the parent directory name
if parts[-1].lower() == "index":
name = parts[-2] if len(parts) >= 2 else parts[-1]
else:
name = parts[-1]
# Replace hyphens/underscores with spaces, title-case
name = name.replace("-", " ").replace("_", " ")
return name.title()
class WikilinksPreprocessor(Preprocessor):
"""Preprocessor that converts [[wikilinks]] to root-relative [text](/url/)."""
def run(self, lines: list[str]) -> list[str]:
text = "\n".join(lines)
# Walk through the text, skipping code spans. Use finditer to
# extract code regions, then transform wiki links in the gaps.
result: list[str] = []
cursor = 0
for m in _CODE_RE.finditer(text):
before = text[cursor : m.start()]
if before:
result.append(_WIKILINK_RE.sub(self._replace, before))
result.append(m.group(0))
cursor = m.end()
tail = text[cursor:]
if tail:
result.append(_WIKILINK_RE.sub(self._replace, tail))
return "\n".join(result).split("\n")
def _replace(self, match: re.Match) -> str:
groups = match.groupdict()
is_image = groups.get("image") or ""
link = groups.get("link") or ""
anchor = groups.get("anchor") or ""
text = groups.get("text") or (link if is_image else _display_name(link)) or anchor
if not (link or text or anchor):
return match.group(0)
# Build the href: root-relative URL for pages; relative for images
if is_image:
# Images: keep filename, strip docs/ prefix, make root-relative
raw = link.strip()
if raw.lower().startswith(_DOCS_PREFIX):
raw = raw[len(_DOCS_PREFIX) :]
# Non-image assets might have extensions; keep them
href = raw if "." in raw else _slugify(raw)
if not href.startswith("/"):
href = "/" + href
else:
href = _url_from_link(link)
# Append anchor if present
if anchor:
anchor_slug = _slugify(anchor)
if anchor_slug:
href = href.rstrip("/") + "#" + anchor_slug
if is_image:
return f"![{text}]({href})"
else:
return f"[{text}]({href})"
class WikilinksExtension(Extension):
"""Register the WikilinksPreprocessor."""
def extendMarkdown(self, md):
# Priority 35: after normalize_whitespace (30), before html_block (20)
md.preprocessors.register(WikilinksPreprocessor(md), "wikilinks", 35)
def makeExtension(**kwargs):
return WikilinksExtension(**kwargs)

View file

@ -1,9 +0,0 @@
# About this space
_This is a living archive for reigniting the spark within._
Multiple voices are welcome here. Not a performance of awareness, but a practice of it.
- Share what calls to you
- Add notes, reflections, or small practices
- Let contributions grow the whole garden gently

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

View file

@ -1,12 +1,13 @@
--- ---
title: Contributing title: Contributing
icon: lucide/heart-handshake
--- ---
# Contributing to Tree of Ascension Docs # Contributing to Tree of Ascension Docs
Welcome! This guide will get you from zero to making your first edit — even if you've never used git before. Welcome! This guide will get you from zero to making your first edit or new post contribution to Tree of Ascension Docs.
> **🔒 Registration is currently closed.** New contributor accounts are not available at this moment. If you'd like to get involved, solve the puzzle below to reveal the contact email and request access. > **🔒 Registration is currently closed.** Self-registration of new contributor accounts are not available at this moment. If you'd like to get involved, solve the puzzle below to reveal the contact email and request access.
--- ---
@ -63,6 +64,10 @@ Welcome! This guide will get you from zero to making your first edit — even if
})(); })();
</script> </script>
!!! info "Single article"
If you just want to contriubute a simple edit or a single article you can send it to the above address and we'll handle adding it to the site for you.
Once you have access, read on below. Once you have access, read on below.
--- ---
@ -70,15 +75,15 @@ Once you have access, read on below.
## 🛠 How it works ## 🛠 How it works
| What | Details | | What | Details |
|------|---------| | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Site host** | [Forgejo](https://forgejo.org) — a friendly, self-hosted git platform | | **Code and file hosting** | [Forgejo](https://forgejo.org) — a friendly, self-hosted git (version control) platform that manages changes and files between many users. Git is a distributed open source tool that lets you work on a folder of files and handles the cases where two users have edited the same file (called merge conflicts). |
| **Repo** | [bali.krystl.org/aja/up](https://bali.krystl.org/aja/up) | | **Repo** | [bali.krystl.org/aja/up](https://bali.krystl.org/aja/up) |
| **Built with** | [Zensical](https://zensical.org) — turns Markdown files into a beautiful docs site | | **Built with** | [Zensical](https://zensical.org) — turns Markdown files into a beautiful docs site |
| **Local editor** | [Tolaria](https://tolaria.dev) — a simple desktop app for editing Markdown with git built in | | **Local editor** | [Tolaria](https://tolaria.dev) — a simple desktop app for editing Markdown with git built in |
--- ---
## ✏️ Making your first edit ## ✏️ Making your first edit directly on Forgejo (easiest as no local setup required)
Follow these steps. If you get stuck, the answer is usually just a few clicks away. Follow these steps. If you get stuck, the answer is usually just a few clicks away.
@ -88,7 +93,7 @@ Go to **[bali.krystl.org/aja/up](https://bali.krystl.org/aja/up)** and sign in w
### Step 2 — Create your branch ### Step 2 — Create your branch
Every edit lives on its own branch. This keeps the main site safe while you work. Every edit lives on its own branch. A branch is a copy of the code that can be kept independent and later merged. This keeps the main site safe while you work and allows us to review and approve or comment on changes.
- Click the **branch dropdown** (near the top of the page, it probably says `main` or `master`) - Click the **branch dropdown** (near the top of the page, it probably says `main` or `master`)
- Type a short name for your branch — like `add-meditation-guide` or `fix-typo-daily-sadhana` - Type a short name for your branch — like `add-meditation-guide` or `fix-typo-daily-sadhana`
@ -100,7 +105,7 @@ You're now on your own copy of the site. Any changes you make stay on this branc
- Browse to the file you want to edit (all content lives in the `docs/` folder) - Browse to the file you want to edit (all content lives in the `docs/` folder)
- Click the **pencil icon** (✏️) in the toolbar above the file - Click the **pencil icon** (✏️) in the toolbar above the file
- Make your changes using Markdown (see our [Markdown quick reference](markdown.md)) - Make your changes using [Markdown](https://zensical.org/docs/authoring/markdown/)
- Scroll down and write a short commit message — something like `Add breathing exercise section` - Scroll down and write a short commit message — something like `Add breathing exercise section`
- Click **"Commit changes"** - Click **"Commit changes"**
@ -109,7 +114,7 @@ You're now on your own copy of the site. Any changes you make stay on this branc
When your changes are ready: When your changes are ready:
- Go back to the repo homepage - Go back to the repo homepage
- You'll see a banner: *"You pushed to your branch — want to open a pull request?"* - You'll see a banner: _"You pushed to your branch — want to open a pull request?"_
- Click **"Compare & pull request"** - Click **"Compare & pull request"**
- Add a title and a short description of what you changed - Add a title and a short description of what you changed
- Click **"Create pull request"** - Click **"Create pull request"**
@ -124,12 +129,13 @@ If you prefer to work on your own computer:
### You'll need ### You'll need
- **[git](https://git-scm.com/downloads)** — the version control tool
- **[Tolaria](https://tolaria.dev)** — a friendly Markdown editor with git support - **[Tolaria](https://tolaria.dev)** — a friendly Markdown editor with git support
- You can also use any text editor together with **[git](https://git-scm.com/downloads)** — the version control tool
### Steps ### Steps
```bash ```bash
# 1. Clone the repo # 1. Clone the repo
git clone https://bali.krystl.org/aja/up.git git clone https://bali.krystl.org/aja/up.git
cd up cd up
@ -143,6 +149,9 @@ git checkout -b my-edit
git add . git add .
git commit -m "Describe your changes" git commit -m "Describe your changes"
git push -u origin my-edit git push -u origin my-edit
# At this point you'll be asked for your username and password.
# You can also set up an SSH key which will mean you don't need to type these every time (you will need to email us your public key)
``` ```
Then follow Step 4 above ("Open a Pull Request") to open your pull request on Forgejo. Then follow Step 4 above ("Open a Pull Request") to open your pull request on Forgejo.

View file

@ -4,9 +4,13 @@ icon: simple/markdown
# Markdown in 5min # Markdown in 5min
## Introduction to Markdown Language
Markdown is a simple language to build web pages. It is easier to read and write than HTML (the language web browsers read) and so we use it to write articles and have a system called Zensical that will compile your Markdown into HTML. You can use this reference to help you write posts and pages directly in our repository where the source documents for this wiki are held. See [[docs/contributing/index]] for more and check the Zensical docs on authoring for a more complete set of markdown notations you can use with Tree.
## Headers ## Headers
``` ```text
# H1 Header # H1 Header
## H2 Header ## H2 Header
### H3 Header ### H3 Header
@ -17,7 +21,7 @@ icon: simple/markdown
## Text formatting ## Text formatting
``` ```text
**bold text** **bold text**
*italic text* *italic text*
***bold and italic*** ***bold and italic***
@ -27,16 +31,16 @@ icon: simple/markdown
## Links and images ## Links and images
``` ```text
[Link text](https://example.com) [Link text](https://example.com)
[Link with title](https://example.com "Hover title") [Link with title](https://example.com "Hover title")
![Alt text](image.jpg) ![Alt text](./image.jpg)
![Image with title](image.jpg "Image title") ![Image with title](./image.jpg "Image title")
``` ```
## Lists ## Lists
``` ```yaml
Unordered: Unordered:
- Item 1 - Item 1
@ -52,7 +56,7 @@ Ordered:
## Blockquotes ## Blockquotes
``` ```text
> This is a blockquote > This is a blockquote
> Multiple lines > Multiple lines
>> Nested quote >> Nested quote
@ -60,17 +64,17 @@ Ordered:
## Code blocks ## Code blocks
```` ````javascript
```javascript ```javascript
function hello() { function hello() {
console.log("Hello, world!"); console.log("Hello, world!");
} }
``` ```;
```` ````
## Tables ## Tables
``` ```text
| Header 1 | Header 2 | Header 3 | | Header 1 | Header 2 | Header 3 |
|----------|----------|----------| |----------|----------|----------|
| Row 1 | Data | Data | | Row 1 | Data | Data |
@ -79,7 +83,7 @@ function hello() {
## Horizontal rule ## Horizontal rule
``` ```text
--- ---
or or
*** ***
@ -89,7 +93,7 @@ ___
## Task lists ## Task lists
``` ```text
- [x] Completed task - [x] Completed task
- [ ] Incomplete task - [ ] Incomplete task
- [ ] Another task - [ ] Another task
@ -97,13 +101,13 @@ ___
## Escaping characters ## Escaping characters
``` ```text
Use backslash to escape: \* \_ \# \` Use backslash to escape: \* \_ \# \`
``` ```
## Line breaks ## Line breaks
``` ```text
End a line with two spaces End a line with two spaces
to create a line break. to create a line break.

View file

@ -1,26 +1,52 @@
--- ---
icon: lucide/leaf icon: lucide/leaf
comments: true
--- ---
# Tree of Ascension Docs # Tree of Ascension Docs
<figure class="godspark-hero" markdown="1"> ## Why Tree of Ascension
<img src="assets/images/hero.jpg" alt="Tree of Ascension" />
<figcaption>Every branch reaches toward the light.</figcaption>
</figure>
<p class="intro-lead gp-reveal"> The world can seem so chaotic that we feel we have no way to make an impact. But if we start with ourselves using time honoured [[docs/practices/index]] in our daily life and adopt [[docs/strategies/index]] to work together with other like hearted beings (physical or otherwise), we can certainly bring about peace and a lighter timeline, one day at a time.
A living guide for those climbing upward — practices for the body, teachings for the mind, and community for the soul. Not a destination, but a tree growing one branch at a time.
</p>
<hr class="wp-divider" /> ### Action steps
<section class="wp-section gp-reveal"> Many sprouts in this tree have action points hidden inside that you can adopt into your life if you feel resonant. Checking these items will help you feel the satisfaction of making progress. Here's a first one for free! Try checking the box below:
## How to contribute
- **Add a reflection** — short notes, practices, or questions - [ ] Read the introduction
- **Plant an idea** — link into new themed pages
- **Tend the tone** — kind, grounded edits keep the garden coherent
</section>
<p class="wp-spacer"></p> ## How this site came about
A small group of us kept having the same kind of conversation. Late nights, voice notes, walls of text — sharing things that had actually moved the needle in our own lives. Practices that stuck. Realizations that rearranged something. Books and teachers and mistakes and breakthroughs.
At some point we thought: why keep this scattered across chat logs? Let's put it somewhere. Not as experts. Not as a finished thing. Just as what it is — notes from people climbing, passing the lantern back down the trail.
---
## What we mean by ascension
Not floating off into the clouds. Not bypassing the hard stuff. Ascension, the way we talk about it, is waking up _here_. In your actual body, in your actual life, with your actual pain and joy and confusion.
It's learning to hold more light without burning out. It's noticing when you're running a program that isn't yours — from culture, from family, from fear — and gently putting it down. It goes in layers. You think you've arrived and then the next onion skin peels back and you realize you were just getting started. That's the game. That's the fun of it.
Some people call it awakening. Some call it remembering. The name doesn't matter much. What matters is that it's possible, it's happening to ordinary people everywhere, and nobody needs permission to begin.
---
## Consciousness isn't abstract
You can feel it. When your mind goes quiet and there's still someone there — aware, alive, unimpressed by the chatter. That's consciousness. Not a concept. It is you, yourself, the light of awareness reading these words.
Practices — meditation, grounding, fasting, silence, community, sound, service — are just ways of clearing the static so you can hear what was already there. The tree doesn't need to _become_ something. It just needs enough light and water to grow into what it already is.
---
## How to use this site
The [[Practices]] section is where to start. Pick one thing and try it. Not all of them. One. Give it a week.
The Strategies section is for when a practice opens a door and you want to understand the room you just walked into. Frameworks, context, the bigger picture.
Everything here is a draft. We update it when we learn something new or when someone points out we got something wrong. If something lands for you — or if it doesn't — we'd love to hear about it.
- [ ] Mark this sprout complete

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,12 @@
{
"/": 2,
"/practices/daily-sadhana/": 15,
"/practices/digital-wellness/": 4,
"/practices/grounding-in-nature/": 2,
"/practices/nourishing-the-body/": 4,
"/practices/spiritual-hygiene/": 5,
"/strategies/collective-awakening/": 4,
"/strategies/community-sovereignty/": 8,
"/strategies/digital-sovereignty/": 8,
"/strategies/finding-purpose/": 4
}

View file

@ -1,46 +1,77 @@
--- ---
icon: material/meditation icon: material/meditation
--- ---
# Daily Sadhana # Daily Sadhana
*Sadhana* means daily spiritual practice — not something you do when you have time, but the foundation you build everything else upon. It doesn't require a temple or a teacher. It requires showing up. *Sadhana* means daily spiritual practice — not something you do when you have time, but the foundation upon which you build everything else. The best time to practice is first thing in the morning, ideally waking an hour before sunrise. At this hour the energy is quiet, as the world is still asleep. Settling into meditation during the 48 minutes surrounding sunrise lets you ride a moment when the energy is in transition — and your practice can have a far greater impact.
--- ***
## Morning routine
Drinking water on waking helps re-hydrate, as the body hasn't drunk anything for several hours. Warm water, or at least room temperature (not cold) is best.
Juice of one lemon or lime, 2 or 3 fingers of water, half spoon of bicarbonate of soda/baking soda (food grade, aluminium free) mixed in a tall glass, first thing in the morning helps regulate any excess acidity and re-hydrate.
## Meditation ## Meditation
Sit. Breathe. That's the whole instruction. - [ ] Sit quietly for 5 minutes — your bed, a chair, a floor, anywhere
- [ ] Notice when the mind wanders and gently return to breath
- [ ] Do this every morning for one week
Start with five minutes. The mind will wander — that's what minds do. The practice is not emptying the mind but noticing when it has wandered and gently returning. Every return is a rep. Like any muscle, attention strengthens with use. Start with five minutes. The mind will wander — that's what minds do. The practice is not emptying the mind but noticing when it has drifted and gently returning to the breath. Every return is a rep, and like any muscle, attention strengthens with use.
No app needed. No special cushion. A chair, a floor, a patch of grass — anywhere you can be still. You can use meditate on your bed, in the car, on a chair or the floor, a patch of grass — anywhere you can be still.
--- ### Zen
The word *zen* traces back through the Chinese *chan* to the Sanskrit *dhyāna*, meaning meditation or deep absorption. The ancient sages studied this state with extraordinary care, and the depth of their insight is something our modern mind can only begin to appreciate. See Patanjali's *Yoga Sutras* if you'd like to go deeper.
#### Focus
The mind can rest on many different objects in meditation. We suggest starting with the breath, since it is a simple and direct link to your soul and to the universe — every breath is an exchange between your being and the greater oneness that holds it.
You can also choose another single point of focus to help the mind settle — a sound (mantra) or a form (yantra). In all, there are 112 techniques for focusing the mind, explored in the ancient text *Vijñāna Bhairava Tantra*.[1](#user-content-fn-1)
***
## Gratitude journal ## Gratitude journal
Before bed or first thing in the morning, write down three things you are genuinely grateful for. Not generic blessings — specific moments. The warmth of sunlight through a window. A conversation that landed. The taste of a ripe fruit. - [ ] Before bed or first thing, write down 3 specific things you're grateful for
- [ ] Do this every day for one week and notice the shift
Gratitude is not toxic positivity. It is the deliberate practice of noticing what is already good, which rewires the brain away from its negativity bias over time. Not generic blessings — specific moments. The warmth of sunlight through a window. A conversation that landed. The taste of a ripe fruit.
--- Gratitude is the deliberate practice of noticing what is already good, which rewires the brain away from its negativity bias over time.
## Personality defect removal ## Merit journal
This is the inner work few want to do: asking honestly where you are still reactive. The merit journal is a practice for reinforcing the virtues in our personality. It can be as simple as noting a smile you offered a stranger on the street or the time you spent truly listening to a friend's concern. By writing down the good you've done, you create a record to reflect upon — especially valuable in the moments before leaving the body at the end of life. Our character is the one thing we carry with us when we depart, so it is well worth the effort to reflect upon and cultivate it.
- Where am I still carrying anger? - [ ] Write an entry in your merit journal
- What am I afraid of?
- How can I be more patient today?
- Where could I replace judgment with kindness?
Don't fix it all at once. Pick one thread and follow it. The goal is not to become perfect — it is to become less defended, more available, more unconditionally loving. Not toward everyone else first — toward yourself. ***
## Improvements journal
This is the inner work few want to do: asking honestly where you are still reactive, and where your character could grow more harmonious and balanced.
Almost every emotion has its time and place. Sometimes it is good to rest or to feel impatient, and anger can be necessary to provoke action. In general, though, we can soften the distorted forms of these emotions (emotion is energy in motion) and cultivate their positive counterparts instead. Balance is the aim.
- [ ] Ask yourself: Where am I still carrying anger?
- [ ] Ask yourself: What am I afraid of?
- [ ] Ask yourself: How can I be more patient today?
- [ ] Replace one judgment with kindness today
To start, pick the one with the most impact, often anger. The goal is not to become perfect — it is to become less impulsive, more available, more unconditionally loving. Starting with yourself is key. Notice your thought patterns and how you speak to yourself. Do you scold yourself over a trivial mistake? How might you extend and deepen your patience toward yourself?
??? question "A simple evening practice" ??? question "A simple evening practice"
Sit quietly and replay the day. Notice any moment where you contracted — irritation, defensiveness, avoidance. Don't judge the reaction. Just see it. Tomorrow, you'll have another chance.
--- Sit quietly and replay the day. Notice any moment where you contracted — irritation, defensiveness, avoidance. Don't judge the reaction. Just see it. Tomorrow, you'll have another chance. If you like you can journal your reflections and over time you may see just by noticing them things have started to resolve.
After reviewing the key area you'd like to work on you can use auto-suggestion to improve it.
***
## Movement: energy and strength ## Movement: energy and strength
@ -48,20 +79,30 @@ The body needs two kinds of movement every day:
**Energy practice** — yoga, tai chi, qigong, or simple stretching with breath awareness. This moves *prana* (life force) through the channels of the body. Even ten minutes shifts the nervous system from fight-or-flight to rest-and-digest. **Energy practice** — yoga, tai chi, qigong, or simple stretching with breath awareness. This moves *prana* (life force) through the channels of the body. Even ten minutes shifts the nervous system from fight-or-flight to rest-and-digest.
**Cardio and strength** — walking briskly, running, bodyweight exercises, lifting. The body evolved to move against resistance. Without it, the mind stagnates too. - [ ] Do 10 minutes of energy practice this morning (yoga, stretching, tai chi)
- [ ] Do 20 minutes of cardio or strength work today
**Cardio and strength** — walking briskly, running, bodyweight exercises, lifting. The body evolved to move against resistance. Without it, the mind stagnates too. Cardio comes in two intensities, and both are necessary: low intensity (such as energy practice or gardening) and high intensity (such as running, cycling, swimming, or tennis). High intensity is anything that raises your heart rate and makes you sweat.
Pair them. Energy practice in the morning to open; strength in the afternoon to ground. Pair them. Energy practice in the morning to open; strength in the afternoon to ground.
--- ***
## Visualization: morning and night ## Visualization: morning and night
Every morning and every night before sleep, spend two minutes visualizing the future you want — for yourself, your family, your community, your 'tribe.' See it as if it is real *now*. Feel the gratitude as if it has already arrived. - [ ] Spend 2 minutes each morning visualizing the future you want — see it as real *now*
- [ ] Spend 2 minutes before sleep visualizing the same — feel the gratitude as if it arrived
This is not magical thinking. It is the practice of orienting the subconscious toward what you are building, so that during the day, you recognize the doors when they appear. This is the practice of orienting the subconscious toward what you are building, so that during the day, you recognize the doors when they appear.
--- ***
**Related:** [Finding Your Purpose](../../teachings/finding-purpose.md) — when sadhana meets direction. **Related:** [Finding Your Purpose](../../strategies/finding-purpose.md) — when sadhana meets direction.
*What practice will you show up for tomorrow?* *What practice will you show up for tomorrow?*
- [ ] Mark this sprout read
## Footnotes
1. The *Vijñāna Bhairava Tantra*, a 7th8th century Kashmir Shaivism text, presents 112 dhāraṇās (meditation techniques) as a dialogue between Bhairava and the goddess Bhairavi, who together personify the interplay between consciousness and energy. [Wikipedia](https://en.wikipedia.org/wiki/Vij%C3%B1%C4%81na_Bhairava_Tantra) [](#user-content-fnref-1)

View file

@ -4,6 +4,11 @@ icon: material/phone-check
# Digital Wellness # Digital Wellness
<figure class="page-hero">
<img src="../assets/images/digital-wellness.jpg" alt="A peaceful nature scene — digital detox in the forest" loading="lazy">
<figcaption>Photo by <a href="https://unsplash.com/@lianhao">Lianhao Qu</a> on Unsplash</figcaption>
</figure>
Your attention is the most valuable resource you own. Every notification, every algorithmic feed, every autoplay is designed to extract it. Taking it back is not a luxury — it is a prerequisite for any kind of awakening. Your attention is the most valuable resource you own. Every notification, every algorithmic feed, every autoplay is designed to extract it. Taking it back is not a luxury — it is a prerequisite for any kind of awakening.
--- ---
@ -12,6 +17,8 @@ Your attention is the most valuable resource you own. Every notification, every
Try this: no news for one week. No headlines, no push alerts, no doom-scrolling. The world will continue. The things you actually need to know will reach you through people, not algorithms. Try this: no news for one week. No headlines, no push alerts, no doom-scrolling. The world will continue. The things you actually need to know will reach you through people, not algorithms.
- [ ] Try a one-week news fast — no headlines, no push alerts, no doom-scrolling
After a week, notice: is your anxiety lower? Is your attention span longer? Are you more present with the people in front of you? After a week, notice: is your anxiety lower? Is your attention span longer? Are you more present with the people in front of you?
!!! note "The 0% horror rule" !!! note "The 0% horror rule"
@ -35,9 +42,10 @@ Set boundaries you can actually keep:
- [ScreenZen](https://screenzen.co/) — makes you pause before opening apps, breaking the reflex loop. - [ScreenZen](https://screenzen.co/) — makes you pause before opening apps, breaking the reflex loop.
- [Kids360](https://kids360.app/) — for children's devices, with transparent limits rather than secret surveillance. - [Kids360](https://kids360.app/) — for children's devices, with transparent limits rather than secret surveillance.
- No screens in the bedroom. Charge devices in another room. - No screens in the bedroom. Charge devices in another room.
- Read a physical book or have a real conversation instead of reaching for a screen in idle moments. - [ ] Remove or mute one app that drains your attention
- [ ] Replace one hour of screen time this week with an outdoor activity
The goal is not abstinence. It's agency. The point is to cultivate your agency and command over your tech, you should be the one in control.
--- ---
@ -55,6 +63,8 @@ The internet is a tool. When it becomes the environment, you've lost the plot.
--- ---
**Related:** [Digital Sovereignty](../../teachings/digital-sovereignty.md) — when wellness meets infrastructure. **Related:** [Digital Sovereignty](../../strategies/digital-sovereignty.md) — when wellness meets infrastructure.
*What's the first app you'll set a limit on today?* *What's the first app you'll set a limit on today?*
- [ ] Mark this sprout read

View file

@ -4,22 +4,42 @@ icon: material/nature-people
# Grounding in Nature # Grounding in Nature
The earth beneath your feet has been waiting for you. Not metaphorically — literally. Every moment spent with bare skin on soil, grass, or sand is a reconnection to the electromagnetic field that humans evolved within for hundreds of thousands of years. <figure class="page-hero">
<img src="../assets/images/nature_bathing.jpg" alt="Forest bathing — a person immersed in dappled woodland light" loading="lazy">
<figcaption>Photo by Adamu</figcaption>
</figure>
Every moment spent with bare skin on soil, grass, or sand is a reconnection to the electromagnetic field that humans evolved within for hundreds of thousands of years.
The Earth (whose other names include mother Gaia, Aurora, Aurelia, Tara), is a living being, and we are a small part of her.
But connecting to the ground, whether that's by contact with our bare feet, using grounding blanket or pad, or even lying down and rolling (one of the best ways to rebalance energy when it gets too high!) we are chemically interacting with our physical Source via ionic exchange.
Even if we can't physically touch the earth we can use awareness, visualisation and intention to guide our energy body down and root it into the crystalline core of mother Gaia. This crystalline core differs from the iron core of earth and is in a higher dimension.
!!! info inline end "Coming soon"
Guided meditation for grounding to mother earth
--- ---
## Why ground? ## Why ground?
Modern life separates us from the earth: rubber-soled shoes, elevated buildings, concrete pavements. The simple act of barefoot contact — called *earthing* or *grounding* — allows the body to absorb free electrons from the earth's surface. Research suggests this can reduce inflammation, improve sleep, and calm the nervous system. Modern life separates us from the earth: rubber-soled shoes, elevated buildings, concrete pavements. The simple act of barefoot contact — called _earthing_ or _grounding_ — allows the body to absorb free electrons from the earth's surface. Research has documented reductions in inflammation, improved sleep, and measurable shifts in nervous system function from regular grounding practice.[^1]
!!! note "Start small" !!! note "Start small"
Five minutes of bare feet on grass in the morning is enough to begin. You don't need a forest retreat — a patch of lawn, a beach, or even damp soil in a garden works. Five minutes of bare feet on grass in the morning is enough to begin. You don't need a forest retreat — a patch of lawn, a beach, or even damp soil in a garden works.
--- ---
## Sun gazing: reconnecting with light ## Sun gazing: reconnecting with light
Sun gazing is an ancient practice of looking at the sun during the first or last hour of daylight, when UV levels are safe. Start with 10 seconds and never push beyond comfort. The practice is less about the eyes and more about allowing the body's circadian rhythm to realign with natural light cycles. Sun gazing is an ancient practice of looking at the sun during the first or last hour of daylight, when UV levels are lower. Start with 10 seconds and never push beyond comfort. The practice is less about the eyes and more about allowing the body's circadian rhythm to realign with natural light cycles.
!!! warning "Eye safety"
Tilt you head down and look 2 inches above the Sun, not directly at it. Stop if you feel discomfort and only gradually build up the duration, starting with 10 seconds and working up to 15 minutes over 6 months is a realistic goal. Some yogis look directly at the sun during midday but this is achieved over many years of practice.
Sit. Breathe. Let the light wash over you. No agenda. Sit. Breathe. Let the light wash over you. No agenda.
@ -27,22 +47,30 @@ Sit. Breathe. Let the light wash over you. No agenda.
## Sitting practice: temples, forests, waterfalls ## Sitting practice: temples, forests, waterfalls
Find a place where nature is doing its thing without human orchestration — a forest floor, a temple courtyard, beside a waterfall. Then do the hardest thing: nothing. Find a place where nature is doing its thing without human orchestration — a forest floor, a temple courtyard, beside a waterfall. Looking at the fractal form of nature found in trees, leaves, and the entire environment is highly nourishing for the nervous system. More significantly the energy flow in nature is more balanced and harmonious, whereas buildings and rooms composed of steel, aluminium and electrosmog are dissonant and disturb this flow.
Don't meditate. Don't journal. Don't photograph. ??? info "Discover more"
Just sit and watch. Notice how the mind, given no task, eventually settles. This is *melukat* in the Balinese tradition — water purification not just of the body, but of the energetic residue we carry. Even sitting beside moving water, without entering it, can shift something. - [ ] See Dan Winter's talks on fractal geometry on YouTube
Just sit and watch. Notice how the mind, given no task, eventually settles. This is _melukat_ in the Balinese tradition — water purification not just of the body, but of the energetic residue we carry.[^2] Even sitting beside moving water, without entering it, can shift something.
--- ---
## Integrating nature time ## Integrating nature time
The guideline is simple: for every hour spent on a device, spend an equal hour in direct contact with the natural world. This isn't a punishment — it's a restoration. The guideline is simple: for every hour on a device, spend an equal hour in direct contact with the natural world. Think of it as restoration and a reward.
Start tracking it loosely. You may find, as many do, that the nature hours become the ones you crave. Start tracking it loosely. You may find, as many do, that the nature hours become the ones you crave.
--- ---
**Related:** [Nourishing the Body](../practices/nourishing-the-body.md) — bringing nature inside through food and materials. **Related:** [Nourishing the Body](nourishing-the-body.md) — bringing nature inside through food and materials.
*What patch of earth will you stand on tomorrow morning?* _What patch of earth will you stand on tomorrow morning?_
- [ ] Mark this sprout read
[^1]: Oschman JL, Chevalier G, Brown R. "The effects of grounding (earthing) on inflammation, the immune response, wound healing, and prevention and treatment of chronic inflammatory and autoimmune diseases." *Journal of Inflammation Research*, 2015. [PMC4378297](https://pmc.ncbi.nlm.nih.gov/articles/PMC4378297/)
[^2]: Melukat is a Balinese Hindu water purification ritual performed at holy springs (*tirta*) to cleanse the body and spirit. [merusaka.com](https://merusaka.com/bali-cultural-experience/bali-sacred-water-melukat-purification-ritual/)

View file

@ -4,14 +4,15 @@ icon: material/run
# Practices # Practices
Small, doable actions. Each practice here is something you can try today — no preparation, no expertise, just willingness. Small, doable actions. Each one is something you can try today — no preparation, no expertise, just willingness.
<div class="grid cards" markdown> <div class="grid cards gp-cards-practices" markdown>
- [:material-nature-people: **Grounding in Nature**](grounding-in-nature.md) — Barefoot contact, sun gazing, sitting practice, melukat - [:material-nature-people: **Grounding in Nature**](grounding-in-nature.md) Barefoot contact, sun gazing, sitting practice, melukat
- [:material-food-apple: **Nourishing the Body**](nourishing-the-body.md) — Real food, herbal teas, fasting, natural materials, self-massage - [:material-food-apple: **Nourishing the Body**](nourishing-the-body.md) Real food, herbal teas, fasting, natural materials, self-massage
- [:material-meditation: **Daily Sadhana**](daily-sadhana.md) — Meditation, gratitude, shadow work, movement, visualization - [:material-meditation: **Daily Sadhana**](daily-sadhana.md) Meditation, gratitude, shadow work, movement, visualization
- [:material-phone-check: **Digital Wellness**](digital-wellness.md) — News fast, screen limits, curating what enters your mind - [:material-phone-check: **Digital Wellness**](digital-wellness.md) News fast, screen limits, curating what enters your mind
- [:material-spa: **Spiritual Hygiene**](spiritual-hygiene.md) Cleanse your space, set intention, sound as medicine
</div> </div>

View file

@ -1,30 +1,40 @@
--- ---
icon: material/food-apple icon: material/food-apple
--- ---
# Nourishing the Body # Nourishing the Body
The body is not a machine to be fueled — it is a living garden that responds to everything you place in it, on it, and around it. Nourishment goes far beyond calories. The body is a highly sophisticated ecosystem that responds to everything you place in it, on it, and around it.
--- Our focus has been guided towards numbers like calories, steps, BMI (weight and height). These quantitative perspectives can be practical, but they often overlook the more subtle qualitative dimensions of health that can be observed and felt more easily through focused awareness than with measures and scales or lab equipment.
## Food from people, not corporations ??? info "Dive deeper"
```text
The body is comprised of a fine balance of elements in different frequencies and states. These are a reflection of the state of the underlying aether at phases and degrees of motion. For instance solid materials are heavy, dense and even though it appears inert, their molecules are actually moving, albeit very slowly. Whereas when these molecules are heated, they undergo a dissolution of the bonds (which are really not a solid thing either, more an electrostatic coupling), and they 'melt' and move from solid to liquid and eventually to a gas and residue (solid aggregate byproduct). If we take more descriptive names to the states we could say the solid "earth" moves through liquid "water" by a process called "fire" and transforms into a gas called "air". Really all these states are part of one all encompassing consciousness and energy, the essence of which is plasma or "aether" as named in Ancient Greek. Modern science disregards this final point, owing to an experiment in 1887 called the Michelson Morley experiment, however this does not actually disprove the existence aether. You can read more about this at Aether Force Blog
```
***
## Food from farmers, gardens and your plant pots, not corporations
Most of what fills supermarket shelves is the product of monopolized supply chains — processed, preserved, and profited from at every step. The alternative is older and simpler: know who grows your food. Most of what fills supermarket shelves is the product of monopolized supply chains — processed, preserved, and profited from at every step. The alternative is older and simpler: know who grows your food.
Work with local farmers. Join a CSA (community-supported agriculture). Buy from a neighbor who keeps hens. Trade skills for produce. When you eat food grown by someone you've spoken to, something shifts — you're no longer a consumer but a participant in a living exchange. Work with local farmers. Join a CSA (community-supported agriculture). Buy from a neighbor who keeps hens. Trade skills for produce. When you eat food grown by yourself or someone you've spoken to, something shifts — you feel the livingness of the food and the vitality it brings you.
!!! warning "The supermarket trap" !!! warning "The supermarket trap"
Nearly every aisle in a conventional supermarket funnels money into a handful of conglomerates. The [documentary on monopoly food systems](https://www.youtube.com/watch?v=nLZV5EesNNI) is worth watching. Start by removing one aisle at a time from your routine.
--- ```text
Nearly every aisle in a conventional supermarket funnels money into a handful of conglomerates. The [documentary on monopolies](https://www.youtube.com/watch?v=nLZV5EesNNI) covers how all the big brand food items are owned by a handful of conglomerates and VC firms and is worth watching to see how it is possible that near everything in your Walgreens or 7 eleven has been engineered for profit and without your best interest or health at heart. You could also see Pam Peeke's fantastic lecture on the Hacked and Hijacked brain on how fast food acts like cocaine on the dopamine centres of the brain, and how to reset via meditation. Start by removing one aisle at a time from your routine and soon you'll feel your taste buds catching up to your desire for healthy organic and fresh natural food and drinks.
```
***
## Herbal teas as daily medicine ## Herbal teas as daily medicine
Herbal teas are one of the gentlest ways to rebalance the body throughout the day: Herbal teas are one of the gentlest ways to rebalance the body throughout the day:
| Time | Tea | Purpose | | Time | Tea | Purpose |
|------|-----|---------| | --------------- | ------------------------------------------------ | ------------------------- |
| Morning | Flower teas (chamomile, jasmine, rose) | Light, opening, uplifting | | Morning | Flower teas (chamomile, jasmine, rose) | Light, opening, uplifting |
| After meals | Ginger tea | Digestive fire, warmth | | After meals | Ginger tea | Digestive fire, warmth |
| When agitated | Vata-pacifying (licorice, cinnamon, ashwagandha) | Grounding, calming | | When agitated | Vata-pacifying (licorice, cinnamon, ashwagandha) | Grounding, calming |
@ -32,15 +42,19 @@ Herbal teas are one of the gentlest ways to rebalance the body throughout the da
Learn your own patterns. The tea that works for someone else may not be yours — experiment gently. Learn your own patterns. The tea that works for someone else may not be yours — experiment gently.
--- - [ ] Try a new herbal tea
***
## Fasting as reset ## Fasting as reset
Fasting doesn't need to be extreme to be effective. Start with one day a week of liquids only — fresh juices, soups, herbal teas. From there, try a 24-hour water fast. With guidance, you can work toward a 3-day water fast, which triggers deeper cellular repair processes (autophagy). Fasting doesn't need to be extreme to be effective. Start with one day a week of liquids only — fresh juices, soups, herbal teas. From there, try a 24-hour water fast. With guidance, you can work toward a 3-day water fast, which triggers deeper cellular repair processes (autophagy).[1](#user-content-fn-1)
The goal is not deprivation. It's giving the digestive system the rest it rarely receives in a culture of constant consumption. It's about giving the digestive system the rest it rarely receives in a culture of constant consumption.
--- - [ ] Try eating or drinking only fruits (smoothies allowed with coconut water) for 24 hours
***
## What touches your skin ## What touches your skin
@ -48,7 +62,13 @@ Gradually replace clothing and bed linen with natural, non-toxic materials: orga
The same applies to what you put *on* your body. A self oil massage (*abhyanga*) with a simple, chemical-free oil suited to your constitution — or just pure coconut oil — is a daily practice that nourishes skin, calms the nervous system, and reconnects you to your own body with care rather than criticism. The same applies to what you put *on* your body. A self oil massage (*abhyanga*) with a simple, chemical-free oil suited to your constitution — or just pure coconut oil — is a daily practice that nourishes skin, calms the nervous system, and reconnects you to your own body with care rather than criticism.
--- - [ ] Replace one item of synthetic clothing with a fully natural alternative
??? info "Hint"
Start with underwear. A 1993 study found that polyester underwear caused significant (mostly reversible) damage to sperm production in dogs, while cotton had no effect — the cause was electrostatic charge or some other effect from wearing synthetic fabrics.[2](#user-content-fn-2)
***
## Small detox steps ## Small detox steps
@ -58,8 +78,15 @@ The same applies to what you put *on* your body. A self oil massage (*abhyanga*)
None of this needs to happen overnight. One change, held consistently, reshapes a life. None of this needs to happen overnight. One change, held consistently, reshapes a life.
--- ***
**Related:** [Grounding in Nature](../practices/grounding-in-nature.md) — where nourishment meets the earth. **Related:** [Grounding in Nature](grounding-in-nature.md) — where nourishment meets the earth.
*What's one thing your body has been quietly asking you to change?* *What's one thing your body has been quietly asking you to change?*
- [ ] Mark this sprout read
## Footnotes
1. Autophagy — the body's cellular cleanup and recycling process — was the subject of Yoshinori Ohsumi's 2016 Nobel Prize in Physiology or Medicine. Fasting is one of the most reliable ways to trigger it. [nobelprize.org](https://www.nobelprize.org/prizes/medicine/2016/ohsumi/facts/) [](#user-content-fnref-1)
2. Shafik A. "Effect of different types of textile fabric on spermatogenesis: an experimental study." *Urological Research*, 1993. [PMID: 8279095](https://pubmed.ncbi.nlm.nih.gov/8279095/) — Note: this was an animal study (dogs). [](#user-content-fnref-2)

View file

@ -0,0 +1,99 @@
---
icon: material/spa
---
# Spiritual Hygiene
Just as you wash your body, your space and energy field benefit from regular tending too. Environments hold residue, and your intention shapes what you encounter.
***
## Cleansing your space
- See the [[docs/practices/daily-sadhana]] action items that will also affect your space. The humans in a space have the greatest impact upon its vibration.
- Chanting is a very powerful way to raise vibration in a space. You can use any sound you enjoy that connects you to yourself. Chanting in the mind is more powerful than out loud.
- [ ] Clear and declutter one space in your home right now
- Clean and declutter: every object carries a subtle energetic weight, see [Marie Kondo](https://www.youtube.com/@MarieKondoTV) and [A monk's guide to a clean house and mind](https://www.thezengateway.com/culture/an-interview-with-shoukei-matsumoto-author-of-a-monk-s-guide-to-a-clean-house-and-mind)
- Cleaning is extremely important, as any dirt and detritus will repel higher consciousness beings and attract those from the lower realms, just like how if you leave a mess insects will be drawn to it, the same applies to non physical beings. A clean home and a clean heart are pre-requisites to connecting to angelic and divine beings.
- Open windows daily and allow light and fresh air to circulate through your space
- Remove electronics from the room, or at minimum cover screens
- [ ] Try a sound cleansing — ring a brass bell, play a singing bowl, or put on Solfeggio tones for 10 minutes
- Use pure frequency: a brass bell with bright tones, a tibetan or crystal singing bowl, download and play a Tarpan music, or Solfeggio tone music in the background on your phone.
- Burn natural incense or diffuse pure essential oils (frankincense, sage, palo santo)
!!! info "Discover more"
- Healing with Form, Energy and Light by Tenzin Wangyal Rinpoche
- Pranic Healing by Master Choa Kok Sui
??? question "How often should I cleanse?"
A light daily clearing (open window, intention setting) and a deeper weekly reset (sound, smoke, decluttering) is a sustainable rhythm. After arguments, illness, or visits from heavy energy, cleanse immediately and go outside for a walk.
***
## Clearing Sleep Space
Your bedroom is the most important room to tend. You spend a third of your life there, in a more unconscious and receptive state. Make your bed as soon as you wake up, crumpled sheets create surprisingly discordant energy. It also helps you feel you've achieved something and sets the precedent to take care of yourself and your life.
Before sleeping you can light a ghee or sattvic oil lamp, being careful it will not be disturbed or near any flammable items. You could keep a shrine or altar with items that make you happy and feel love, that could be family or those who have inspired you who have good character.
### Intention
Before sleep, state clearly — aloud or internally:
> *I invite only energies of the highest light to interact with me. My space is sovereign. My field is clear.*
- [ ] Set this intention aloud before sleep tonight
You don't need to believe in guides for this to work. The practice is about setting a boundary and orienting your awareness toward what is loving, clear, and true. Whatever your framework — ancestors, angels, higher self, or simply the clearest version of your own consciousness — the act of calling it in is what matters.
***
## Sound as medicine
The frequencies you surround yourself with shape your nervous system. Consider:
- Solfeggio tones — a set of frequencies used in alternative healing traditions:[^1]
- **432 Hz** — often described as calming and naturally resonant
- **528 Hz** — sometimes called the "love frequency" and associated with transformation in alternative medicine circles
- **Natural classical** — Debussy, Ravi Shankar — music that creates space rather than filling it
- **Kirtan and mantra** — collective chanting that synchronizes heart rates and entrains the group field
The rule is simple: if a song has a single negative word or message, skip it. The subconscious absorbs everything. Curate your sound environment as carefully as your food.
- [ ] Try a week of only positive, uplifting music — no negative lyrics
***
## Group singing, toning, and joy
Human voices together are one of the most powerful frequency generators available. Group singing — kirtan, toning, community choirs, or just friends around a fire — synchronizes nervous systems, releases oxytocin, and creates a field of shared vibration that lingers long after the sound stops.
Pair this with:
- **Uplifting art** — surround yourself with images that open the heart
- **Light-hearted comedy** — laughter is a genuine cleansing practice
- **Positive energy events** — gatherings where the purpose is simply to feel good together
- **Joy maxxing** is relentlessly choosing what your heart calls you to do, even if you would have been shy or too scared to pursue it normally. It could be wearing that silly hat, or singing and dancing in the rain. Take at least one day a week or one hour a day to really follow your heart!
***
## Mass meditations and peace visualization
When large numbers of people hold the same intention simultaneously, something measurable shifts. A 2017 study of large Transcendental Meditation groups found a 28.4% reduction in murder rates across 206 US urban areas during periods when the practicing group exceeded a critical threshold.[^2] Similar studies have reported reductions in violent crime, traffic fatalities, and drug-related deaths during the same periods.
Join global mass meditations when they are called. Or gather a small group — even three people — and sit together with the intention of peace and the most positive timeline for humanity.
Create something tangible to crystallize the intention: a doodle, a piece of art, a short written statement of what that positive timeline looks like *for you*. Make it specific. Make it beautiful. Keep it visible.
***
**Related:** [Daily Sadhana](daily-sadhana.md) — spiritual hygiene as daily practice.
*What's the first thing you'll clear from your bedroom tonight?*
- [ ] Mark this sprout read
[^1]: Solfeggio frequencies originate from a medieval hymn to St. John the Baptist and were reinterpreted in the 1970s by Dr. Joseph Puleo as healing tones. While many people find them subjectively calming, there is no rigorous scientific evidence that specific frequencies repair DNA or produce specific physiological effects. A 2019 review noted that most published studies on 432 Hz music are small and preliminary. [scienceinsights.org](https://scienceinsights.org/what-is-528-hz-the-love-frequency-explained/)
[^2]: Cavanaugh KL, Dillbeck MC. "Field-effects of consciousness: A follow-up study on the reduction of murder rates in large US urban areas." *Journal of Health and Environmental Research*, 2017. The study was conducted by researchers at Maharishi University of Management, the institution founded by the founder of Transcendental Meditation. Results are debated in the wider scientific community. [EurekAlert summary](https://www.eurekalert.org/news-releases/511271)

View file

@ -4,18 +4,23 @@ icon: material/hand-heart
# Collective Awakening # Collective Awakening
<figure class="page-hero">
<img src="../assets/images/collective-awakening.jpg" alt="Group of people meditating together in nature at golden hour" loading="lazy">
<figcaption>Photo by <a href="https://unsplash.com/@rishikesh_yogpeeth">Rishikesh Yogpeeth</a> on Unsplash</figcaption>
</figure>
Awakening is often described as an individual journey, but it has never been a solo project. Consciousness shifts ripple through groups, communities, and fields — and when enough people hold the same frequency simultaneously, something in the collective field changes. Awakening is often described as an individual journey, but it has never been a solo project. Consciousness shifts ripple through groups, communities, and fields — and when enough people hold the same frequency simultaneously, something in the collective field changes.
--- ---
## The power of mass intention ## The power of mass intention
Decades of research on group meditation — particularly large Transcendental Meditation assemblies — has documented statistically significant reductions in crime, violence, hospital admissions, and traffic fatalities when a critical mass (roughly the square root of 1% of a population) meditates together. Decades of research on group meditation — particularly large Transcendental Meditation assemblies — has documented correlations between group practice and reductions in crime, violence, and other social stress indicators when a critical mass (roughly the square root of 1% of a population) meditates together.[^1]
The mechanism is debated. The data is not.
When you join a mass meditation — whether online or in person — you are not just calming your own nervous system. You are contributing to a field. The intention you hold for peace, for the most positive timeline, is not private. It radiates. When you join a mass meditation — whether online or in person — you are not just calming your own nervous system. You are contributing to a field. The intention you hold for peace, for the most positive timeline, is not private. It radiates.
- [ ] Join a mass meditation this month — search online for upcoming global events
--- ---
## Creating your own circle ## Creating your own circle
@ -35,11 +40,12 @@ Do it weekly. The consistency matters more than the size.
Between gatherings, make something tangible: Between gatherings, make something tangible:
- [ ] Create a vision artifact — a doodle, statement, or drawing of the world you want to see
- **Doodles or drawings** — what does the peaceful world look like through your eyes? - **Doodles or drawings** — what does the peaceful world look like through your eyes?
- **Written statements of intent** — short, present-tense declarations: *"Clean water flows freely. Children laugh without fear. Elders are honored. The land is tended."* - **Written statements of intent** — short, present-tense declarations: *"Clean water flows freely. Children laugh without fear. Elders are honored. The land is tended."*
- **A shared board or album** — where each person contributes their vision of the positive timeline - **A shared board or album** — where each person contributes their vision of the positive timeline
These artifacts are not wishful thinking. They are anchors. When the external world looks chaotic, the images and words you've created together remind you what you are building toward — and that you are building it together. These artifacts serve as anchors. When the external world looks chaotic, the images and words you've created together remind you what you are building toward — and that you are building it together.
--- ---
@ -59,7 +65,7 @@ Do this offline where possible. Face-to-face relationships with decision makers
Through all of this, hold a simple compass: Through all of this, hold a simple compass:
- Is this action arising from love or from fear? - [ ] Before the next emotional action, ask: Is this arising from love or from fear?
- Is it connecting people or dividing them? - Is it connecting people or dividing them?
- Is it building something or only tearing something down? - Is it building something or only tearing something down?
@ -67,6 +73,10 @@ Fear-based activism burns out. Love-based activism regenerates. The most radical
--- ---
**Related:** [Spiritual Hygiene](./spiritual-hygiene.md) — keeping your own field clear so you can contribute cleanly to the collective. **Related:** [Spiritual Hygiene](../practices/spiritual-hygiene.md) — keeping your own field clear so you can contribute cleanly to the collective.
*What does the most positive timeline look like to you — in one sentence?* *What does the most positive timeline look like to you — in one sentence?*
- [ ] Mark this sprout read
[^1]: Cavanaugh KL, Dillbeck MC. "Field-effects of consciousness: A follow-up study on the reduction of murder rates in large US urban areas." *Journal of Health and Environmental Research*, 2017. A series of studies from Maharishi University researchers has found correlations between large TM-Sidhi groups and reductions in social stress indicators; the interpretation of these findings is not universally accepted. [EurekAlert summary](https://www.eurekalert.org/news-releases/511271)

View file

@ -4,7 +4,12 @@ icon: material/crowd
# Community Sovereignty # Community Sovereignty
Sovereignty is not something you achieve alone. It is built in relationship — with the land, with the people who grow food, with neighbors who share skills, and with networks that operate outside the extractive economy. <figure class="page-hero">
<img src="../assets/images/community-sovereignty.jpg" alt="People shopping at a farmers market with fresh produce" loading="lazy">
<figcaption>Photo by <a href="https://unsplash.com/@theguccer2100">Spencer Plouzek</a> on Unsplash</figcaption>
</figure>
Sovereignty grows in relationship — with the land, with the people who grow food, with neighbors who share skills, and with networks that operate outside the extractive economy.
--- ---
@ -13,9 +18,9 @@ Sovereignty is not something you achieve alone. It is built in relationship —
Every dollar spent at a supermarket feeds a system designed to concentrate wealth and power. The alternative is older than capitalism: direct relationships with the people who produce what you consume. Every dollar spent at a supermarket feeds a system designed to concentrate wealth and power. The alternative is older than capitalism: direct relationships with the people who produce what you consume.
- Join a local CSA (community-supported agriculture) - Join a local CSA (community-supported agriculture)
- Buy from farmers' markets — talk to the people behind the stall - [ ] Buy from farmers' markets — talk to the people behind the stall
- Trade skills: help with a harvest, offer web design, teach a class - [ ] Trade skills: help with a harvest, offer web design, teach a class
- Grow something yourself, even if it's just herbs on a windowsill - [ ] Grow something yourself, even if it's just herbs on a windowsill
When your food comes from someone you know, the transaction becomes a relationship. That relationship is the foundation of a parallel economy. When your food comes from someone you know, the transaction becomes a relationship. That relationship is the foundation of a parallel economy.
@ -45,10 +50,10 @@ Research what's possible in your jurisdiction. Find lawyers and politicians with
Start small: Start small:
- Cook a meal for someone who is struggling - [ ] Cook a meal for someone who is struggling
- Sit and listen to someone who is lonely — just listen, no advice - [ ] Sit and listen to someone who is lonely — just listen, no advice
- Clean a section of your local park or river - [ ] Clean a section of your local park or river
- Offer your skills (legal, technical, therapeutic) to those who cannot pay - [ ] Offer your skills (legal, technical, therapeutic) to those who cannot pay
Do three kind things every week that you tell no one about. The anonymity is part of the practice — it purifies the motivation. Do three kind things every week that you tell no one about. The anonymity is part of the practice — it purifies the motivation.
@ -86,3 +91,5 @@ Consult aligned professionals. The goal is to keep resources circulating within
**Related:** [Digital Sovereignty](./digital-sovereignty.md) — because freedom networks need free infrastructure. **Related:** [Digital Sovereignty](./digital-sovereignty.md) — because freedom networks need free infrastructure.
*Who in your community could you reach out to this week?* *Who in your community could you reach out to this week?*
- [ ] Mark this sprout read

View file

@ -10,7 +10,7 @@ Digital sovereignty means owning your own digital life — the hardware, the sof
## The hardware you already own ## The hardware you already own
You don't need a new device. An old laptop — the one gathering dust — can run Linux perfectly. Modern distributions like Linux Mint, Ubuntu, or Fedora breathe new life into aging hardware and free you from operating systems designed to extract data. An old laptop — the one gathering dust — can run Linux perfectly. Modern distributions like MX Linux or Linux Mint breathe new life into aging hardware and free you from operating systems designed to extract data.
For phones, the path is similar: For phones, the path is similar:
@ -27,11 +27,12 @@ For phones, the path is similar:
## Network sovereignty ## Network sovereignty
**Switch from WiFi to Ethernet** for your main computer. It's faster, more stable, and eliminates constant radio-frequency exposure at close range. - [ ] Switch your main computer from WiFi to Ethernet
- [ ] On your phone: switch 5G to 4G, use airplane mode when not needed
- [ ] Install and use a trusted VPN with a clear no-logging policy
- [ ] Keep your phone away from your body — not in a pocket, not against your head
**On your phone**: switch 5G to 4G (lower frequency = less power = less exposure). Keep your phone on airplane mode when not actively needed. Keep it away from your body — not in a pocket, not against your head. Zero wearables (no smartwatch, no fitness tracker, no bluetooth earbuds). **VPN**: A simple, trusted VPN prevents your internet provider from building a profile of every site you visit. Choose one with a clear no-logging policy and preferably based outside surveillance alliances. Mullvad, Nyx are good. If you want extra privacy pay via Monero.
**VPN**: A simple, trusted VPN prevents your internet provider from building a profile of every site you visit. Choose one with a clear no-logging policy and preferably based outside surveillance alliances.
**Meshtastic**: When the grid is not your friend, build your own. [Meshtastic](https://meshtastic.org/) lets you create off-grid, encrypted text networks using inexpensive LoRa radios. It's community infrastructure — no cell towers, no subscriptions, no central authority. **Meshtastic**: When the grid is not your friend, build your own. [Meshtastic](https://meshtastic.org/) lets you create off-grid, encrypted text networks using inexpensive LoRa radios. It's community infrastructure — no cell towers, no subscriptions, no central authority.
@ -45,8 +46,8 @@ Move away from Google piece by piece:
|-----------|-----| |-----------|-----|
| Gmail | [Proton Mail](https://proton.me/mail), self-hosted mail | | Gmail | [Proton Mail](https://proton.me/mail), self-hosted mail |
| Google Drive | [Syncthing](https://syncthing.net/), [Nextcloud](https://nextcloud.com/) | | Google Drive | [Syncthing](https://syncthing.net/), [Nextcloud](https://nextcloud.com/) |
| Google Photos | [Immich](https://immich.app/), local storage | | Google Photos | [Ente](https://ente.com/), local storage shared by Syncthing |
| Google Docs | [CryptPad](https://cryptpad.fr/), local office suite | | Google Docs | [CryptPad](https://cryptpad.fr/), Libre Office suite |
The principle is simple: **self-hosted first, local-first, privacy-first**. If your data lives on someone else's computer, it is not your data. The principle is simple: **self-hosted first, local-first, privacy-first**. If your data lives on someone else's computer, it is not your data.
@ -54,20 +55,17 @@ The principle is simple: **self-hosted first, local-first, privacy-first**. If y
## Passwords and keys ## Passwords and keys
Use [KeePassXC](https://keepassxc.org/) — a local, offline, open-source password manager. Unlike browser-based password managers or online services, your password database lives on your device. You control the file. Nobody can leak what they don't have. - [ ] Install KeePassXC and create your first password database
- [ ] Generate unique passwords for every important service
- [ ] Get a hardware security key (like a YubiKey) where possible
Generate unique passwords for every service. Use a hardware security key (like a YubiKey) where possible. Treat your digital keys as carefully as the keys to your home. Treat your digital keys as carefully as the keys to your home.
---
## The bigger picture
This isn't about becoming a hermit with a tin-foil hat. It's about intentionality. Every service you leave is a vote. Every open-source tool you adopt strengthens an alternative ecosystem. Every friend you help migrate multiplies the effect.
Digital sovereignty is not isolation — it's the foundation for authentic connection.
--- ---
**Related:** [Digital Wellness](../../practices/digital-wellness.md) — sovereignty begins with what you consume. **Related:** [Digital Wellness](../../practices/digital-wellness.md) — sovereignty begins with what you consume.
*What's one service you could migrate away from this month?* *What's one service you could migrate away from this month?*
- [ ] Mark this sprout read

View file

@ -10,14 +10,14 @@ Beyond making a living lies the question that has quietly followed you for years
## The passion that was always there ## The passion that was always there
For many, purpose is not something you find — it's something you remember. It was there when you were a child, before the world told you to be practical. It was in the activities that made you lose track of time. Your purpose is innate and can be seen in your passions, what you naturally feel drawn to. In childhood these may have been more evident by how you spent your free time. Your soul was born with a particular intention to experience and contribute something to this reality, this can be seen in your natural tendencies and skills or gifts. Meditation or Spiritual Hypnotherapy can be powerful way to discover life's purpose more clearly.
Ask yourself: Ask yourself:
- What would I do if money were not a concern? - [ ] Write down your answer: What would I do if money were not a concern?
- [ ] Write down your answer: What challenge have I lived through that I could help others navigate?
- What topic could I talk about for hours without tiring? - What topic could I talk about for hours without tiring?
- What makes me feel most alive — and who benefits when I am in that state? - What makes me feel most alive — and who benefits when I am in that state?
- What challenge have I lived through that I could help others navigate?
That last question is often the most direct path. The wound becomes the gift. That last question is often the most direct path. The wound becomes the gift.
@ -58,15 +58,18 @@ Spend more time with people who are on a positive frequency — those who energi
You don't need to quit your job tomorrow. Start with: You don't need to quit your job tomorrow. Start with:
- [ ] Do one unannounced act of kindness each day this week
- One hour a week on the thing that lights you up - One hour a week on the thing that lights you up
- One conversation with someone doing what you feel called to do - One conversation with someone doing what you feel called to do
- One small act of service, unannounced - One small act of service, unannounced
- One visualization, morning and night, of the future you are building - One visualization, morning and night, of the future you are building
Purpose is not a destination. It is a direction you calibrate toward, daily, with each small choice. Purpose is a direction you calibrate toward, daily, with each small choice. Which of your daily actions feel aligned with your purpose, and which ones could use a nudge in the right direction?
--- ---
**Related:** [Community Sovereignty](./community-sovereignty.md) — purpose expressed through collective action. **Related:** [Community Sovereignty](./community-sovereignty.md) — purpose expressed through collective action.
*What challenge have you lived through that someone else needs help with right now?* *What challenge have you lived through that someone else needs help with right now?*
- [ ] Mark this sprout read

18
docs/strategies/index.md Normal file
View file

@ -0,0 +1,18 @@
---
icon: material/chess-knight
---
# Strategies
Big-picture frameworks for when a practice opens a door and you're ready to walk through. These are the patterns, mindsets, and structural shifts — the strategy beneath the tactics.
<div class="grid cards gp-cards-strategies" markdown>
- [:material-shield-lock: **Digital Sovereignty**](digital-sovereignty.md) Own your hardware, software, data, and networks
- [:material-crowd: **Community Sovereignty**](community-sovereignty.md) Parallel economies, PMAs, seva, freedom networks
- [:material-compass: **Finding Your Purpose**](finding-purpose.md) Passion, suffering into service, building your tribe
- [:material-hand-heart: **Collective Awakening**](collective-awakening.md) Mass intention, circles, crystallizing the vision
</div>
Come back to these. They'll mean something different each time.

File diff suppressed because it is too large Load diff

View file

@ -1,19 +0,0 @@
---
icon: material/book-open-variant
---
# Teachings
Deeper explorations for when a practice opens a door and you want to walk through it. Frameworks, context, and the why beneath the how.
<div class="grid cards" markdown>
- [:material-shield-lock: **Digital Sovereignty**](digital-sovereignty.md) — Own your hardware, software, data, and networks
- [:material-crowd: **Community Sovereignty**](community-sovereignty.md) — Parallel economies, PMAs, seva, freedom networks
- [:material-spa: **Spiritual Hygiene**](spiritual-hygiene.md) — Cleanse your space, set intention, sound as medicine
- [:material-compass: **Finding Your Purpose**](finding-purpose.md) — Passion, suffering into service, building your tribe
- [:material-hand-heart: **Collective Awakening**](collective-awakening.md) — Mass intention, circles, crystallizing the vision
</div>
These are living documents. Return to them. They'll mean something different each time.

View file

@ -1,75 +0,0 @@
---
icon: material/spa
---
# Spiritual Hygiene
Just as you wash your body, your space and energy field require regular cleansing. This is not superstition — it is the recognition that environments hold residue, and that your intention shapes what you encounter.
---
## Cleansing your space
Your bedroom is the most important room to tend. You spend a third of your life there, unconscious and receptive.
- Open windows daily — stagnant air holds stagnant energy
- Remove electronics from the room, or at minimum cover screens
- Declutter: every object carries a subtle energetic weight
- Use sound: a bell, singing bowl, or simple clapping in corners breaks up density
- Burn natural incense or diffuse pure essential oils (frankincense, sage, palo santo)
??? question "How often should I cleanse?"
A light daily clearing (open window, intention setting) and a deeper weekly reset (sound, smoke, decluttering) is a sustainable rhythm. After arguments, illness, or visits from heavy energy, cleanse immediately.
---
## Setting intention and calling guides
Before sleep, state clearly — aloud or internally:
> *I invite only energies of the highest light to interact with me. My space is sovereign. My field is clear.*
You don't need to believe in guides for this to work. The practice is about setting a boundary and orienting your awareness toward what is loving, clear, and true. Whatever your framework — ancestors, angels, higher self, or simply the clearest version of your own consciousness — the act of calling it in is what matters.
---
## Sound as medicine
The frequencies you surround yourself with shape your nervous system. Consider:
- **432 Hz** — associated with heart coherence and natural resonance
- **528 Hz** — often called the "love frequency," used in DNA repair research
- **Natural classical** — Bach, Debussy, Ravi Shankar — music that creates space rather than filling it
- **Kirtan and mantra** — collective chanting that synchronizes heart rates and entrains the group field
The rule is simple: if a song has a single negative word or message, skip it. The subconscious absorbs everything. Curate your sound environment as carefully as your food.
---
## Group singing, toning, and joy
Human voices together are one of the most powerful frequency generators available. Group singing — kirtan, toning, community choirs, or just friends around a fire — synchronizes nervous systems, releases oxytocin, and creates a field of shared vibration that lingers long after the sound stops.
Pair this with:
- **Uplifting art** — surround yourself with images that open the heart
- **Light-hearted comedy** — laughter is a genuine cleansing practice
- **Positive energy events** — gatherings where the purpose is simply to feel good together
"Joy maxxing" is not avoidance. It is deliberate nervous system nourishment.
---
## Mass meditations and peace visualization
When large numbers of people hold the same intention simultaneously, something measurable shifts. Research on transcendental meditation groups has shown reductions in crime rates, hospital admissions, and conflict when a critical mass is reached.
Join global mass meditations when they are called. Or gather a small group — even three people — and sit together with the intention of peace and the most positive timeline for humanity.
Create something tangible to crystallize the intention: a doodle, a piece of art, a short written statement of what that positive timeline looks like *for you*. Make it specific. Make it beautiful. Keep it visible.
---
**Related:** [Daily Sadhana](../../practices/daily-sadhana.md) — spiritual hygiene as daily practice.
*What's the first thing you'll clear from your bedroom tonight?*

1265
index.html

File diff suppressed because it is too large Load diff

73
main.py
View file

@ -1,5 +1,74 @@
def main(): #!/usr/bin/env python3
print("Hello from up!") """Generate the Tree of Ascension action-points totals manifest.
Scans docs/**/*.md for Markdown tasklist items (`- [ ]` / `- [x]`), counts
them per page, and writes docs/javascripts/toa-totals.json mapping each
page's site URL -> total task count.
The action-points JS (docs/javascripts/extra.js) fetches this manifest once
on first load so nav badges show correct totals BEFORE a user has visited
every page. Counts are fully static (known from the Markdown), so this has
zero runtime cost it's a build-time artifact.
Run before `zensical build`:
python3 main.py
"""
from __future__ import annotations
import json
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parent
DOCS = ROOT / "docs"
OUT = DOCS / "javascripts" / "toa-totals.json"
# Matches a Markdown tasklist item: optional indent, list marker, [ ] or [x].
TASK_RE = re.compile(r"^\s*[-*+]\s+\[[ xX]\]\s+", re.MULTILINE)
# Matches fenced code blocks (``` or ~~~), incl. language hint, non-greedy.
# These contain tasklist *examples* (e.g. the Markdown reference doc) that render
# as plain text, NOT interactive checkboxes — so we strip them before counting.
FENCE_RE = re.compile(r"^([ \t]*)(`{3,}|~{3,}).*?\n.*?^\1\2[ \t]*$", re.MULTILINE | re.DOTALL)
def count_tasks(text: str) -> int:
"""Count real (interactive) tasklist items, excluding fenced code examples."""
stripped = FENCE_RE.sub("", text)
return len(TASK_RE.findall(stripped))
def url_for(md_path: Path) -> str:
"""Map a docs/*.md path to its built site URL (directory-style URLs).
docs/index.md -> /
docs/practices/index.md -> /practices/
docs/practices/daily-sadhana.md-> /practices/daily-sadhana/
"""
rel = md_path.relative_to(DOCS).with_suffix("")
parts = list(rel.parts)
if parts and parts[-1] == "index":
parts = parts[:-1]
path = "/" + "/".join(parts)
if not path.endswith("/"):
path += "/"
return path
def main() -> None:
totals: dict[str, int] = {}
for md in sorted(DOCS.rglob("*.md")):
text = md.read_text(encoding="utf-8")
count = count_tasks(text)
if count:
totals[url_for(md)] = count
OUT.parent.mkdir(parents=True, exist_ok=True)
OUT.write_text(json.dumps(totals, indent=2, sort_keys=True) + "\n", encoding="utf-8")
print(f"toa-totals: wrote {len(totals)} page(s) -> {OUT.relative_to(ROOT)}")
for url, n in sorted(totals.items()):
print(f" {url} {n}")
if __name__ == "__main__": if __name__ == "__main__":

25
overrides/main.html Normal file
View file

@ -0,0 +1,25 @@
{% extends "base.html" %}
{#
Action Points feature flag.
Exposes the zensical.toml setting `[project.extra.action_points] enabled`
to client-side JS as `window.TOA_ACTION_POINTS_ENABLED`. This block renders
in <head>, before extra_javascript loads in {% block scripts %}, so the
action-points engine in docs/javascripts/extra.js can bail out immediately
when the feature is disabled.
Set `enabled = false` in zensical.toml to turn the ENTIRE interactive
checklist feature off — no localStorage, no nav badges, no confetti, no
per-click work. Checkboxes then fall back to Material's default read-only
rendering. Defaults to ON when the key is absent.
#}
{% block extrahead %}
{{ super() }}
<script>
window.TOA_ACTION_POINTS_ENABLED =
{{ "false" if config.extra.action_points and config.extra.action_points.enabled == false else "true" }};
window.TOA_KEEP_IN_TOUCH_ENDPOINT =
{{ ('"' + config.extra.keep_in_touch.endpoint + '"') if config.extra.keep_in_touch and config.extra.keep_in_touch.endpoint else '""' }};
</script>
{% endblock %}

View file

@ -0,0 +1,13 @@
{% include "partials/keep-in-touch.html" %}
<h2 id="__comments">{{ lang.t("meta.comments") }}</h2>
<div id="cusdis_thread"
data-host="{{ config.extra.cusdis.host }}"
data-app-id="{{ config.extra.cusdis.app_id }}"
data-page-id="{{ page.canonical_url }}"
data-page-url="{{ page.canonical_url }}"
data-page-title="{{ page.title }}"
data-theme="auto">
</div>
<script async defer src="{{ config.extra.cusdis.host }}/js/cusdis.es.js"></script>
<noscript>Please enable JavaScript to view the comments.</noscript>

View file

@ -0,0 +1,20 @@
<div class="md-copyright">
{% if config.copyright %}
<div class="md-copyright__highlight">
{{ config.copyright }}
</div>
{% endif %}
{% if not config.extra.generator == false %}
<div class="md-copyright__badges">
<span class="md-copyright__zensical">
Built with
<a href="https://zensical.org/" target="_blank" rel="noopener">
Zensical
</a>
</span>
<a href="https://grebedoc.dev" class="md-copyright__grebedoc" title="served by Grebedoc">
<img src="https://grebedoc.dev/88x31.gif" alt="served by Grebedoc" style="image-rendering: pixelated; height: 31px; width: 88px;">
</a>
</div>
{% endif %}
</div>

View file

@ -0,0 +1,92 @@
{#
Keep In Touch — newsletter / contact capture admonition.
Rendered above the comments section on every page (included from
partials/comments.html). Lets a visitor leave a WhatsApp number and/or
email to get updates. Each field submits independently; once both are
present the widget asks for their name. Submissions POST as JSON to the
endpoint configured in zensical.toml under [project.extra.keep_in_touch].
Config (zensical.toml):
[project.extra.keep_in_touch]
endpoint = "https://subscribe.krystl.org/api/subscribe"
enabled = true
The endpoint is also exposed to JS as window.TOA_KEEP_IN_TOUCH_ENDPOINT
via overrides/main.html. Styling lives in docs/stylesheets/extra.css
(.toa-kit-*), behaviour in docs/javascripts/extra.js (Keep-In-Touch IIFE).
#}
{% if config.extra.keep_in_touch and config.extra.keep_in_touch.enabled != false %}
<section class="toa-kit gp-reveal"
data-endpoint="{{ config.extra.keep_in_touch.endpoint | default('') }}"
aria-labelledby="toa-kit-title">
<div class="toa-kit__inner">
<div class="toa-kit__glow" aria-hidden="true"></div>
<header class="toa-kit__header">
<span class="toa-kit__icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor"
stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" class="lucide">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
<path d="m22 6-10 7L2 6"></path>
</svg>
</span>
<div class="toa-kit__heading">
<h2 id="toa-kit-title" class="toa-kit__titletext">Keep In Touch</h2>
<p class="toa-kit__sub">Leave your WhatsApp or email to get updates on the journey.</p>
</div>
</header>
<form class="toa-kit__form" novalidate>
{# WhatsApp #}
<label class="toa-kit__field" data-kind="whatsapp">
<span class="toa-kit__fieldicon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor"
stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" class="lucide">
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
</svg>
</span>
<input type="tel" class="toa-kit__input" name="whatsapp"
inputmode="tel" autocomplete="tel"
placeholder="WhatsApp number" aria-label="WhatsApp number">
</label>
{# Email #}
<label class="toa-kit__field" data-kind="email">
<span class="toa-kit__fieldicon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor"
stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" class="lucide">
<rect width="20" height="16" x="2" y="4" rx="2"></rect>
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path>
</svg>
</span>
<input type="email" class="toa-kit__input" name="email"
inputmode="email" autocomplete="email"
placeholder="Email address" aria-label="Email address">
</label>
{# Name — revealed after both whatsapp + email are captured #}
<label class="toa-kit__field toa-kit__field--name" data-kind="name" hidden>
<span class="toa-kit__fieldicon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor"
stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" class="lucide">
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
</span>
<input type="text" class="toa-kit__input" name="name"
autocomplete="name"
placeholder="Your name (optional)" aria-label="Your name">
</label>
<button type="submit" class="toa-kit__send">Send</button>
</form>
<p class="toa-kit__notice" role="status" aria-live="polite" hidden></p>
</div>
</section>
{% endif %}

View file

@ -0,0 +1,296 @@
# Action Points — Interactive Checklist PRD
**Status:** Draft
**Author:** aja + Hermes
**Date:** 2026-06-03
---
## 1. Problem Statement
The Tree of Ascension site contains practices and strategies that invite the reader to *do* something — meditate, journal, take a walk barefoot, migrate off a service. Right now those calls to action are flat text. A reader who returns tomorrow has no way to see what they've already tried or what remains.
We want to make the site *participatory*: let readers check off action items, see their progress, and feel a sense of momentum. Completion should be visible and celebratory — not gamified in a manipulative way, but genuinely satisfying.
---
## 2. Feature Overview
| # | Feature | Summary |
|---|---------|---------|
| 1 | **Checkable action points** | Markdown `- [ ]` task lists that are clickable and persist checked state in `localStorage` |
| 2 | **Heading counters** | Each heading with action items underneath shows a counter (e.g., `3/5`). When all items are checked, the heading changes color and confetti drops from the top of the page |
| 3 | **Navigation badges** | Sidebar navigation items show a checkmark and color change when all action items on that page are checked |
| 4 | **Page-level completion** | The top-of-page heading (h1) reflects overall page completion with a counter |
---
## 3. Detailed Specifications
### 3.1 Checkable Action Points
**What they are:**
Any `- [ ]` Markdown task list item rendered on a page. The site already uses `pymdownx.tasklist` with `custom_checkbox = true`, which renders checkboxes. We layer interactivity + persistence on top.
**Behavior:**
- Clicking a checkbox toggles its state (unchecked ↔ checked)
- State is immediately persisted to `localStorage`
- On page load (and on instant navigation), previously saved state is restored
- If a checkbox's label text no longer matches any saved entry (content was edited), the stale entry is silently ignored
**Checkbox identification:**
Each checkbox is identified by a key derived from:
1. The page's canonical URL path (e.g., `/practices/daily-sadhana/`)
2. The normalized label text (trimmed, lowercased, collapsed whitespace)
```
Key = URL + "::" + normalized_label
```
This is stable across reloads and survives minor whitespace changes but intentionally breaks on substantial rewrites (which should reset progress anyway).
**Visual style:**
- Unchecked: current Zensical tasklist styling (green-tinted)
- Checked: strikethrough + muted color, consistent with existing site palette
---
### 3.2 Heading Counters & Completion Celebration
**Counter display:**
For each heading (h2, h3, h4) that has one or more action items in its scope, a pill badge is floated to the right of the heading:
```
## Meditation [0/2]
```
When partially complete:
```
## Meditation [1/2]
```
When fully complete — the heading and badge both shift to the site's accent aurora purple (`--gp-accent`).
**Heading scope:**
An action item belongs to the nearest preceding heading at or above its level. Concretely:
- Items after an h2 but before the next h2 belong to that h2
- Items after an h3 but before the next h2 or h3 belong to that h3
**Confetti trigger:**
When the last unchecked item under a heading is checked (counter goes from `(n-1)/n` to `n/n`):
- A confetti burst animates from the top of the viewport
- Confetti uses the site's palette (greens, aurora purple, soft gold)
- Animation lasts ~3 seconds
- Respects `prefers-reduced-motion` (skips entirely)
**Confetti implementation:** Custom canvas animation (zero dependency).
Two tiers:
- **Heading completion:** Subtle aurora particle shower — ~2s, calm, particles in site palette. Accompanied by a soft 432 Hz sine chime (Web Audio API, gentle attack/decay envelope).
- **Page-level completion:** More energetic burst — ~3s, denser particles. Accompanied by an ascending arpeggio centered on 528 Hz (Web Audio API, sine waves with smooth envelope).
Both respect `prefers-reduced-motion` (confetti skipped, sounds skipped).
---
### 3.3 Navigation Integration
**Sidebar nav items:**
Each link in the left sidebar that points to a page with action items:
- Displays a pill badge next to the link text showing the completion count (e.g., `2/5`)
- When all items on that page are complete, the badge becomes a ✓ checkmark and the link text shifts to the accent color
**Index page aggregation:**
Section index pages (e.g., `/practices/`) aggregate completion across all their sub-pages. The badge shows the combined total — e.g., `12/28` summing all practice pages. Sub-page grouping is derived from URL structure: `/practices/daily-sadhana/` is a child of `/practices/`.
**How it works:**
1. After a page renders and checkboxes are initialized, compute `{ checked, total }` for that page
2. Store the summary in `localStorage` under the page URL
3. Find the corresponding `<a>` element in the sidebar navigation and inject the badge/checkmark
4. Re-run on every page navigation (instant or full)
**Edge cases:**
- Pages with no action items: no badge, no color change
- Deleted pages: stale localStorage entries don't render (no nav element to match)
---
### 3.4 Page-Level Heading
The top-of-page `<h1>` gets a pill badge (right-aligned) showing overall page progress:
```
# Daily Sadhana [4/12]
```
Same color-change logic as section headings: when complete, the h1 turns accent-colored.
The h1 counter aggregates *all* action items on the page — it's the sum of all section counts.
---
### 3.5 Progress Export (trivial add-on)
A small "Download my progress" link in the page footer or near the comments section. Clicking it triggers a browser download of a JSON file containing the full localStorage state. This lets users:
- Back up their progress before clearing browser data
- Share their completion state (import could come later)
Implementation is ~10 lines: read `localStorage`, create a `Blob`, trigger download via a temporary `<a>` element.
---
## 4. Technical Design
### 4.1 localStorage Schema
```json
{
"toa-action-points": {
"version": 1,
"pages": {
"/practices/daily-sadhana/": {
"lastUpdated": "2026-06-03T12:00:00.000Z",
"checked": [
"sit. breathe. that's the whole instruction.",
"write down three things you are genuinely grateful for"
]
},
"/strategies/digital-sovereignty/": {
"lastUpdated": "2026-06-03T12:30:00.000Z",
"checked": [
"switch from wifi to ethernet for your main computer"
]
}
}
}
}
```
- Keys are the site-relative URL path (without domain; works across environments)
- `checked` is an array of normalized label strings
- `version` allows future schema migrations
- One key per page keeps reads/writes small
### 4.2 Instant Navigation Compatibility
The site uses `navigation.instant` (SPA-style page transitions). Zensical/Material for MkDocs exposes `document$` as an observable for navigation events.
Our JS hooks into:
- `DOMContentLoaded` — for initial page load
- `document$.subscribe` — for instant navigation transitions
On each navigation:
1. Wait for DOM to settle (the new page content is rendered)
2. Scan for tasklist items
3. Restore saved state from localStorage
4. Inject counters into headings and h1
5. Update sidebar nav badges for *all* pages (not just current — because the current page's completion may have changed)
### 4.3 Storage Limit
`localStorage` is typically 510 MB per origin. Our schema is compact (a few KB even with many pages). No practical risk of hitting the limit.
### 4.4 Performance
- DOM scanning on each navigation: O(n) where n = number of tasklist items on a page (typically < 30)
- Nav badge updates: O(sidebar links × pages with data), well under 1ms
- confetti: canvas-based, runs off main thread via `requestAnimationFrame`
All work is < 5ms per navigation; no perceptible impact.
---
## 5. Future: Cross-Device Persistence (v2)
### 5.1 Problem
`localStorage` is per-browser, per-device. A reader who checks items on their phone won't see them on their laptop.
### 5.2 Solution sketch
- User optionally enters their email address
- We store a mapping: `email → checked_items` on a lightweight server
- On page load, if an email is stored in localStorage, fetch state from the server
- On checkbox toggle, sync to server (debounced)
- No authentication required — email is the identifier (like Cusdis comments)
- Server can be a simple SQLite-backed Python/FastAPI service or even a Cloudflare Worker + D1
### 5.3 Why not now
- Requires deploying and maintaining a server
- Adds latency and failure modes
- `localStorage` solves 80% of the value with 0% of the infrastructure cost
- We ship v1, learn from usage, then decide if cross-device is worth it
---
## 6. Content Authoring Guide
For content authors, "action points" are simply `- [ ]` Markdown task lists. No special syntax, no frontmatter, no directives.
```markdown
## Meditation
- [ ] Sit quietly for 5 minutes
- [ ] Notice when the mind wanders and return to breath
- [ ] Do this every morning for one week
```
The JS layer automatically detects these and adds interactivity. To opt a page *out* of action-point tracking entirely (e.g., index pages with task lists that aren't meant to be checked off), add frontmatter:
```yaml
---
action_points: false
---
```
---
## 7. Open Questions
1. **Confetti style — subtle or playful?**
A gentle aurora-colored particle shower that respects the site's calm aesthetic, or a more energetic celebration? The site's ethos ("not gamified in a manipulative way, but genuinely satisfying") points toward subtle — soft particles in the site palette, ~2-second duration, no sound.
2. **Should index pages (e.g., `/practices/`) track action items?**
Index pages use grid cards, not task lists. Likely `action_points: false` by default for any page without `- [ ]` items. But if someone adds checklist items to an index, should they track? Probably yes — detection is automatic unless explicitly opted out.
3. **Counter placement on headings — inline badge or superscript?**
`## Meditation [0/2]` (inline, after heading text) vs `## Meditation` with a small pill badge. Inline is simpler, less DOM manipulation, and works with existing heading anchors. I'd recommend inline.
4. **Navigation badges — all pages or only pages with action items?**
Only pages with at least one action item should get a badge. Empty counters clutter the sidebar. This means we compute on first page visit and store the `total` count — pages with total=0 get no badge.
5. **When a user edits the Markdown source (adding/removing items), how should we handle stale localStorage entries?**
Stale entries (label text no longer matches any rendered checkbox) are silently dropped. New items start unchecked. This is the least-surprising behavior — edits "reset" progress only for changed items, not the whole page.
6. **Should completion state be exportable/downloadable?**
A "download my progress" button would let users save their state as a JSON file before clearing browser data. Nice-to-have for v1.1.
7. **Confetti: custom canvas or `canvas-confetti` library?**
- Custom: ~60 lines of JS, full control over palette and behavior, zero dependency, but more code to maintain
- `canvas-confetti`: battle-tested, good defaults, one function call, but adds ~7 KB dependency
Leaning custom — the palette matching and reduced-motion respect are trivial to implement and the site already values self-contained minimalism.
---
## 8. Implementation Plan (high-level)
| Phase | What | Files touched |
|-------|------|--------------|
| 1 | Core checkbox persistence (read/write localStorage) | `docs/javascripts/extra.js` |
| 2 | Heading counters + color change | `docs/javascripts/extra.js`, `docs/stylesheets/extra.css` |
| 3 | Confetti on completion | `docs/javascripts/extra.js` (custom canvas) |
| 4 | Navigation badge injection | `docs/javascripts/extra.js`, `docs/stylesheets/extra.css` |
| 5 | Page-level h1 counter | `docs/javascripts/extra.js`, `docs/stylesheets/extra.css` |
| 6 | Opt-out frontmatter support | `docs/javascripts/extra.js` |
| 7 | Test across all content pages + mobile | manual QA |
All JS goes in the existing `docs/javascripts/extra.js`. All CSS in `docs/stylesheets/extra.css`. No new files, no new dependencies, no build pipeline changes.
---
## 9. Success Criteria
- [ ] Clicking a `- [ ]` checkbox toggles its visual state
- [ ] Refreshing the page preserves checked state
- [ ] Navigating to another page and back preserves checked state
- [ ] Headings show accurate counters (e.g., `2/5`)
- [ ] When a heading reaches full completion, it changes to accent color
- [ ] Confetti plays when the last item under a heading is checked (and not on reduced-motion)
- [ ] Navigation sidebar shows badges for pages with action items
- [ ] Fully-completed pages show ✓ checkmark in nav
- [ ] Page h1 shows overall completion counter
- [ ] Zero console errors on any page
- [ ] Works on mobile (touch events fire correctly on checkboxes)
- [ ] No visual regression on pages without action items

View file

@ -1,3 +1,7 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project] [project]
name = "up" name = "up"
version = "0.1.0" version = "0.1.0"
@ -6,7 +10,8 @@ readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"
dependencies = [] dependencies = []
[tool.hatch.build.targets.wheel]
packages = ["_extensions"]
[dependency-groups] [dependency-groups]
dev = [ dev = ["zensical>=0.0.43"]
"zensical>=0.0.43",
]

File diff suppressed because one or more lines are too long

View file

@ -1,3 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
</urlset>

View file

@ -0,0 +1,4 @@
node_modules
data
.git
*.md

View file

@ -0,0 +1,33 @@
# ── Subscribe Service ────────────────────────────────────────────────────
# Keep In Touch — subscribe capture endpoint for Tree of Ascension docs.
#
# Deploy on Coolify:
# 1. Point the service to this repo (or a subfolder if supported)
# 2. Set Build Pack: Dockerfile
# 3. Add a persistent volume at /app/data
# 4. Set env vars (PORT, ALLOW_ORIGIN, ADMIN_TOKEN)
# 5. Map your domain (e.g. subscribe.krystl.org)
FROM node:22-alpine
# Create unprivileged user
RUN addgroup -S app && adduser -S -G app app
WORKDIR /app
# Dependencies first for layer caching
COPY package.json ./
RUN npm install --omit=dev && npm cache clean --force
# Application
COPY server.js ./
# Persistent data volume + ownership
RUN mkdir -p /app/data && chown -R app:app /app
USER app
EXPOSE 8080
ENV PORT=8080
CMD ["node", "server.js"]

View file

@ -0,0 +1,16 @@
{
"name": "toa-subscribe-service",
"version": "1.0.0",
"description": "Keep In Touch — subscribe capture endpoint for Tree of Ascension docs. Captures WhatsApp / email / name into SQLite.",
"type": "module",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"engines": {
"node": ">=20"
},
"dependencies": {
"better-sqlite3": "^11.8.1"
}
}

248
subscribe-service/server.js Normal file
View file

@ -0,0 +1,248 @@
/**
* Keep In Touch subscribe capture service.
*
* A tiny dependency-light HTTP service (Node core http + better-sqlite3) that
* receives JSON submissions from the docs site "Keep In Touch" widget and
* upserts them into a SQLite database. Designed to run in a single container
* on Coolify with a persistent volume, mirroring the Cusdis deployment.
*
* Endpoints:
* POST /api/subscribe capture/upsert a subscriber -> { ok: true }
* GET /api/health liveness probe -> { ok: true }
* GET /api/subscribers list (requires ADMIN_TOKEN) -> [ ... ]
*
* A submission is keyed by whatsapp OR email whichever is present. As the
* widget collects more fields across submissions (email after whatsapp, then
* name), each POST sends the full known set, and we merge into the existing
* row rather than creating duplicates.
*
* Environment:
* PORT listen port (default 8080)
* DB_PATH SQLite file path (default ./data/subscribers.db)
* ALLOW_ORIGIN CORS allow-origin (default "*"; set to your site origin)
* ADMIN_TOKEN if set, required as `Authorization: Bearer <token>` for
* GET /api/subscribers
*/
import http from "node:http";
import { dirname } from "node:path";
import { mkdirSync } from "node:fs";
import Database from "better-sqlite3";
const PORT = parseInt(process.env.PORT || "8080", 10);
const DB_PATH = process.env.DB_PATH || "./data/subscribers.db";
const ALLOW_ORIGIN = process.env.ALLOW_ORIGIN || "*";
const ADMIN_TOKEN = process.env.ADMIN_TOKEN || "";
const MAX_BODY = 16 * 1024; // 16 KB cap — these payloads are tiny.
// ── Database ────────────────────────────────────────────────────────────
mkdirSync(dirname(DB_PATH), { recursive: true });
const db = new Database(DB_PATH);
db.pragma("journal_mode = WAL");
db.pragma("busy_timeout = 5000");
db.exec(`
CREATE TABLE IF NOT EXISTS subscribers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
whatsapp TEXT,
email TEXT,
name TEXT,
first_page TEXT,
first_url TEXT,
user_agent TEXT,
ip TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_subscribers_email
ON subscribers(email) WHERE email IS NOT NULL AND email <> '';
CREATE UNIQUE INDEX IF NOT EXISTS idx_subscribers_whatsapp
ON subscribers(whatsapp) WHERE whatsapp IS NOT NULL AND whatsapp <> '';
`);
const findByEmail = db.prepare(
"SELECT * FROM subscribers WHERE email = ? LIMIT 1"
);
const findByWhatsApp = db.prepare(
"SELECT * FROM subscribers WHERE whatsapp = ? LIMIT 1"
);
const insertRow = db.prepare(`
INSERT INTO subscribers (whatsapp, email, name, first_page, first_url, user_agent, ip)
VALUES (@whatsapp, @email, @name, @first_page, @first_url, @user_agent, @ip)
`);
const updateRow = db.prepare(`
UPDATE subscribers
SET whatsapp = COALESCE(NULLIF(@whatsapp, ''), whatsapp),
email = COALESCE(NULLIF(@email, ''), email),
name = COALESCE(NULLIF(@name, ''), name),
updated_at = datetime('now')
WHERE id = @id
`);
const listRows = db.prepare(
"SELECT * FROM subscribers ORDER BY updated_at DESC LIMIT 1000"
);
// ── Validation / normalization ──────────────────────────────────────────
function normEmail(v) {
return typeof v === "string" ? v.trim().toLowerCase() : "";
}
function normWhatsApp(v) {
if (typeof v !== "string") return "";
const cleaned = v.trim().replace(/[^\d+]/g, "");
const digits = cleaned.replace(/[^\d]/g, "");
if (digits.length < 7 || digits.length > 15) return "";
return cleaned;
}
function isValidEmail(v) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v);
}
function clean(v, max = 200) {
return typeof v === "string" ? v.trim().slice(0, max) : "";
}
// Upsert: find an existing row by email or whatsapp, merge; else insert.
const upsert = db.transaction((rec) => {
let existing = null;
if (rec.email) existing = findByEmail.get(rec.email);
if (!existing && rec.whatsapp) existing = findByWhatsApp.get(rec.whatsapp);
if (existing) {
updateRow.run({
id: existing.id,
whatsapp: rec.whatsapp,
email: rec.email,
name: rec.name,
});
return { id: existing.id, created: false };
}
const info = insertRow.run(rec);
return { id: info.lastInsertRowid, created: true };
});
// ── HTTP helpers ──────────────────────────────────────────────────────────
function cors(res) {
res.setHeader("Access-Control-Allow-Origin", ALLOW_ORIGIN);
res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.setHeader("Vary", "Origin");
}
function json(res, status, obj) {
cors(res);
res.writeHead(status, { "Content-Type": "application/json" });
res.end(JSON.stringify(obj));
}
function clientIp(req) {
const xff = req.headers["x-forwarded-for"];
if (typeof xff === "string" && xff.length) return xff.split(",")[0].trim();
return req.socket.remoteAddress || "";
}
function readBody(req) {
return new Promise((resolve, reject) => {
let size = 0;
const chunks = [];
req.on("data", (c) => {
size += c.length;
if (size > MAX_BODY) {
reject(new Error("payload too large"));
req.destroy();
return;
}
chunks.push(c);
});
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
req.on("error", reject);
});
}
// ── Server ─────────────────────────────────────────────────────────────
const server = http.createServer(async (req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
if (req.method === "OPTIONS") {
cors(res);
res.writeHead(204);
res.end();
return;
}
if (req.method === "GET" && url.pathname === "/api/health") {
return json(res, 200, { ok: true });
}
if (req.method === "GET" && url.pathname === "/api/subscribers") {
if (ADMIN_TOKEN) {
const auth = req.headers["authorization"] || "";
if (auth !== `Bearer ${ADMIN_TOKEN}`) {
return json(res, 401, { ok: false, error: "unauthorized" });
}
} else {
// No admin token configured — refuse rather than leak data.
return json(res, 403, { ok: false, error: "admin token not configured" });
}
return json(res, 200, { ok: true, subscribers: listRows.all() });
}
if (req.method === "POST" && url.pathname === "/api/subscribe") {
let raw;
try {
raw = await readBody(req);
} catch (e) {
return json(res, 413, { ok: false, error: "payload too large" });
}
let data;
try {
data = JSON.parse(raw || "{}");
} catch (e) {
return json(res, 400, { ok: false, error: "invalid JSON" });
}
const email = normEmail(data.email);
const whatsapp = normWhatsApp(data.whatsapp);
if (email && !isValidEmail(email)) {
return json(res, 422, { ok: false, error: "invalid email" });
}
if (!email && !whatsapp) {
return json(res, 422, {
ok: false,
error: "provide a valid email or whatsapp number",
});
}
const rec = {
whatsapp,
email,
name: clean(data.name, 120),
first_page: clean(data.page, 300),
first_url: clean(data.url, 500),
user_agent: clean(req.headers["user-agent"], 400),
ip: clientIp(req),
};
try {
const result = upsert(rec);
return json(res, 200, { ok: true, id: result.id, created: result.created });
} catch (e) {
console.error("upsert failed:", e);
return json(res, 500, { ok: false, error: "server error" });
}
}
json(res, 404, { ok: false, error: "not found" });
});
server.listen(PORT, () => {
console.log(`[subscribe] listening on :${PORT} (db: ${DB_PATH})`);
});
// Graceful shutdown so SQLite WAL checkpoints cleanly.
function shutdown() {
server.close(() => {
try { db.close(); } catch {}
process.exit(0);
});
}
process.on("SIGTERM", shutdown);
process.on("SIGINT", shutdown);

86
theming.md Normal file
View file

@ -0,0 +1,86 @@
---
title: Theming
---
# Zensical Consciousness Theme — Plan & Prompt Document
## 1. Goal
Build a nature/consciousness-themed, beautiful, pastel/iridescent, performance-safe theme
for a multi-contributor Zensical awareness site about reigniting the God Spark within.
## 2. What we learned from Zensical customization
- Theme extension is mostly additive:
- `zensical.toml``extra_css` for extra stylesheets.
- Page templates can be overridden by placing matching files under `overrides/`.
- Site theming is largely controlled by palette/color attributes:
- `data-md-color-scheme`
- `data-md-color-primary`
- `data-md-color-accent`
- `extra.css` is the safest layer; it shouldnt break Zensical if it only adds selectors
and doesnt overwrite core layout-critical rules blindly.
- We should keep JS minimal, lazy-friendly, and nonblocking for contributors.
## 3. Non-goals / constraints
- No TypeScript/React build pipeline rerouting.
- No breaking built-in Zensical navigation/search/skip behavior.
- No space/technology motif — instead: botanical/organic/aurora/nature.
- Animations must respect load speed and reduced-motion.
- Theme should still be readable as Markdown documentation after styling.
## 4. Adapting MotionSites-style prompts for Kimi
From the example landing-page prompts:
- Use: typography system, motion patterns, component thinking, copy composition.
- Remove: React/TS/Vite/Framer Motion specifics.
- Replace with: plain HTML/CSS + minimal vanilla JS utilities that Zensical can load.
## 5. Ready-to-run Kimi prompt (refined)
You are a web designer specializing in calm, premium editorial interfaces.
Create a Zensical theme add-on for a consciousness/awakening awareness site.
Theme name placeholder: "God Spark". Site title is temporary and may change later.
Constraints:
- Output must be plain HTML/CSS/JS only.
- Must work as a Zensical `extra.css` drop-in plus optional `overrides/` partials.
- Do NOT use React, TypeScript, Tailwind build, Framer Motion, or shadcn/ui.
- Do NOT break Zensical core behavior.
- Performance-first: no heavy dependencies; any JS should be small and optional.
- Accessibility-first: readable contrast, reduced-motion safe, semantic markup.
Design brief:
- Aesthetic: futuristic pastel + iridescent, but inspired by nature rather than space/tech.
Soft aurora-like gradients, botanical motifs, dappled-light effects, gentle watercolor-like transitions.
- Color palette references: soft lavender, mist, pearl, sage, blush, iris, morning frost.
- Typography: elegant serif headings, clean sans-serif body. Use standard system fonts or
Google Fonts loaded with `preconnect` if needed.
- Contributions UI must remain friendly for many contributors: simple class names, clear areas
to edit content blocks, great default headings, friendly call-to-action language.
Functional requirements:
1. Provide one CSS file intended as Zensical's `extra.css` entry.
2. Provide optional HTML/JS micro-animations:
- fade-up reveal on scroll via IntersectionObserver
- soft parallax cursor glow (optional, turned off by default)
3. Provide at least 2 override template examples for `overrides/` (e.g., `main.html`, `footer.html`)
that layer glass surfaces and brand text without removing existing placeholders.
4. Include README with install steps, customization guidance, and contributor notes.
## 6. Execution plan
1. Create an isolated sandbox outside the project.
2. Generate theme kit using the prompt above with Kimi.
3. Review generated files for Zensical safety before pulling into the project.
4. Keep the prompt in `docs/zensical-theme-plan.md` for refinement.
## 7. Where this is saved
- Path: `/home/a/w/up/docs/zensical-theme-plan.md`
- Reuse by updating this file and rerunning Kimi from the same sandboxed branch/tree.

View file

@ -232,7 +232,7 @@ wheels = [
[[package]] [[package]]
name = "up" name = "up"
version = "0.1.0" version = "0.1.0"
source = { virtual = "." } source = { editable = "." }
[package.dev-dependencies] [package.dev-dependencies]
dev = [ dev = [

View file

@ -9,8 +9,8 @@
[project] [project]
repo_url = "https://bali.krystl.org/aja/up" # repo_url = "https://bali.krystl.org/aja/up"
repo_name = "Contribute" # repo_name = "Contribute"
# The site_name is shown in the page header and the browser window title # The site_name is shown in the page header and the browser window title
# #
# Read more: https://zensical.org/docs/setup/basics/#site_name # Read more: https://zensical.org/docs/setup/basics/#site_name
@ -47,10 +47,25 @@ Copyright &copy; 2026 The authors
# can be defined using TOML syntax. # can be defined using TOML syntax.
# #
# Read more: https://zensical.org/docs/setup/navigation/ # Read more: https://zensical.org/docs/setup/navigation/
# nav = [ nav = [
# { "Get started" = "index.md" }, { "Home" = "index.md" },
# { "Markdown in 5min" = "markdown.md" }, { "Practices" = [
# ] "practices/index.md",
"practices/daily-sadhana.md",
"practices/digital-wellness.md",
"practices/grounding-in-nature.md",
"practices/nourishing-the-body.md",
"practices/spiritual-hygiene.md",
] },
{ "Strategies" = [
"strategies/index.md",
"strategies/collective-awakening.md",
"strategies/community-sovereignty.md",
"strategies/digital-sovereignty.md",
"strategies/finding-purpose.md",
] },
{ "Contributing" = "contributing/index.md" },
]
# With the "extra_css" option you can add your own CSS styling to customize # With the "extra_css" option you can add your own CSS styling to customize
# your Zensical project according to your needs. You can add any number of # your Zensical project according to your needs. You can add any number of
@ -307,6 +322,34 @@ toggle.name = "Switch to light mode"
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# The "extra" section contains miscellaneous settings. # The "extra" section contains miscellaneous settings.
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
[project.extra.cusdis]
host = "https://cusdis.krystl.org"
app_id = "d9ab4b66-d5f1-4514-a475-1a824f69530f"
lang = "en"
# ----------------------------------------------------------------------------
# Action Points — interactive checklist feature flag.
# Set enabled = false to disable the ENTIRE feature (localStorage progress,
# nav badges, heading pills, confetti, and all per-click JS). Checkboxes then
# render as Material's default read-only tasklist. The flag is exposed to the
# client via overrides/main.html as window.TOA_ACTION_POINTS_ENABLED.
# ----------------------------------------------------------------------------
[project.extra.action_points]
enabled = true
# ----------------------------------------------------------------------------
# Keep In Touch — subscribe widget (rendered above comments on every page).
# Captures a visitor's WhatsApp number and/or email (and later their name)
# and POSTs them as JSON to `endpoint`. Set enabled = false to hide the
# widget entirely. The endpoint is exposed to client JS as
# window.TOA_KEEP_IN_TOUCH_ENDPOINT via overrides/main.html and as the
# data-endpoint attribute on the widget (overrides/partials/keep-in-touch.html).
# ----------------------------------------------------------------------------
[project.extra.keep_in_touch]
enabled = true
endpoint = "https://subscribe.krystl.org/api/subscribe"
#[[project.extra.social]] #[[project.extra.social]]
#icon = "fontawesome/brands/github" #icon = "fontawesome/brands/github"
#link = "https://github.com/user/repo" #link = "https://github.com/user/repo"
@ -327,6 +370,7 @@ toggle.name = "Switch to light mode"
[project.markdown_extensions.md_in_html] [project.markdown_extensions.md_in_html]
[project.markdown_extensions.toc] [project.markdown_extensions.toc]
permalink = true permalink = true
[project.markdown_extensions."_extensions.wikilinks:WikilinksExtension"]
[project.markdown_extensions.pymdownx.arithmatex] [project.markdown_extensions.pymdownx.arithmatex]
generic = true generic = true
[project.markdown_extensions.pymdownx.betterem] [project.markdown_extensions.pymdownx.betterem]