Tutorial: 2026-06-25

2026-06-25

Newest entry on top.

engine-v3 → v3-only + dropped the expansion mechanism

Owner decided (clear-eyed, after I showed the coupling was only ~20 <rays>/<dap> tokens and v3 is a complete standalone catalog) to go v3-only and drop expansions to lighten the code — "nobody's going to use the old stuff." Done in verified stages on feature/v3-only-drop-expansions:

  1. Deleted data/blocks/v1/ + v2/ (+ metas); repointed the only two live v3 expansion tokens (v3/scene/futuristic.js) to {#dap}/{#legacy}. Verified (84 tests) → commit cf61dd4.
  2. Removed the <expansion> stage from the engine (engine.js DEFAULT_ORDER + settings.js promptModulesblock → prompt-salt → list → cleanup), deleted core/stages/expansion.js, gutted expansion loading from promptFilesAndSuggestions, retired the expansion integration/snapshot tests (re--u'd the snapshot). 83 tests → commit 2d33db2.
  3. Removed the SPA expansion UI: the legacy "Expansions" building-block tab + expansionItems, the "Save as Expansion" feature (toggle/button/panel/state/handler + SaveIcon), the composite-loader expansion override, and the custom-expansion store + its tests (customStore keeps presets). Prettier-fixed the engine files from step 2 (they'd have failed CI format:check). 28 SPA tests.
  4. Deleted data/expansions-obsolete/. Smoke + build still green (the migrated v3/expansion/ DPLs live on as {#dap}/{#rays}/{#coffecup}… generators; only the legacy <> mechanism + data are gone).

Net: lint warnings 140 → 18, ~300+ old generator files gone. Trivial dead code left for a follow-up (loader expansionNames/readExpansion/globs, fakeLoader expansion support, settings.expansionFiles). Used PowerShell throughout. Merged --no-ff to dev.

Split the repo into engine-v1-2 (frozen) + engine-v3 (the project)

Owner wanted the tangled repo cleansed into two fully separate worlds. Iterated on the exact shape via several questions, landing on: engine-v1-2/ = the literal pre-revival snapshot restored from git history; engine-v3/ = the single maintained project (new system relocated there); zero shared files; no expansions in v3; root README must point users to both and mark the old complete.

Found the revival boundary: de4d6c5 (tooling modernization) → 5f56ccb (CJS→ESM 2.0.0) → 805c527 (src/+data/ reorg). So the pre-revival snapshot = 241a148 (parent of de4d6c5). Stages:

  1. git archive 241a148 → extracted into engine-v1-2/ (self-contained: own package.json/lock, webui.bat/update.bat, web/ inside). Committed.
  2. Pure relocation: git mv src/, web-app/, data/, tests/, scripts/ + package.json/configs into engine-v3/ preserving relative structure so cross-folder imports survive. Moved root node_modules in. Verified green (88 tests + SPA build) — committed.
  3. Removed the transitional ESM legacy from engine-v3/src (classic server+web/, CLI, image/upscale/ animation, loadSettings/diffSettings/etc., legacy prompt-modules stages + helpers). git rm needed -f because the CRLF working-tree "modifications" made git refuse plain removal. Rewrote scripts/smoke-test.mjs to boot the core engine (nodeLoader + settings.js) instead of common.js. Verified: lint 0 errors, smoke OK, 84 unit + 30 SPA, build green — committed (539bb38).
  4. Verified engine-v1-2 runs: npm install (130 era packages; node-fetch@2 is CJS, fine on Node 24), node index.js --generate-images false produced a prompt. Works like it did.
  5. Retargeted .github/workflows/ci.yml to run inside engine-v3/ (working-directory + cache paths), cleaned engine-v3 package.json (removed start/server/webui scripts + main → core/engine.js), wrote the root README (engine-v3 active / engine-v1-2 frozen+complete).

Used PowerShell throughout (never bash). CRLF noise (core.autocrlf=true, empty git diff) left alone; staged only real changes. Follow-ups noted in the changelog + engine-split.md.

Triaged the old /generate page for SPA carry-over

Owner wanted to see the legacy classic-server prompt page to figure out what's left to port to the new SPA. Started the classic server via PowerShell (npm run server, port 7861) and opened /generate (src/web/views/generate.pug) — purely to view it; no old code touched (classic server is frozen and slated for deletion). Walked the full sidebar control list with the owner and sorted every field into buckets, grounded in settings.js / image-settings.js, notes/reference/prompt-dsl.md, and notes/plans/v3-layers.md.

Owner decisions: image-AI settings (size/sampler/cfg/seed/steps/upscale/url/negative/mode) → the future provider abstraction (deferred); emphasis/editing/alternating → rework, keep as input but make output provider-dependent and modern (verified via web search: (word:1.2) weighting still exists in ComfyUI but Flux barely responds; old (((x))) + "masterpiece, best quality" framing is dated) and cut the global auto-roll; chaos / keyword counts / auto-fx / auto-artists / anime-words → DPL + v3 wrapper; all animation + salt settings → drop ({salt} token already covers salting); per-image actions (variation/reroll/upscale-file) → future image viewer/editor; folder paths + pipeline → port to SPA app config; keepers = promptCount + keyword/artist list selectors; listEntriesUsedOnce/reloadLists…park & investigate.

Recorded it in notes/plans/generate-page-triage.md (full disposition table + four-sweep order — Sweep 1 = prune the DPL-replaced/animation/salt settings in the SPA/core engine only) and added Sweep 1 as item 00 in notes/plans/next-steps.md. Notes-only commit on dev (no VERSION bump). Reaffirmed the "old stuff is being deleted, only touch the new server" directive. Used PowerShell only — never the bash sandbox. Working tree shows mass M files but git diff is empty — pure CRLF noise (core.autocrlf=true), left untouched; staged only the notes files.

Adopted the fairyfox git-flow standard + renamed mastermain

Owner said "check the fairyfox system for updates" → ran the check-report-wait flow. The system dev had been force-pushed (a1bc7e6c5659f8), so the --ff-only clone pull aborted; refreshed the read-only clone with git reset --hard origin/dev instead (it's a git-ignored mirror with no local work). Reported the diff and waited; owner said proceed with the full migration.

The headline standard change: hub/standards/git-workflow.md replaced the lean "dev → main fast-forward" model with full git-flow — two long-lived branches (main + dev), three support types (feature/*, release/*, hotfix/*), all merges --no-ff, every commit on main a tagged release, and mastermain mandatory. Adopted it project-side:

  • Renamed mastermain (git branch -m, published origin/main). Default-branch flip on GitHub + deleting origin/master are left as owner GitHub-side steps (flagged).
  • Repointed CI: ci.yml ([dev, master][dev, main]), pages.yml and release.yml ([master][main]), and reworded their FF-only header comments to the git-flow / tagged-release model. visual-baselines.yml is workflow_dispatch-only — untouched.
  • Rewrote the git-workflow docs: notes/reference/git-workflow.md (full git-flow), the CLAUDE.md "Default Workflow" steps 5–6 + "GitHub Is Part of Default Management" trigger, and the master/FF-only references in deployment.md, versioning.md, and status.md.

Also noted the lighter system changes for later (no project action needed now): docs-site back-linking relaxed to one required "← Back to Fairy Fox" link (breadcrumbs/footer now recommended-only), guidance on theming generator-produced docs (relevant to our JSDoc site), and a registry honesty rule — and that our registry branch: dev is correct (it tracks the work branch, not the default branch; an earlier status note misread it).

Observation (pre-existing, unrelated): git status shows ~510 files as modified but git diff --numstat reports zero content changes across the whole tree — a core.autocrlf=true stale-index / line-ending artifact, not real edits. Staged only the specific migration files so none of that phantom churn entered the commit. Worth a deliberate cleanup pass (e.g. a committed .gitattributes

  • git add --renormalize) at some point.

No VERSION bump — this is a process/CI/docs change, which doesn't move the number.

SFW by default + a top-bar NSFW toggle (2.6.1)

Owner asked: "in the header until we get an options screen have an NSFW toggle, right-aligned, make sure the whole project defaults to SFW, NSFW requires a confirmation popup, have it remember the preference — we haven't properly set that up yet."

Found the gating was already done in the engine — it reads settings.includeAdult everywhere (core/listStore.js, core/stages/block.js + expansion.js, gatedLists.js, promptFilesAndSuggestions.js). The SPA just never set the flag or surfaced a control, so it was effectively undefined/falsy with no UI. So this was a UI-only job:

  • web-app/src/lib/settings.js: added includeAdult: false to defaultSettings → whole app defaults SFW. (Persistence was already automatic — useSettings saves all settings to localStorage, so the preference is remembered.)
  • New web-app/src/components/NsfwToggle.jsx: a role="switch" pill labelled NSFW. OFF→ON opens a confirmation modal (18+ / adult-content warning, Cancel / "Enable NSFW"); ON→OFF is immediate. Escape / overlay click cancels.
  • web-app/src/App.jsx: added a .topbar-spacer flex filler + <NsfwToggle> so it sits at the right edge of the title bar.
  • web-app/src/styles.css: switch + confirm-modal styles, matching the dark theme tokens.

Bumped to 2.6.1 (ordinary feature → PATCH per the VERSION guide). Updated plans/removed-pending-readd.md (the "Allow adult content switch" half of the removed Style toggle now exists; list split + Style control still pending) and status.md.

Verification (run in PowerShell): npm run lint 0 errors (169 pre-existing legacy warnings), npm run format, npm run smoke OK (reports 2.6.1), npm run web:build OK, npm run test:unit 88/88, npm run test:web 30/30, npm run test:e2e:update 8/8. The home.spec.js .topbar .wordmark text assertion is unaffected.

Landmine — stale Playwright preview server gave a false green. playwright.config.js sets reuseExistingServer: !process.env.CI, so the visual run will silently reuse whatever is already on port 4173. A preview server left running from an earlier session served the OLD build (no toggle), so the topbar visual test "passed" against the old baseline and --update-snapshots left the PNGs untouched (mtime unchanged) — looked verified but wasn't. Fix: kill the listener on 4173 (Get-NetTCPConnection -LocalPort 4173 -State Listen | %{ Stop-Process -Id $_.OwningProcess -Force }) before the visual run; when in doubt, delete the *-win32.png baselines so Playwright is forced to write fresh ones. After doing that, topbar-chromium-win32.png grew 3826→5835 B and home-full-chromium-win32.png 79890→81785 B (toggle now captured); sidebar unchanged. Worth adding to notes/plans/testing.md / fix-patterns.md.

Linux baselines — investigated and resolved (not a bug). First worry was that CI's e2e job (which DOES run the visual specs — ci.yml's comment about skipping them is stale; nothing sets PLAYWRIGHT_SKIP_VISUAL) would fail on the toggle. It didn't — CI stayed green. Dug in because the regenerated Linux topbar baseline came back byte-identical to the pre-toggle one. Root cause: the right-aligned pill changes the wide/short .topbar screenshot by just under the global maxDiffPixelRatio: 0.02 (playwright.config.js), so the strict compare passes AND --update-snapshots declines to rewrite in place. Confirmed the toggle really does render under CI's engine by screenshotting the production vite preview build with Playwright's bundled chromium locally (tmp/shot-bundled.mjs) — switch present, topbar 3826→~5700 B. So: no production bug, the toggle renders everywhere. To keep the Linux baselines truthful (the in-place update couldn't), git rm'd the two affected Linux PNGs, pushed, re-ran the "Update visual baselines (Linux)" workflow (writes the real render when the baseline is absent), downloaded the artifact, and committed the refreshed topbar(→6010 B)/home-full Linux PNGs. CI green on dev afterward.

Threshold note worth acting on later: the 0.02 ratio is loose enough that a small header control slips under it on the .topbar spec — visual regression gives weak coverage for small chrome changes. Consider a tighter maxDiffPixels/ratio (or a dedicated tight assertion) for the topbar. Logged for notes/plans/testing.md.

Onboarded into the fairyfox system (hub mesh) — project-side reconciliation

Followed the hub's onboarding-existing-project runbook (from the read-only clone at assets/references/fairyfox.io/) to fold this established repo into the fairyfox mesh properly. Surveyed first: the hub clone was already pulled (git-ignored), VERSION (2.6.0) is real, the notes system is mature, the branch model is devmaster, and the project is already registered in the hub's registry.yml + _data/projects.yml. So most of the audit was already green — the real project-side gaps were the mesh-awareness block and an unthemed docs site.

What changed this session (all project-side; the hub repo was deliberately not touched):

  • CLAUDE.md — added the standing instruction "Cross-project standards & checking the fairyfox system for updates" (the check-for-updates flow + guardrails), adapted to this repo's devmaster model and the assets/references/fairyfox.io/ clone path. Added the explicit "stay inside this repo only — report hub-side changes to the owner" guardrail.
  • notes/reference/cross-project-sync.md (new) — the project-side record of the sync model the mesh-awareness block references; points at the canonical standard in the clone.
  • Docs site themed toward fairyfox.io — the JSDoc (docdash) doc-site now wears the fairyfox design system (dark-first warm palette, Fraunces/Inter/JetBrains, theme-color metas) and carries the required two-way links back to Fairy Fox: a Fairy Fox brand atop the sidebar, a Fairy Fox / Projects / Random AI Prompt breadcrumb, docdash menu back-links, and a footer to the main site's sections. New assets/docs-theme/{fairyfox-docs.css,fairyfox-docs.js}, wired via jsdoc.config.json (docdash.scripts/menu/meta); scripts/build-docs.mjs copies the theme assets into docs/jsdoc/ (docdash references but doesn't copy them). Verified visually across the home, a tutorial, and an API module page. See ../../reference/documentation.md.

Verification: npm run lint (0 errors), npm run smoke (OK), npm run docs (clean build).

Still open (reported to the owner, NOT done here — hub-side): the hub registry.yml lists this project as branch: dev (real default is master) and adopts_hub: true (now true-er, but the docs-site theme is a skinned-generator deviation, not a bespoke Jekyll shell). Those are corrections for the owner to apply in the junebug12851.github.io repo. The themed docs only go live after a master fast-forward + Pages deploy (master FF held for go-ahead this session).