<?xml version="1.0"?>
<rss version="2.0"><channel><title>Flarum Latest Topics</title><link>https://ernestdefoe.online/forums/forum/15-flarum/</link><description>Flarum Latest Topics</description><language>en</language><item><title>Page Builder &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/22-page-builder-support-and-discussion/</link><description><![CDATA[<h1>Page Builder for Flarum 2</h1><p>A premium drag‑and‑drop <strong>page builder + CMS</strong> for Flarum 2. Design custom pages</p><p>from blocks, run structured content types ("databases") like an articles</p><p>section or knowledge base, and edit it all visually — in the admin **or live on</p><p>the front end**. No code required.</p><p></p><hr><h2>Table of contents</h2><ul><li><p>Features</p></li><li><p>Requirements</p></li><li><p>Installation</p></li><li><p>Quick start</p></li><li><p>Pages &amp; the block designer</p></li><li><p>The live front‑end editor</p></li><li><p>Block reference</p></li><li><p>Hero banners</p></li><li><p>Content types (the CMS)</p></li><li><p>Comments on records</p></li><li><p>Promote a discussion to an article</p></li><li><p>SEO</p></li><li><p>Setting a custom homepage</p></li><li><p>Permissions</p></li><li><p>For developers: the block &amp; field APIs</p></li><li><p>License</p></li></ul><hr><h2>Features</h2><ul><li><p><strong>Visual page designer</strong> — build pages from a responsive 12‑column grid of</p><p>rows → columns → blocks, with <strong>drag‑and‑drop</strong> reordering, in the admin.</p></li><li><p><strong>Live WYSIWYG editor on the front end</strong> — admins get an <em>Edit layout</em> button</p><p>on any Page Builder page; drag blocks around and edit their settings while</p><p>seeing the real, rendered result.</p></li><li><p><strong>15 built‑in blocks</strong> — heroes, text/HTML/images/buttons, forum widgets</p><p>(recent &amp; featured discussions, online users, newest members, stats, tag</p><p>grid), content lists, and media embeds.</p></li><li><p><strong>Customizable hero banners</strong> — full‑width or split layouts; gradient, solid,</p><p>or uploaded/linked image backgrounds; custom text color; one or two buttons.</p></li><li><p><strong>Content types (CMS)</strong> — define your own kinds of content (articles,</p><p>downloads, a directory, a knowledge base) with custom fields, categories, and</p><p>per‑group permissions. Records get listing pages, detail pages, and comments.</p></li><li><p><strong>Promote a discussion to an article</strong> in one click.</p></li><li><p><strong>Built‑in SEO</strong> — server‑rendered titles, meta descriptions, and Open</p><p>Graph / Twitter cards for every page and record.</p></li><li><p><strong>Open block &amp; field APIs</strong> — other extensions can register their own blocks</p><p>and field types.</p></li></ul><hr><h2>Requirements</h2><ul><li><p>Flarum <code>^2.0</code></p></li><li><p>PHP 8.1+</p></li><li><p>Optional: <code>flarum/tags</code> — required only for the **Tag</p><p>Grid** block.</p></li></ul><hr><h2>Installation</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum migrate
php flarum cache:clear```

Then enable **Page Builder** under *Admin → Extensions*.

This is a proprietary, paid extension — see License.

---

## Quick start

1. Open **Admin → Extensions → Page Builder**.
2. Click **New page**, give it a title, and you're dropped into the designer.
3. **Add row → Add block**, pick a **Hero banner**, and edit its heading,

   background, and buttons.
4. Click **Save changes**, then **Preview**.
5. (Optional) Use the **Forum homepage** card to make your page the site's front

   page — see Setting a custom homepage.

![Page Builder admin: homepage, pages, and content types](https://raw.githubusercontent.com/ernestdefoe/page-builder/main/docs/screenshots/admin-pages.png)

---

## Pages &amp; the block designer

A **page** lives at `/p/{slug}` (or `/` when set as the homepage) and is built

from a layout tree:

```Page
└── Row            (full‑width / wide / narrow, padding, background)
    └── Column     (1–12 of a 12‑column grid)
        └── Block  (hero, text, widget, …)```

In the designer you can:

* **Add / delete / reorder rows**, set each row's width and padding, and give it

  a background color.
* **Add / delete / reorder columns** within a row and set each column's width

  (out of 12).
* **Add / delete / reorder blocks** within and across columns.
* **Edit every block's settings** inline (the form is generated from the block's

  schema).
* Set **per‑block visibility** — which device sizes (desktop / mobile) and which

  user groups can see it.

Everything reorders by **dragging the grip handle** (☰); drop zones appear

between items as you drag.

![The admin page designer](https://raw.githubusercontent.com/ernestdefoe/page-builder/main/docs/screenshots/designer.png)

---

## The live front‑end editor

Open any Page Builder page as an admin and click **Edit layout** (bottom‑right).

The page turns into a live editor where the **real blocks render as you work**:

* Drag rows, columns, and blocks to rearrange them.
* Click the **</code></pre><p><code><span class="ipsEmoji" title="">⚙</span> settings** icon on a block to edit it — changes update the live preview instantly (true WYSIWYG). * **Add block** / delete blocks per column. * Click **Save layout** to publish, or **Cancel** to discard. ![Live front‑end WYSIWYG editor](https://raw.githubusercontent.com/ernestdefoe/page-builder/main/docs/screenshots/live-editor.png) --- ## Block reference | Block | Category | What it does | |-------|----------|--------------| | **Hero banner** | content | Full‑width or split banner; gradient/solid/image background, heading, subheading, up to two buttons. See Hero banners. | | **Heading** | content | A styled heading (h1–h4), alignment. | | **Text** | content | A rich text paragraph block, alignment. | | **HTML** | content | Raw HTML, **sanitized on save** (scripts &amp; event handlers stripped). Authoring is admin‑only. Great for embeds and custom markup. | | **Image** | media | A single image (uploaded or by URL), optional rounded corners, alignment. | | **Button** | content | A call‑to‑action button (primary/secondary), link, alignment. | | **Divider** | layout | A horizontal rule with adjustable spacing. | | **Recent Discussions** | forum | The latest discussions, visibility‑filtered. | | **Featured Discussions** | forum | Hand‑picked discussions by ID, in your chosen order, with optional excerpts. | | **Online Users** | forum | Avatars of who's online now. | | **Newest Members** | forum | The most recently joined members, with join dates. | | **Forum Stats** | forum | Member / discussion / post / online counts. | | **Content list** | content | Embeds records from a content type (e.g. latest articles) as cards. | | **Tag Grid** | forum | Forum tags as clickable cards (requires `flarum/tags`). | | **Embed** | media | A responsive YouTube/Vimeo embed from a URL, with caption. | --- ## Hero banners The **Hero banner** block (and each content type's optional **listing hero**) is fully customizable: * **Layout** — *Full‑width background* (centered or left text) or *Split* (text panel beside an image panel). * **Background** — **Gradient** (start/end colors + angle), **Solid** color, or **Image** (upload or paste a URL, with an adjustable dark overlay). * **Text** — heading, subheading, and **text color**: light, dark, or a **custom color** to match your theme. * **Buttons** — a primary and an optional secondary button (e.g. "Browse articles" + "Browse forum"). * **Height** &amp; **alignment**. --- ## Content types (the CMS) Page Builder includes a full content‑management layer. A **content type** is your own kind of content — *Articles*, *Downloads*, a *Knowledge base*, a *Directory* — each with its own fields, categories, permissions, and URLs. ![Editing a content type](https://raw.githubusercontent.com/ernestdefoe/page-builder/main/docs/screenshots/content-type.png) **Create one** under *Page Builder → Content types → New content type*, then configure: * **Fields** — text, textarea, rich text, **markdown** (the full Flarum composer with uploads/mentions/emoji), **image** (upload or URL), number, date, boolean, select, multiselect, URL, email, color, rating, and relationship. Mark one as the **title**, and choose which appear in the list view. * **Categories** — optional taxonomy with a filter bar and badges on the listing. * **Permissions** — which groups can **view**, **submit**, and **manage** records. * **Listing hero** — an optional hero banner on the type's `/c/{type}` page. Each type gives you: * A **listing** at `/c/{type}` (cards, category filter, pagination). * A **record page** at `/c/{type}/{slug}`. * A **composer** at `/c/{type}/new` and `/c/{type}/{slug}/edit`. ![A content type's listing page with a full‑width hero](https://raw.githubusercontent.com/ernestdefoe/page-builder/main/docs/screenshots/listing-hero.png) --- ## Comments on records When enabled for a type, each published record gets a **comment thread** backed by a real Flarum discussion — so comments get mentions, reactions, notifications, and moderation for free. The thread is created lazily on first view and hidden from the normal discussion list. --- ## Promote a discussion to an article Turn any forum discussion into an article from its **controls dropdown → Promote to article** (admin only). The discussion's title becomes the article title and its first post becomes the body; the original discussion is then attached to the new article as its **comment thread** (and drops out of the forum listing). --- ## SEO Page Builder renders SEO tags **server‑side** (so crawlers and social cards see them without running JavaScript) for `/home`, `/p/{slug}`, `/c/{type}`, and `/c/{type}/{slug}`: * `&lt;title&gt;` and `&lt;meta name="description"&gt;` * **Open Graph** (`og:type`, `og:title`, `og:url`, `og:description`, `og:image`) * **Twitter** card tags * `article:published_time` for records, plus a canonical URL Record descriptions come from a summary/excerpt and `og:image` from the record's cover image. Pages use the **Meta description** field you set in the designer. The tags are authoritative and de‑duplicated, so they coexist cleanly with a dedicated SEO extension. --- ## Setting a custom homepage 1. In **Page Builder → Forum homepage**, choose the page to use as your front page. 2. Go to **Admin → Basics → Home Page** and select **“Home (Page Builder)”**. Your custom page now serves as the forum's landing route (`/`), Invision‑style. --- ## Permissions * **Pages &amp; the designer** (admin) — building pages and editing HTML blocks is admin‑only. * **Content types** — set per‑type **view / submit / manage** group permissions in the content‑type editor. * **Block visibility** — limit individual blocks to specific groups (enforced server‑side) and device sizes. --- ## For developers: the block &amp; field APIs Register a **block** from any extension: ```// extend.php (new Ernestdefoe\PageBuilder\Extend\PageBuilderBlock(MyBlock::class)),``` ```// forum JS app.pageBuilder.registerBlock('my-block', MyBlockComponent);``` `MyBlock` extends `Ernestdefoe\PageBuilder\Block\AbstractBlock`: declare `type()/name()/icon()/category()`, a `settingsSchema()` (the same schema language the editor renders), and a `resolve($settings, $actor)` returning data **scoped to the actor's visibility**. The matching JS component receives `{ settings, data }`. Register a custom **field type** for content types via `app.pageBuilderFields.register(type, InputComponent, DisplayComponent)`. --- ## License **Proprietary <span class="ipsEmoji">©</span> Ernest Defoe.** A premium paid extension — see [LICENSE](https://github.com/ernestdefoe/page-builder/blob/main/LICENSE) for terms. For licensing inquiries: ernestdefoe@gmail.com</code></p>]]></description><guid isPermaLink="false">22</guid><pubDate>Sun, 31 May 2026 20:42:06 +0000</pubDate></item><item><title>Connect for Flarum 2 &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/56-connect-for-flarum-2-support-and-discussion/</link><description><![CDATA[<h1>Connect for Flarum 2</h1><p><strong>Automation for your forum.</strong> Connect gives Flarum 2 outgoing webhooks, a</p><p>scoped REST API, and an in-app <em>if-this-then-that</em> Rules engine. Wire your</p><p>community up to <strong>Zapier, Make, IFTTT, n8n</strong> — or automate things right on the</p><p>forum with no external service at all.</p><p>Free and <strong>MIT-licensed</strong>.</p><p><a rel="external nofollow" href="https://flarum.org"><img src="https://img.shields.io/badge/Flarum-2.0%2B-orange" alt="Flarum" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="" href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="License" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://php.net"><img src="https://img.shields.io/badge/PHP-8.3%2B-777bb4" alt="PHP" class="ipsRichText__align--block" loading="lazy"></a></p><hr><h2>What it does</h2><p>Connect covers both directions of automation:</p><ul><li><p><strong>Out of your forum → anywhere.</strong> When a discussion is started, a reply is</p><p>posted, or a user registers, Connect fires a signed webhook to whatever URL</p><p>you (or a Zap) subscribed. Perfect for Zapier/Make/IFTTT/n8n triggers.</p></li><li><p><strong>Anywhere → into your forum.</strong> A scoped API key lets an external service</p><p>create discussions and replies <em>as a real user</em>, through Flarum's own API — so</p><p>every permission and validation rule still applies.</p></li><li><p><strong>Inside your forum.</strong> The built-in <strong>Rules</strong> engine runs trigger → conditions</p><p>→ actions entirely on your server. No third-party account, no per-task billing,</p><p>no data leaving the box.</p></li></ul><p><img src="https://raw.githubusercontent.com/ernestdefoe/connect/main/.github/screenshots/connect-admin.png" alt="The Connect admin page — automation rules, API keys, triggers and live subscriptions" class="ipsRichText__align--block" loading="lazy"></p><hr><h2>Set it all up without leaving your forum</h2><p>Connect embeds Zapier's official experience right in your admin panel. Browse</p><p>6,000+ apps, pick a recipe — <em>Share new discussions to a Facebook Page</em>, *Post to</p><p>Slack<em>, </em>Add members to Mailchimp* — and build or manage Zaps in place. No tab</p><p>switching, no developer knowledge required.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/connect/main/.github/screenshots/zapier-embed.png" alt="The in-admin Zapier experience — curated recipes plus the full Zap builder" class="ipsRichText__align--block" loading="lazy"></p><p>Paste your Zapier integration's <strong>Client ID</strong> once (Admin → Connect) and the full</p><p>experience appears, themed to match your forum. Prefer Make, n8n, or IFTTT?</p><p>They all work off the same REST API and webhooks.</p><hr><h2>Automation rules (no external service needed)</h2><p>Pick a <strong>trigger</strong>, add optional <strong>conditions</strong>, and choose one or more</p><p><strong>actions</strong>. Rules run on a queue, off the request path, so they never slow down</p><p>the person who triggered them.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/connect/main/.github/screenshots/rule-builder.png" alt="The rule builder — when a new discussion's title contains “help”, post a reply" class="ipsRichText__align--block" loading="lazy"></p><p><strong>Triggers</strong></p><p>| Event | Fires when |</p><p>| --- | --- |</p><p>| <code>discussion.created</code> | someone starts a new discussion |</p><p>| <code>post.created</code> | someone posts a reply |</p><p>| <code>user.registered</code> | a new member signs up |</p><p><strong>Conditions</strong> — match <strong>all</strong> or <strong>any</strong> of a list. Each condition compares a</p><p>payload field (e.g. <code>title</code>, <code>content</code>, <code>tagList</code>) using one of:</p><p><code>is</code>, <code>is not</code>, <code>contains</code>, <code>does not contain</code>, <code>starts with</code>, <code>is greater than</code>,</p><p><code>is less than</code>, <code>is empty</code>, <code>is not empty</code>, <code>matches (regex)</code>.</p><p><strong>Actions</strong></p><p>| Action | What it does |</p><p>| --- | --- |</p><p>| Post a reply | replies to the discussion the event is about |</p><p>| Add / remove a tag | requires <a rel="external nofollow" href="https://github.com/flarum/tags">flarum/tags</a> |</p><p>| Add / remove from a group | changes the involved user's groups |</p><p>| Call a webhook | POSTs the event payload to a URL you choose |</p><p>Actions are isolated — if one fails, the rest of the rule still runs — and each</p><p>rule tracks how many times it has run.</p><hr><h2>Connecting Zapier / Make / IFTTT / n8n</h2><ol><li><p>In <strong>Admin → Connect</strong>, create an API key. Give it a label (e.g. <em>Zapier</em>) and</p><p>the scopes it needs — <strong>Read</strong> for triggers, <strong>Write</strong> for actions.</p></li><li><p>Copy the <strong>token</strong> (<code>ck_…</code>) and <strong>secret</strong> (<code>cs_…</code>).</p></li><li><p>In your automation tool, add a webhook that authenticates with</p><p><code>Authorization: Bearer ck_…</code>.</p><ul><li><p>To <strong>receive</strong> forum events, subscribe your tool's catch-hook URL (Zapier</p><p>does this automatically via REST Hooks — see the API below).</p></li><li><p>To <strong>act</strong> on the forum, POST to the action endpoints.</p></li></ul></li></ol><p>Every outgoing delivery is <strong>HMAC-signed</strong> so you can verify it really came from</p><p>your forum:</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>

valid  ⇔  signature == 'sha256=' + hmac_sha256(rawRequestBody, keySecret)```

---

## REST API

All routes are under your forum's API root (`/api`). Authenticate with

`Authorization: Bearer ck_…`.

| Method | Endpoint | Purpose |

| --- | --- | --- |

| `GET` | `/connect/me` | Who this key acts as (auth test) |

| `POST` | `/connect/hooks` | Subscribe: `{ event, targetUrl }` → REST Hook, returns `{ id }` |

| `DELETE` | `/connect/hooks/{id}` | Unsubscribe |

| `GET` | `/connect/samples/{event}` | Recent real items shaped like the payload (Zap setup) |

| `POST` | `/connect/actions/discussions` | Create a discussion `{ title, content }` |

| `POST` | `/connect/actions/posts` | Reply to a discussion `{ discussionId, content }` |

A `410 Gone` from a subscribed target auto-prunes the subscription — so a Zap you

turn off cleans itself up.

### Example

```# What does this key act as?
curl https://your-forum.example/api/connect/me \
  -H "Authorization: Bearer ck_live_xxx"

# Create a discussion as the key's user
curl -X POST https://your-forum.example/api/connect/actions/discussions \
  -H "Authorization: Bearer ck_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"title":"Posted from Zapier","content":"Hello from an automation!"}'```

---

## Installation

```composer require ernestdefoe/connect```

Then enable **Connect** in **Admin → Extensions**. Make sure a queue worker is

running (`php flarum queue:work`) so webhooks and rule actions are delivered.

The tag actions light up automatically if [flarum/tags](https://github.com/flarum/tags) is installed; everything

else works on a stock forum.

## Minting a key from the CLI

```php flarum connect:key "My key" --scopes=read,write```

---

## Requirements

* Flarum `^2.0`
* PHP `^8.3`
* A running queue worker (recommended — webhooks and rule actions are queued)

## License

[MIT](https://github.com/ernestdefoe/connect/blob/main/LICENSE) <span class="ipsEmoji">©</span> Ernest Defoe</code></pre>]]></description><guid isPermaLink="false">56</guid><pubDate>Thu, 23 Jul 2026 23:55:19 +0000</pubDate></item><item><title>Importer &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/55-importer-support-and-discussion/</link><description><![CDATA[<h1>Importer / Converter for Flarum 2</h1><p>Migrate an existing forum into <strong>Flarum 2</strong> — from <strong>phpBB, vBulletin (3/4/5), XenForo, MyBB, SMF, Vanilla, NodeBB, Invision, Discourse</strong>, or <strong>Convoro</strong>. Everything is driven from the <strong>admin panel</strong>: pick a platform, connect to its database (or upload a dump), test it, then run the import in <strong>small batches with a live progress bar</strong> — so even a large forum won't time out.</p><p>Ported from the Convoro importer suite. Members keep their passwords where possible (bcrypt hashes are copied straight across; other formats are randomised so the member simply resets on first login). Post bodies are converted to Flarum's native rich-text format, so BBCode / HTML / Markdown comes across as real formatting — bold, italics, links, quotes, lists and code.</p><h2>Runs on shared hosting</h2><p>No queue worker and no SSH required. The import runs as a loop of <strong>small "step" requests straight from your browser</strong>, each processing one bounded batch and returning — so it can never hit a web timeout. Progress and the source→Flarum id-maps are persisted in the database, so if the tab is closed or the connection drops, reopen the page and it <strong>resumes exactly where it left off</strong>. If you <em>do</em> have a queue worker (e.g. <code>fof/redis</code>), the import is handed to it and runs fully in the background instead — either way it's safe.</p><h2>The admin area</h2><p>The whole tool lives on the extension's settings page.</p><h3>1. The wizard</h3><p>Pick a <strong>source platform</strong>, then either <strong>connect to a database</strong> (host, port, database name, username, password, and table prefix) or <strong>upload a database file</strong> (a <code>mysqldump</code> <code>.sql</code>/<code>.sql.gz</code>, or a SQLite file) for hosts that only hand you a dump. Nothing is written until you start.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/importer/main/screenshots/admin-1-initial.png" alt="Importer admin — connection wizard" class="ipsRichText__align--block" loading="lazy"></p><h3>2. Test the connection</h3><p><strong>Test connection</strong> validates the credentials, confirms it really is the platform you picked, then reports exactly what it found — here <strong>21 Users, 4 Categories, 30 Topics, 371 Posts</strong> — so you know it will pull the right data before committing. <strong>Start import</strong> only lights up once the test passes.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/importer/main/screenshots/admin-2-tested.png" alt="Importer admin — successful connection test with row counts" class="ipsRichText__align--block" loading="lazy"></p><h3>3. Watch it run</h3><p><strong>Start import</strong> kicks off the batched run and shows a <strong>live progress bar</strong> with the current phase and running totals — categories, members, topics and posts — updating as it goes.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/importer/main/screenshots/admin-3-progress.png" alt="Importer admin — live progress bar with running totals" class="ipsRichText__align--block" loading="lazy"></p><p>When it finishes you get a summary of everything imported, and can start another.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/importer/main/screenshots/admin-3-complete.png" alt="Importer admin — completed import summary" class="ipsRichText__align--block" loading="lazy"></p><h2>Supported sources</h2><p>| Platform | Notes |</p><p>|----------|-------|</p><p>| phpBB 3.x | BBCode posts; bcrypt passwords copied across |</p><p>| vBulletin 3 / 4 · vBulletin 5 / 6 | one option covers both — vB5's node schema is auto-detected |</p><p>| XenForo 1.x / 2.x | BBCode posts; XF2 bcrypt passwords copied |</p><p>| MyBB 1.8 · SMF 2.0 / 2.1 | BBCode posts |</p><p>| Vanilla · NodeBB | Markdown / mixed formats; NodeBB reads its Redis store (needs the <code>redis</code> PHP extension) |</p><p>| Invision Community (IP.Board) | HTML posts, quotes &amp; mentions cleaned up |</p><p>| Discourse | PostgreSQL source (needs <code>pdo_pgsql</code>) |</p><p>| Convoro | Convoro → Flarum; bcrypt passwords copied, so members keep their logins |</p><p>Categories are imported as <strong>tags</strong> (requires <code>flarum/tags</code>); if tags aren't installed, discussions and posts still import, just untagged.</p><h2>How it works</h2><ul><li><p><strong>Timeout-proof</strong> — the run is a resumable state machine; each request processes one small batch and returns, so memory stays flat and nothing runs long enough to time out. Works with or without a queue worker.</p></li><li><p><strong>Resumable</strong> — progress, cursors and the source→Flarum id-maps live in the database, so a run survives a closed tab, a reload, or a dropped connection.</p></li><li><p><strong>Faithful content</strong> — post bodies go source → HTML/Markdown → Flarum's formatter, landing in Flarum's native stored format so they render as proper rich text.</p></li><li><p><strong>Relations preserved</strong> — members, tags, discussions, first/last-post pointers, comment counts and participant counts are all rebuilt.</p></li></ul><h2>Requirements &amp; tips</h2><ul><li><p>Import into a <strong>fresh Flarum</strong> for the cleanest result.</p></li><li><p>A queue worker is <strong>optional</strong> — the import runs from the browser without one. If you have <code>fof/redis</code> + a worker, it runs in the background instead.</p></li><li><p>There's also a CLI for very large migrations or scripting:</p></li></ul><pre spellcheck="" class="ipsCode" data-language="bashphp"><code>
  --host=127.0.0.1 --database=my_old_forum --username=root --password=secret --prefix=phpbb_
# add --test to only check the connection and show counts```

## License

MIT <span class="ipsEmoji">©</span> ernestdefoe</code></pre>]]></description><guid isPermaLink="false">55</guid><pubDate>Wed, 08 Jul 2026 12:59:56 +0000</pubDate></item><item><title>Typesense Search &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/54-typesense-search-support-and-discussion/</link><description><![CDATA[<h1>Typesense Search for Flarum</h1><p>A free, drop-in <a rel="external nofollow" href="https://typesense.org">Typesense</a> search driver for <strong>Flarum 2</strong> —</p><p>fast, typo-tolerant full-text search across <strong>discussions, users and posts</strong> that anyone</p><p>can set up in a few minutes.</p><p>Flarum 2 shipped a pluggable search architecture; this extension implements a Typesense</p><p>driver for it. Text searches are answered by Typesense; everything else (filtering,</p><p>browsing, permissions) stays exactly as Flarum does it. You choose per resource which</p><p>searches Typesense answers.</p><h2>Why it's safe by design</h2><p>Typesense is <strong>only ever asked for candidate discussion IDs and their ranking</strong>. Which</p><p>results a given user may actually see is decided entirely by Flarum's own</p><p><code>whereVisibleTo</code> (including tag restrictions) — never by Typesense. The search server</p><p>holds no authorization logic, and the browser never talks to it. Your API key is stored</p><p>server-side and is never exposed to visitors.</p><h2>Requirements</h2><ul><li><p>Flarum <code>^2.0</code></p></li><li><p>A running Typesense server (self-hosted is a single binary or Docker container, or use</p><p>Typesense Cloud)</p></li></ul><h2>Install</h2><p><code>composer require ernestdefoe/typesense</code></p><h3>Run Typesense (self-hosted example)</h3><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
  -v typesense-data:/data typesense/typesense:27.1 \
  --data-dir /data --api-key='CHANGE_ME' --enable-cors```

## Set up

1. **Admin → Typesense Search.** Enter the host, port, protocol and API key, then **Save**.
2. Click **Test connection** to confirm Flarum can reach the server.
3. Click **Rebuild index** (or run `php flarum typesense:index`) to populate the index

   from your existing discussions.
4. Turn on **Use Typesense for discussion search** and save.

That's it — searches for discussions are now served by Typesense.

Search tabs that Typesense answers show a small **Powered by Typesense** badge in the

search modal, so you can see at a glance which searches are using the driver. Only that

on/off fact is sent to the browser — connection details and the API key stay on the server.

### Console

```php flarum typesense:index          # build / refresh the index
php flarum typesense:index --flush  # delete the index```

## How indexing works

* Each discussion is one Typesense document: its title plus the concatenated text of its

  visible comment posts.
* Creating, editing or deleting a discussion or post re-indexes the affected discussion

  automatically through Flarum's queued indexing pipeline.
* **Configure a real queue driver** (`redis`, `database`, …) in production so indexing and

  rebuilds run in the background rather than inline on a web request.

Several forums can share one Typesense server safely — collections are namespaced by a

prefix (set one, or it's derived from your forum URL).

## What's indexed

Everything Flarum can full-text search, each in its own namespaced collection:

* **Discussions** — title + the concatenated text of visible comment posts.
* **Users** — username and display name.
* **Posts** — individual comment post text (post-scoped search).

Each is toggled independently in the admin, so you can send discussion search to

Typesense while leaving users or posts on the database, or run all three through it.

(Groups and access tokens have no full-text search in Flarum, so they always stay on the

database driver.)

## License

[MIT](./LICENSE.md) <span class="ipsEmoji">©</span> Ernest Defoe</code></pre>]]></description><guid isPermaLink="false">54</guid><pubDate>Sun, 05 Jul 2026 21:42:35 +0000</pubDate></item><item><title>Hero Builder &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/49-hero-builder-support-and-discussion/</link><description><![CDATA[<h1>Hero Builder for Flarum</h1><p><strong>A fully customizable, animated hero banner for your Flarum 2 discussion list — designed live, per page and per tag.</strong></p><p><a rel="" href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://flarum.org"><img src="https://img.shields.io/badge/Flarum-2.0%2B-orange.svg" alt="Flarum 2.0+" class="ipsRichText__align--block" loading="lazy"></a></p><p>Give your community a polished, modern welcome. Hero Builder adds a configurable banner to the top of your discussion list — a title, subtitle, any Font Awesome icon, an animated gradient or a cover image, and optional live community stats. Set a different hero for the home page <strong>and for every tag</strong>, all from a live in-admin editor. No core files are touched.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/hero-builder/master/images/hero-banner.png" alt="The hero banner on a discussion list" class="ipsRichText__align--block" loading="lazy"></p><hr><h2>Features</h2><ul><li><p><strong>Title &amp; subtitle</strong> — say hello, set the tone.</p></li><li><p><strong>Any Font Awesome icon</strong> — type the class (<code>fas fa-meteor</code>, <code>fas fa-dragon</code>, <code>fab fa-discord</code> …), not a fixed preset list.</p></li><li><p><strong>Animated two-colour gradient</strong> <em>or</em> a <strong>cover image</strong> — pick a palette or drop in a full-bleed background.</p></li><li><p><strong>Optional live stats</strong> — surface real community numbers in the banner.</p></li><li><p><strong>Per-context heroes</strong> — a distinct hero for the <strong>home page</strong> and for <strong>each tag</strong>, so every corner of your forum gets its own welcome.</p></li><li><p><strong>No core files touched</strong> — ships as a clean, self-contained extension.</p></li></ul><hr><h2>Hero Studio — design it live</h2><p>Everything is configured in <strong>Admin → Extensions → Hero Builder</strong>, in the <strong>Hero Studio</strong>: pick a context (the home page or any tag), edit the fields, and watch the banner update in a live preview as you type. No saving-and-refreshing to see how it looks.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/hero-builder/master/images/hero-studio.png" alt="The Hero Studio live editor" class="ipsRichText__align--block" loading="lazy"></p><p>Tabs across the top let you switch between the home hero and a per-tag hero; the <strong>"Show the hero here"</strong> toggle lets you enable it only where you want it.</p><hr><h2>Installation</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum cache:clear```

Then open **Admin → Extensions → Hero Builder** and start designing.

### Requirements

* Flarum **2.0+**
* PHP 8.1+

---

## Building from source

```cd js
npm install
npm run build```

---

## License

[MIT](https://github.com/ernestdefoe/hero-builder/blob/master/LICENSE) <span class="ipsEmoji">©</span> Ernest Defoe. Free to use, fork and build on.</code></pre>]]></description><guid isPermaLink="false">49</guid><pubDate>Sun, 05 Jul 2026 21:32:32 +0000</pubDate></item><item><title>Favorite Team &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/17-favorite-team-support-and-discussion/</link><description><![CDATA[<h1>Favorite Team</h1><p><a rel="external nofollow" href="https://floxum.com/extension/ernestdefoe/favorite-team"><img src="https://floxum.com/extension/ernestdefoe/favorite-team/badge/name" alt="Floxum" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://floxum.com/extension/ernestdefoe/favorite-team"><img src="https://floxum.com/extension/ernestdefoe/favorite-team/badge/highest-version" alt="Version" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://floxum.com/extension/ernestdefoe/favorite-team"><img src="https://floxum.com/extension/ernestdefoe/favorite-team/badge/downloads" alt="Downloads" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://floxum.com/extension/ernestdefoe/favorite-team"><img src="https://floxum.com/extension/ernestdefoe/favorite-team/badge/review" alt="Review" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://floxum.com/extension/ernestdefoe/favorite-team"><img src="https://floxum.com/extension/ernestdefoe/favorite-team/badge/license" alt="License" class="ipsRichText__align--block" loading="lazy"></a></p><p>A <a rel="external nofollow" href="https://flarum.org">Flarum</a> 2.x extension that lets members pick a favorite</p><p>FBS (NCAA Division I-A) college-football team. The team's logo is displayed</p><p>under the member's avatar on posts and on their profile.</p><h2>Features</h2><ul><li><p><strong>Team picker</strong> — a searchable grid of all 136 FBS teams (logo + name) in the</p><p>member's account settings.</p></li><li><p><strong>Avatar badge</strong> — the chosen team's logo appears under the avatar on posts</p><p>(in the post's side column) and on the profile / user card.</p></li><li><p><strong>Require at registration (optional)</strong> — an admin toggle that forces new</p><p>members to pick a team before they can use the forum. It shows a</p><p>non-dismissible picker on the next page load for any logged-in member who</p><p>hasn't chosen yet (works with normal, social, and SSO sign-ups).</p></li><li><p><strong>No database migration</strong> — the choice is stored in the member's existing</p><p>preferences, so it loads with the user row (no extra query when rendering the</p><p>badge across a page of posts).</p></li><li><p><strong>Logos via the ESPN CDN</strong> — no images are bundled or hosted by the extension.</p></li></ul><h2>Installation</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum cache:clear```

Then enable **Favorite Team** in the admin panel under Extensions.

## Usage

### For members

Go to **Settings** → **Favorite Team** → **Choose your team**, search or scroll

the grid, pick a team, and save. The logo then shows under your avatar.

### For admins

Open the **Favorite Team** extension page in the admin panel and toggle

**Require members to pick a team** to force the choice at registration. It's off

by default.

## How it works

* The FBS team list is bundled as static reference data in

  `resources/teams.json` (id, name, abbreviation, color,

  and ESPN logo URL per team).
* The chosen team id is stored in the member's `preferences`

  (`ernestdefoe-favorite-team.team`).
* The core `UserResource` is extended with two fields:
  * `favoriteTeamId` — writable by the member themselves (or an admin), validated

    against the bundled team list.
  * `favoriteTeam` — a read-only resolved object (`id`, `name`, `logo`, …) used to

    render the badge; readable by everyone.
* `GET /api/fbs-teams` returns the full team list for the picker.

## API

| Method | Endpoint | Notes |

|---|---|---|

| `GET` | `/api/fbs-teams` | Full FBS team list (registered users). |

| `PATCH` | `/api/users/{id}` | Set `favoriteTeamId` (self or admin). |

## Configuration

| Admin setting | Default | Effect |

|---|---|---|

| Require members to pick a team | off | Blocks members without a team until they choose. |

## Notes

Team names and logos are the property of their respective institutions and are

served from ESPN's public logo CDN. This is an unofficial fan tool and is not

affiliated with or endorsed by the NCAA, ESPN, or any team.

## License

MIT

# Favorite Team

A [Flarum](https://flarum.org) 2.x extension that lets members pick a favorite

FBS (NCAA Division I-A) college-football team. The team's logo is displayed

under the member's avatar on posts and on their profile.

## Features

* **Team picker** — a searchable grid of all 136 FBS teams (logo + name) in the

  member's account settings.
* **Avatar badge** — the chosen team's logo appears under the avatar on posts

  (in the post's side column) and on the profile / user card.
* **Require at registration (optional)** — an admin toggle that forces new

  members to pick a team before they can use the forum. It shows a

  non-dismissible picker on the next page load for any logged-in member who

  hasn't chosen yet (works with normal, social, and SSO sign-ups).
* **No database migration** — the choice is stored in the member's existing

  preferences, so it loads with the user row (no extra query when rendering the

  badge across a page of posts).
* **Logos via the ESPN CDN** — no images are bundled or hosted by the extension.

## Installation

```composer require ernestdefoe/favorite-team
php flarum cache:clear```

Then enable **Favorite Team** in the admin panel under Extensions.

## Usage

### For members

Go to **Settings** → **Favorite Team** → **Choose your team**, search or scroll

the grid, pick a team, and save. The logo then shows under your avatar.

### For admins

Open the **Favorite Team** extension page in the admin panel and toggle

**Require members to pick a team** to force the choice at registration. It's off

by default.

## How it works

* The FBS team list is bundled as static reference data in

  `resources/teams.json` (id, name, abbreviation, color,

  and ESPN logo URL per team).
* The chosen team id is stored in the member's `preferences`

  (`ernestdefoe-favorite-team.team`).
* The core `UserResource` is extended with two fields:
  * `favoriteTeamId` — writable by the member themselves (or an admin), validated

    against the bundled team list.
  * `favoriteTeam` — a read-only resolved object (`id`, `name`, `logo`, …) used to

    render the badge; readable by everyone.
* `GET /api/fbs-teams` returns the full team list for the picker.

## API

| Method | Endpoint | Notes |

|---|---|---|

| `GET` | `/api/fbs-teams` | Full FBS team list (registered users). |

| `PATCH` | `/api/users/{id}` | Set `favoriteTeamId` (self or admin). |

## Configuration

| Admin setting | Default | Effect |

|---|---|---|

| Require members to pick a team | off | Blocks members without a team until they choose. |

## Notes

Team names and logos are the property of their respective institutions and are

served from ESPN's public logo CDN. This is an unofficial fan tool and is not

affiliated with or endorsed by the NCAA, ESPN, or any team.

## License

MIT</code></pre>]]></description><guid isPermaLink="false">17</guid><pubDate>Sat, 30 May 2026 19:02:43 +0000</pubDate></item><item><title>Social Groups for Flarum &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/9-social-groups-for-flarum-support-and-discussion/</link><description><![CDATA[<h1>Social Groups for Flarum</h1><p><img src="https://img.shields.io/badge/Flarum-2.x-3B2ADB?logo=flarum&amp;logoColor=white" alt="Flarum 2.x" class="ipsRichText__align--block" loading="lazy"></p><p><img src="https://img.shields.io/badge/PHP-8.3%2B-777BB4?logo=php&amp;logoColor=white" alt="PHP 8.3+" class="ipsRichText__align--block" loading="lazy"></p><p><img src="https://img.shields.io/badge/License-MIT-22c55e" alt="License MIT" class="ipsRichText__align--block" loading="lazy"></p><p>A full-featured social groups extension for Flarum 2. Members can create public or private groups, post to a Facebook-style feed, hold threaded discussions, share media, react to posts, run polls, and more — with optional real-time updates powered by <code>flarum/realtime</code>.</p><hr><h2>Features</h2><h3>Groups</h3><ul><li><p><strong>Public &amp; private groups</strong> — public groups are open to all; private groups require a join request or direct invitation.</p></li><li><p><strong>Group image &amp; banner upload</strong> — each group has its own avatar and cover banner image.</p></li><li><p><strong>Featured groups</strong> — administrators can pin groups to a featured row on the group directory.</p></li><li><p><strong>Primary group badge</strong> — members designate one group as their primary group; the badge is displayed on their Flarum profile.</p></li><li><p><strong>Group analytics dashboard</strong> — overview of member count, post activity, and growth over time (visible to group admins and moderators).</p></li><li><p><strong>RSS feed</strong> — each group exposes a per-group RSS 2.0 feed at <code>/groups/{slug}/feed.rss</code>.</p></li></ul><h3>Feed</h3><ul><li><p>Facebook-style post cards with full Flarum BBCode/Markdown rendering.</p></li><li><p><strong>Emoji reactions</strong> — six reaction types: <span class="ipsEmoji" title="">👍</span> Like, <span class="ipsEmoji" title="">❤️</span> Love, <span class="ipsEmoji" title="">😂</span> Haha, <span class="ipsEmoji" title="">😮</span> Wow, <span class="ipsEmoji" title="">😢</span> Sad, <span class="ipsEmoji" title="">😡</span> Angry; one reaction per user, toggleable.</p></li><li><p><strong>Polls</strong> — create polls directly from the post composer; members vote inline with live percentage bars.</p></li><li><p><strong>Link previews</strong> — URLs are automatically expanded into rich Open Graph preview cards (title, description, thumbnail).</p></li><li><p><strong>Media attachments</strong> — attach images and files to posts via <code>fof/upload</code> (optional).</p></li><li><p><strong>Pin posts</strong> — group admins can pin discussions to the top of the feed.</p></li><li><p><strong>Post search</strong> — debounced search bar filters discussions by title or content in real time.</p></li><li><p><strong>Post sharing</strong> — share any discussion into another group you belong to, with an optional comment; shared posts render a quoted card.</p></li></ul><h3>Discussions</h3><ul><li><p>Threaded discussion view at <code>/groups/{slug}/d/{discussionId}</code> with nested comment replies.</p></li><li><p><strong>Pin discussions</strong> to the top of the discussion list.</p></li><li><p><strong>Share discussions</strong> to the group feed.</p></li></ul><h3>Media Gallery</h3><ul><li><p>Dedicated "Media" tab on each group page aggregating all images from posts and discussions into a responsive thumbnail grid with lightbox.</p></li></ul><h3>Member Management</h3><ul><li><p><strong>Join requests</strong> — group admins approve or reject membership requests; direct invitations bypass the queue.</p></li><li><p><strong>Promote / demote</strong> — elevate a member to group admin or step them back down.</p></li><li><p><strong>Kick</strong> — remove a member from the group.</p></li><li><p><strong>Member badges on profiles</strong> — group membership chips appear on Flarum user profile cards forum-wide.</p></li></ul><h3>Notifications</h3><ul><li><p>Alert when a new post is created in a group the user participates in.</p></li><li><p>Alert when someone replies directly to a user's post.</p></li></ul><h3>Real-time (optional — requires <code>flarum/realtime</code>)</h3><p>See the flarum/realtime Integration section below.</p><hr><h2>Requirements</h2><p>| Dependency | Version | Required |</p><p>|---|---|---|</p><p>| Flarum | 2.x | Yes |</p><p>| PHP | 8.3+ | Yes |</p><p>| <code>flarum/realtime</code> | any | No — graceful no-op if absent |</p><p>| <code>fof/upload</code> | ^2.0 | No — required for file/image attachments in posts |</p><hr><h2>Installation</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum migrate
php flarum cache:clear```

Then go to **Admin → Extensions** and enable **Social Groups**.

**After every update**, run the migrate and cache-clear commands to apply any new database migrations:

```php flarum migrate &amp;&amp; php flarum cache:clear```

---

## Configuration

### Admin panel settings

Navigate to **Admin → Extensions → Social Groups**:

| Setting | Options | Default |

|---|---|---|

| **Who can create groups** | `member` — any registered user; `admin` — forum administrators only | `member` |

### Group privacy

Group creators choose privacy at creation time:

| Type | Behaviour |

|---|---|

| **Public** | Anyone can view the feed, discussions, and gallery. Joining is instant. |

| **Private** | Content is hidden from non-members. New members must submit a join request (approved by a group admin) or be invited directly. |

---

## flarum/realtime Integration

The real-time features are entirely **optional**. If `flarum/realtime` is not installed the extension works normally — the typing endpoint silently returns `204` and the post-broadcast listener exits immediately without any error or warning.

When `flarum/realtime` **is** installed and running:

* **Live post injection** — after a member submits a reply in a group discussion thread, all other members viewing that thread see the new post card appear instantly via the `sg-post-created` WebSocket event. No page refresh is needed.
* **Typing indicator** — while a member is composing a reply, an animated "Jane is typing…" indicator with bouncing dots is broadcast via the `sg-typing` event and displayed above the reply box for all other members viewing the same thread. The indicator disappears automatically when the member stops typing or submits their post.
* **Deduplication** — the client compares each incoming post's ID against already-rendered posts to prevent duplicates when both the HTTP response and the WebSocket push arrive for the same post.
* **No extra configuration** — the extension uses the existing public Pusher/Soketi channel that `flarum/realtime` sets up. Nothing additional needs to be configured.

---

## Updating

```composer update ernestdefoe/social-groups
php flarum migrate
php flarum cache:clear```

---

## License

Released under the [MIT License](https://github.com/ernestdefoe/social-groups/blob/main/LICENSE). <span class="ipsEmoji">©</span> Ernestdefoe

&lt;https://ernestdefoe.online/extension/ernestdefoe/social-groups&gt;</code></pre>]]></description><guid isPermaLink="false">9</guid><pubDate>Sun, 17 May 2026 17:14:18 +0000</pubDate></item><item><title>OnAir+ &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/39-onair-support-and-discussion/</link><description><![CDATA[<h1>OnAir+ — Live Streaming for Flarum 2</h1><p><a rel="" href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT" class="ipsRichText__align--block" loading="lazy"></a></p><p>Bring live video into your community. Members go live from <strong>YouTube</strong> or <strong>Twitch</strong>,</p><p>and a <strong>LIVE NOW</strong> badge follows their avatar everywhere it appears — posts, the</p><p>discussion list, mentions, the header, the sidebar.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/onair/main/screenshots/onair-live-badge.png" alt="OnAir — the LIVE badge follows a streamer's avatar everywhere, with a Live Now sidebar widget" class="ipsRichText__align--block" loading="lazy"></p><p><strong>Free / MIT.</strong> The optional premium add-on <strong>OnAir+</strong></p><p>turns your forum into the whole platform — a built-in RTMP server (stream straight in</p><p>from OBS), in‑forum HLS playback, multistream, VOD, live chat, go‑live notifications and</p><p>scheduled streams. See the comparison below.</p><h2>Features</h2><ul><li><p><span class="ipsEmoji" title="">🔴</span> <strong>LIVE badge on every avatar</strong> — one <code>Avatar</code> override lights a streamer up everywhere.</p></li><li><p><span class="ipsEmoji" title="">▶️</span> <strong>YouTube + Twitch embed viewer</strong> — paste a channel/video URL and go live.</p></li><li><p><span class="ipsEmoji" title="">📡</span> <strong>Presence with graceful fallback</strong> — uses <code>flarum/realtime</code> for instant badge</p><p>updates when installed, transparently falls back to lightweight polling when it isn't.</p></li><li><p><span class="ipsEmoji" title="">🟥</span> <strong>Live Now widget + a</strong> <code>/onair</code> directory — see who's streaming at a glance.</p></li><li><p><span class="ipsEmoji" title="">🔐</span> <strong>Permissions + admin settings</strong> — who can go live, default provider, poll interval.</p></li><li><p><span class="ipsEmoji" title="">⏱️</span> <strong>Stale‑stream reaper</strong> — auto‑ends streams left running.</p></li></ul><h3>The Live directory</h3><p><img src="https://raw.githubusercontent.com/ernestdefoe/onair/main/screenshots/onair-directory.png" alt="The /onair live directory listing everyone currently streaming" class="ipsRichText__align--block" loading="lazy"></p><h2>OnAir vs OnAir+</h2><p>OnAir (this extension) is free and complete on its own for YouTube/Twitch streamers.</p><p><strong>OnAir+</strong> is a paid add‑on for communities that want to host streaming themselves.</p><p>| | <strong>OnAir</strong> (free) | <strong>OnAir+</strong> |</p><p>|---|:---:|:---:|</p><p>| LIVE badge on avatar, everywhere | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| Live Now widget + <code>/onair</code> directory | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| YouTube embed viewer | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| Twitch embed viewer | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| Realtime presence + polling fallback | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| Permissions + admin settings | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| Auto‑end stale streams | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Built‑in RTMP server → in‑forum HLS</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Stream keys + creator studio</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Multistream / restream to YouTube + Twitch</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>VOD recordings</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Live chat overlay</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Go‑live notifications + follow a streamer</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Scheduled streams + reminders</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Concurrent viewer counts</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><h3>OnAir+ — stream straight into the forum</h3><p>Members broadcast from OBS to your own server; viewers watch an <code>hls.js</code> player inline,</p><p>with live chat beside it.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/onair/main/screenshots/onairplus-live-stream.png" alt="OnAir+ playing a live RTMP→HLS stream in the forum with the live chat panel" class="ipsRichText__align--block" loading="lazy"></p><h3>OnAir+ — creator studio</h3><p>Each streamer gets an ingest URL, a secret stream key, multistream targets, and a one‑click</p><p>key reset.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/onair/main/screenshots/onairplus-studio.png" alt="OnAir+ streaming studio showing the ingest server, masked stream key and playback URL" class="ipsRichText__align--block" loading="lazy"></p><h2>Install</h2><p><code>composer require ernestdefoe/onair</code></p><p>Then enable <strong>OnAir</strong> in the admin panel. Optionally install <code>flarum/realtime</code> for</p><p>instant (push) LIVE badges — OnAir detects it automatically. For self‑hosted streaming,</p><p>add <strong>OnAir+</strong> (<code>composer require ernestdefoe/onair-pro</code>).</p><h2>Development</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
npm install
npm run build      # or: npm run dev  (watch)```

A no‑backend concept render of the whole product lives in `preview/index.html`.

## Architecture notes

* **LIVE badge:** overrides the shared `Avatar` component (main‑bundle, safe to extend at

  init) and reads a serializer‑supplied `user.isLive()`.
* **Presence transport:** `app.onair.presence` picks `RealtimeTransport` when

  `flarum/realtime` is detected, else `PollingTransport`; both expose the same API.
* **Providers:** `app.onair.providers` (JS) + the `StreamProvider` interface (PHP) are the

  extension points **OnAir+** plugs its RTMP/HLS provider into.

## License

MIT <span class="ipsEmoji">©</span> Ernestdefoe</code></pre>]]></description><guid isPermaLink="false">39</guid><pubDate>Sun, 07 Jun 2026 19:40:37 +0000</pubDate></item><item><title>Projects &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/45-projects-support-and-discussion/</link><description><![CDATA[<h1>Projects</h1><p>A flexible <strong>user projects</strong> extension for <strong>Flarum 2</strong> — a showcase page for creator communities. Members publish "projects" (books, games, apps, art, mods, anything) as cards on a dedicated page, with rich, admin-configurable metadata.</p><p>Inspired by <a rel="external nofollow" href="https://discuss.flarum.org/d/39400-user-projects-extension-for-creator-communities">this community request</a>. Free and MIT-licensed.</p><h2>Features</h2><ul><li><p><strong>Project cards</strong> with an optional cover image, author, categories, key parameters, a short description and link buttons — on a dedicated <code>/projects</code> page.</p></li><li><p><strong>Search &amp; filters</strong> — full-text search, category filter and sort (recent / most-liked / A–Z), plus an <strong>Add project</strong> button.</p></li><li><p><strong>Admin-defined categories</strong> with an icon and accent colour. A project's <em>main</em> category becomes a badge shown next to the author's name across the forum.</p></li><li><p><strong>Custom parameters</strong> — define your own typed fields (text, paragraph, number, date, URL, select, yes/no) such as <em>Genre</em>, <em>Age rating</em> or <em>Release date</em>. Choose which show on the card.</p></li><li><p><strong>Flexible link/button system</strong> — define button slots, optionally <strong>restricted to specific domains</strong> (e.g. only YouTube links), with default or custom labels. Example for a book: <em>Read Excerpt</em>, <em>Buy</em>, <em>Discuss on Forum</em>.</p></li><li><p><strong>Optional moderation</strong> — projects can publish instantly or wait for approval, controlled per-group by the <code>Publish without moderation</code> permission.</p></li><li><p><strong>Detail page</strong> with forum-formatted content, all parameters and link buttons; link a forum discussion for comments.</p></li><li><p><strong>Built-in likes</strong> on every project.</p></li><li><p><strong>Profile integration</strong> — a <strong>Projects</strong> tab on each member's profile, plus a featured-project badge (their main category's icon, with the project name on hover) next to their username everywhere.</p></li><li><p><strong>FoF Badges integration</strong> <em>(optional)</em> — award a badge when a member's project is first published.</p></li></ul><h2>Screenshots</h2><p>| Browse page | Project detail |</p><p>| --- | --- |</p><p>| <img src="https://raw.githubusercontent.com/ernestdefoe/projects/main/screenshots/projects-page.png" alt="Projects browse page" class="ipsRichText__align--block" loading="lazy"> | <img src="https://raw.githubusercontent.com/ernestdefoe/projects/main/screenshots/project-detail.png" alt="Project detail page" class="ipsRichText__align--block" loading="lazy"> |</p><p>| Submission form | Admin configuration |</p><p>| --- | --- |</p><p>| <img src="https://raw.githubusercontent.com/ernestdefoe/projects/main/screenshots/submit-form.png" alt="Submit project form" class="ipsRichText__align--block" loading="lazy"> | <img src="https://raw.githubusercontent.com/ernestdefoe/projects/main/screenshots/admin.png" alt="Admin: categories, fields &amp; buttons" class="ipsRichText__align--block" loading="lazy"> |</p><h2>Permissions</h2><p>| Permission | Default |</p><p>| --- | --- |</p><p>| Create projects | Members |</p><p>| Publish without moderation | — (admins/mods always can) |</p><p>| Moderate projects | Moderators |</p><h2>Installation</h2><pre spellcheck="" class="ipsCode" data-language="composer"><code>
php flarum migrate
php flarum cache:clear```

Then open **Admin → Projects** to add categories, custom parameters and button slots.

## License

[MIT](https://github.com/ernestdefoe/projects/blob/main/LICENSE)</code></pre>]]></description><guid isPermaLink="false">45</guid><pubDate>Sun, 28 Jun 2026 18:38:04 +0000</pubDate></item><item><title>Respawn &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/12-respawn-support-and-discussion/</link><description><![CDATA[<h1>Respawn</h1><p>A gaming theme for <strong>Flarum 2</strong>: chamfered surfaces, neon accents, mono typography, hex-clipped avatars, hero with blinking cursor, level/XP sidebar widget, and a stats footer.</p><hr><h2>Features</h2><ul><li><p><strong>Dark + Light mode</strong> — admin-configurable default, per-user toggle in the header (☾ / <span class="ipsEmoji" title="">☀</span>)</p></li><li><p><strong>Branded hero</strong> — replaces the default <code>IndexPage</code> hero with a panel showing an eyebrow line, big mono headline ("Welcome to {forum}"), tagline, and an optional row of tag-shortcut chips</p></li><li><p><strong>Server-status footer</strong> — four chamfered stat cards (Posts · Discussions · Members · Online Now) rendered at the bottom of the index page, cached server-side at 60s</p></li><li><p><strong>Player Card</strong> — sidebar widget for the logged-in user with hex avatar, derived <code>LVL N · {posts} POSTS</code>, and a cyan→magenta XP bar</p></li><li><p><strong>Rarity Legend</strong> — sidebar panel mapping the four tag-color tiers (Legendary / Epic / Rare / Common) so newcomers learn the vocabulary</p></li><li><p><strong>Post styling</strong> — chamfered post cards, mono usernames in cyan, post-number pills, accent-bordered blockquotes, mono code blocks</p></li><li><p><strong>Composer + Scrubber</strong> — restyled to match the theme</p></li></ul><p>The theme is a pure CSS/LESS skin layered on top of stock Flarum — no Mithril components replaced or routes added beyond the small components above. Anything that uses Flarum's CSS variables (<code>--primary-color</code>, <code>--secondary-color</code>, etc.) is remapped, so most extensions skin for free.</p><hr><h2>Requirements</h2><ul><li><p>Flarum 2.x</p></li><li><p>PHP 8.3+</p></li></ul><hr><h2>Installation</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum cache:clear```

Then enable **Respawn** in **Admin → Extensions**.

---

## Configuration

All settings are in **Admin → Extensions → Respawn**.

| Setting | Description | Default |

|---|---|---|

| **Theme Mode** | Default colour mode for new visitors (`Dark` or `Light`). Users can toggle with the moon/sun button in the header. | `Dark` |

| **Hero Tagline** | Subtitle shown under the welcome headline. Leave blank to hide. | `Drop in, level up, and join the discussion.` |

| **Hero Eyebrow** | Small accent line above the headline. | `▸ Player Connected` |

| **Hero Tag Chips** | Comma-separated list of tag slugs to feature as quick-jump chips (e.g. `halo, elden-ring, deals`). Leave blank to hide. | *(blank)* |

The hero headline reads from Flarum's standard **Forum Title** setting (Admin → Basics).

---

## How the stats are computed

`ForumStatistics` queries the `posts`, `discussions`, `users`, and `users.last_seen_at` tables and caches each count for 60 seconds. The "Online Now" tile uses a 5-minute activity window matching Flarum's stock indicator. Any DB error renders the affected tile as `—` rather than a misleading `0`.

---

## Player Card level formula

Currently: `level = floor(posts / 100) + 1`, progress to next level = `posts % 100`.

It's a deliberately simple linear ramp. If you want a non-linear curve (exponential, custom thresholds, Bronze/Silver/Gold ranks instead of a number), open an issue.

---

## Customising

The theme exposes its tokens as CSS variables on `:root` (and `[data-respawn="light"]`), so an extension or custom CSS can override any of them without touching Respawn itself:

```:root {
  --r-accent:  #50ff8a;    /* lime instead of cyan */
  --r-magenta: #ff6b35;    /* orange instead of magenta */
}```

Every component reads through these variables.

---

## Support

Questions, bug reports, and feature requests:

* **Support forum:** https://ernestdefoe.online
* **Issues:** https://github.com/ernestdefoe/respawn/issues

---

## License

Respawn is released under the [MIT License](https://github.com/ernestdefoe/respawn/blob/main/LICENSE).

Copyright <span class="ipsEmoji">©</span> ernestdefoe.</code></pre>]]></description><guid isPermaLink="false">12</guid><pubDate>Wed, 20 May 2026 04:28:41 +0000</pubDate></item><item><title>Bespoke &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/23-bespoke-support-and-discussion/</link><description><![CDATA[<h1>Bespoke — Custom Theme &amp; Live Builder for Flarum 2</h1><p><a rel="external nofollow" href="https://floxum.com/extension/ernestdefoe/bespoke"><img src="https://floxum.com/extension/ernestdefoe/bespoke/badge/name" alt="Floxum" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://floxum.com/extension/ernestdefoe/bespoke"><img src="https://floxum.com/extension/ernestdefoe/bespoke/badge/highest-version" alt="Version" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://floxum.com/extension/ernestdefoe/bespoke"><img src="https://floxum.com/extension/ernestdefoe/bespoke/badge/downloads" alt="Downloads" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://floxum.com/extension/ernestdefoe/bespoke"><img src="https://floxum.com/extension/ernestdefoe/bespoke/badge/review" alt="Review" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://floxum.com/extension/ernestdefoe/bespoke"><img src="https://floxum.com/extension/ernestdefoe/bespoke/badge/license" alt="License" class="ipsRichText__align--block" loading="lazy"></a></p><p><strong>Design your whole forum on the live page — colours, fonts, layout, widgets, chrome — and publish when it's perfect. No code, no rebuilds, no guesswork.</strong></p><p>Bespoke is a premium theme <strong>and</strong> an in-context visual theme builder for Flarum 2, in the spirit of Invision Community's Theme Designer. Open the overlay editor right on your forum, change anything, watch it repaint instantly, and hit <strong>Publish</strong> when you're happy. Visitors only ever see the published result.</p><p></p><hr><h2>Table of contents</h2><ul><li><p>Why Bespoke</p></li><li><p>Feature tour</p><ul><li><p>The live editor</p></li><li><p>Palette &amp; accessibility</p></li><li><p>Typography (any Google Font)</p></li><li><p>Shape &amp; depth</p></li><li><p>Layout modes — Feed / Grid / Category</p></li><li><p>Hero</p></li><li><p>Effects — header, dark mode, glass, tag colouring</p></li><li><p>Site chrome — announcement bar &amp; footer</p></li><li><p>Widgets</p></li><li><p>Inspector</p></li><li><p>Presets, import &amp; export</p></li></ul></li><li><p>How it works</p></li><li><p>Installation</p></li><li><p>Using the editor</p></li><li><p>Permissions</p></li><li><p>Internationalisation</p></li><li><p>Performance &amp; security</p></li><li><p>Requirements &amp; compatibility</p></li><li><p>FAQ</p></li><li><p>Pricing</p></li><li><p>Support</p></li><li><p>License</p></li></ul><hr><h2>Why Bespoke</h2><p>Most Flarum theming means editing LESS, redeploying, and refreshing to see what you got. Bespoke replaces that loop with a <strong>live, in-context editor</strong>:</p><ul><li><p><strong>Instant</strong> — colour, font, radius, spacing and effect changes repaint with zero server round-trips.</p></li><li><p><strong>Safe</strong> — everything you change is a private <strong>draft</strong> until you <strong>Publish</strong>; one click reverts.</p></li><li><p><strong>Deep</strong> — it's a complete theme in itself (three discussion-list layouts, hero, posts, avatars, header variants), not just a colour picker.</p></li><li><p><strong>No code</strong> — but power users still get a Custom CSS escape hatch.</p></li></ul><hr><h2>Feature tour</h2><h3>The live editor</h3><p>A floating <strong>✦ Edit theme</strong> launcher appears for admins. It opens a docked overlay with tabs for every part of the theme; the forum stays fully interactive behind it so you always edit in real context. A light/dark preview switch, <strong>Save draft</strong>, and <strong>Publish</strong> sit in the footer.</p><p></p><h3>Palette &amp; accessibility</h3><p>Set every colour role — <strong>brand, accent, background, surface, text, muted, border</strong> — with independent <strong>light and dark</strong> values. Don't want to hand-pick seven colours? <strong>Generate harmony from Brand</strong> derives a balanced palette from one hue.</p><p>A built-in <strong>WCAG contrast checker</strong> grades the key text/background pairings live (AA / AAA / fail) so your theme stays readable as you go.</p><h3>Typography (any Google Font)</h3><p>Pick <strong>any</strong> Google Font by name — not a short curated list, the whole library — for headings and body independently, plus base size, modular type scale, and line-height. System and already-loaded fonts work too. Font links are injected server-side so there's no flash of the wrong typeface.</p><p></p><h3>Shape &amp; depth</h3><p>Corner radius, border width, elevation/shadow depth, button styles (solid / soft / outline / ghost), <strong>post styles</strong> (boxed / flat / bubble), and <strong>avatar shapes</strong> (circle / rounded / square / hexagon).</p><h3>Layout modes — Feed / Grid / Category</h3><p>The discussion list ships in three first-class layouts, switchable live:</p><p>| Mode | Look |</p><p>|---|---|</p><p>| <strong>Feed</strong> | Comfortable, separated cards — the refined default. |</p><p>| <strong>Grid</strong> | Magazine cards with a cover image (pulled from the first post), excerpt, tag pills, and a participant/reply footer. Configurable columns or auto-fit. |</p><p>| <strong>Category</strong> | A classic forum <strong>category index built from your tags</strong>, inspired by fof/categories — parent tags become sections, child tags become rows with icons, descriptions and counts. |</p><p></p><p></p><h3>Hero</h3><p>Full control of the welcome hero: height, contained vs. full-bleed width, a brand→accent gradient or a background image, custom text colours, and an <strong>admin-locked (non-dismissible)</strong> option so the hero always shows.</p><h3>Effects — header, dark mode, glass, tag colouring</h3><p>The <strong>Effects</strong> tab is where Bespoke earns its keep:</p><ul><li><p><strong>Header style</strong> — solid, transparent, or gradient; optional <strong>centred logo</strong>; sticky on/off.</p></li><li><p><strong>Visitor dark-mode toggle</strong> — adds a sun/moon switch to the header so each visitor picks their own scheme (remembered locally, applied before paint — no flash).</p></li><li><p><strong>Glassmorphism</strong> — frosted, translucent surfaces; pairs beautifully with a site background image.</p></li><li><p><strong>Subtle animations</strong> — tasteful hover/entrance motion, toggleable.</p></li><li><p><strong>Colour UI by active tag</strong> — a built-in <strong>ramon/colored</strong> replacement: on a tag page the <strong>hero</strong> adopts that tag's colour (with automatically-contrasting text), and the brand accent follows too.</p></li><li><p><strong>Card tag accent</strong> — give each discussion card a left bar or full border in <strong>its own</strong> primary-tag colour, so a mixed list reads as a colour-coded index.</p></li></ul><p></p><h3>Site chrome — announcement bar &amp; footer</h3><ul><li><p><strong>Announcement bar</strong> — a dismissible, optionally-linked banner across the top of every page.</p></li><li><p><strong>Custom footer</strong> — your own links, social icons (X, Discord, GitHub, YouTube, Facebook, Instagram), and copyright/text — no second extension required.</p></li></ul><p></p><h3>Widgets</h3><p>Drag widgets from the tray into any zone — <strong>above the list, sidebar, below the list, header, hero, or footer</strong> — then reorder them by their handle. Click a placed widget to edit its settings in the inspector.</p><p>| Widget | What it shows |</p><p>|---|---|</p><p>| <strong>Hero banner</strong> | Heading, subheading, CTA, background image. |</p><p>| <strong>Community stats</strong> | Discussions / posts / members / online counts. |</p><p>| <strong>Online users</strong> | Avatars of who's online now. |</p><p>| <strong>Top Contributors</strong> | Ranked by posts, likes received, or discussions, over week / month / all-time. |</p><p>| <strong>Newest Members</strong> | Most-recent sign-ups, as a list with join dates or an avatar grid. |</p><p>| <strong>Trending threads</strong> | Most-active discussions over 24h / 48h / 7d. |</p><p>| <strong>Call to action</strong> | Heading, body, button + link. |</p><p>| <strong>Markdown / HTML</strong> | Free-form content block. |</p><p>| <strong>Tag cloud</strong> | Popular tags. |</p><p>| <strong>Articles</strong> | From <a rel="external nofollow" href="https://github.com/ernestdefoe">Page Builder</a>, shown automatically when that extension is installed. |</p><p>All data-driven widgets share <strong>one</strong> cached request per page, so a widget-heavy sidebar stays cheap.</p><p></p><h3>Inspector</h3><p>Toggle <strong>Inspect</strong> (⊹) and hover any element on the page — Bespoke highlights it and labels it; click to jump straight to the controls that style it.</p><p></p><h3>Presets, import &amp; export</h3><p>Start from curated themes (Aurora, Carbon, Sunrise, Newsprint, Terminal, Grape), then <strong>export</strong> your finished theme as a portable <code>.bespoke.json</code> and <strong>import</strong> it on another Bespoke site — perfect for moving a look between staging and production, or shipping a house style across forums.</p><hr><h2>How it works</h2><p>Bespoke splits styling into two layers so editing feels instant but still reaches deep into Flarum:</p><p>| Layer | Carries | Mechanism | When |</p><p>|---|---|---|---|</p><p>| <strong>Instant</strong> | colours, fonts, radius, spacing, shadows, effects, layout switches | CSS custom properties in <code>&lt;style id="bespoke-vars"&gt;</code> + <code>data-bespoke-*</code> attributes on <code>&lt;html&gt;</code> | every page load; mutated client-side in the editor for zero-latency preview |</p><p>| <strong>Structural</strong> | the premium base theme, layout modes, component styling | compiled LESS (<code>less/forum.less</code>) | at build/compile time |</p><p>The theme is stored as a single JSON <strong>document</strong> (tokens + layout + zones + custom CSS + chrome). The editor edits an in-memory copy and applies it live; <strong>Save draft</strong> persists it for admins only; <strong>Publish</strong> promotes it to what every visitor sees. Because the instant layer is server-injected, the forum is themed <em>before</em> JavaScript runs — there's no flash of an unstyled or default theme.</p><hr><h2>Installation</h2><p><code>composer require ernestdefoe/bespoke</code></p><p>Then enable <strong>Bespoke</strong> in <strong>Admin → Extensions</strong>, open your forum, and click <strong>✦ Edit theme</strong> (bottom-right).</p><p>To update:</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum cache:clear```

---

## Using the editor

1. Click **✦ Edit theme**. The overlay docks to the side; your forum stays live behind it.
2. Work through the tabs — **Palette, Type, Shape, Layout, Hero, Discussion, Effects, Site, Widgets, Presets**. Every change previews instantly.
3. Use the footer **◑** switch to preview light vs. dark.
4. **Save draft** to keep working privately, or **Publish** to go live for everyone.
5. Use **Inspect (⊹)** any time to jump from an on-page element to its controls.

---

## Permissions

The editor and the theme save/publish API are gated on the `bespoke.edit` ability, which is granted to **administrators**. Visitors and regular members never load the editor and cannot write theme data or custom CSS.

---

## Internationalisation

Every user-facing string is translatable via standard Flarum locale files (`resources/locale/en.yml`) — tab names, control labels, widget names, hints, and messages. Translations are welcome.

---

## Performance &amp; security

* **One request for widgets** — all data widgets share a single, 60-second-cached `widget-data` call per page.
* **No render flash** — colours/fonts are injected server-side before JS.
* **Visibility-aware** — the Trending widget is scoped to guest-visible discussions, so its shared cache can never leak titles of private or tag-gated threads.
* **Admin-only writes** — theme save/publish (including Custom CSS) require `bespoke.edit`; injected custom CSS is additionally sanitised against tag-breakout as defence-in-depth.

---

## Requirements &amp; compatibility

* **Flarum** `^2.0`
* **PHP** `8.3+` (Flarum 2's minimum)
* Optional: [Flarum Tags](https://github.com/flarum/tags) (Category layout, tag colouring, tag accents) and Page Builder (Articles widget) light up automatically when present.

---

## FAQ

**Will my visitors see my experiments?**

No. Everything is a private draft until you **Publish**. One click reverts.

**Can I use a font that isn't in the suggestions?**

Yes — type *any* Google Font name; the whole library is available.

**Does it replace ramon/colored or fof/categories?**

It includes native equivalents — tag-driven colouring and a tag-based category index — so you don't need to run both.

**Can I move a theme between forums?**

Export `.bespoke.json` on one and import it on another.

**Is there a flash of the default theme on load?**

No — the instant layer is server-rendered.

---

## Pricing

Bespoke is a premium extension sold on [Floxum](https://floxum.com/extension/ernestdefoe/bespoke):

| Plan | Price |

|---|---|

| **Annual** | **$20.00 / year** |

| **Lifetime** | **$100.00 one-time** |

Both plans include all features and updates. Buy at [floxum.com/extension/ernestdefoe/bespoke](https://floxum.com/extension/ernestdefoe/bespoke).

---

## Support

Found a bug or have a request?

* **Support site:** [ernestdefoe.online](https://ernestdefoe.online)
* **Issues:** [github.com/ernestdefoe/bespoke/issues](https://github.com/ernestdefoe/bespoke/issues)

---

## License

Proprietary — commercial license. <span class="ipsEmoji">©</span> 2026 ernestdefoe. See `LICENSE.md`.</code></pre>]]></description><guid isPermaLink="false">23</guid><pubDate>Wed, 03 Jun 2026 04:33:18 +0000</pubDate></item><item><title>Digest Mail &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/29-digest-mail-support-and-discussion/</link><description><![CDATA[<h1>Digest Email</h1><p>A <a rel="external nofollow" href="https://flarum.org">Flarum</a> extension that sends beautifully formatted digest emails to your forum members on a schedule they choose. Each email summarises what happened on your forum since the last digest — new discussions, active conversations, new members, leaderboard standings, badges earned, pick'em results, awards, and more — all in a clean, branded email that works in every major email client.</p><hr><h2>What It Does</h2><p>Instead of sending a notification every time something happens, Digest Mail sends one well-organised summary email per period. Members choose how often they want it — daily, weekly, or monthly — and can unsubscribe at any time with a single click. Admins control what goes in the email, when it sends, and how hard it works on the server.</p><hr><h2>Email Content</h2><p>Every digest email is made up of sections. Some are always included, others only appear when the relevant extension is installed and enabled by the admin.</p><h3>Always included</h3><p><strong>Featured Discussion</strong></p><p>An admin-pinned discussion displayed prominently at the top of every digest with a highlighted card, author avatar, and a button linking directly to the discussion. Set this to your most important current thread — announcements, pinned rules, ongoing events. Leave it blank to disable it.</p><p><strong>New Discussions</strong></p><p>Discussions that were started during the digest period, showing the title, author, and reply count.</p><p><strong>Active Discussions</strong></p><p>The most engaged discussions during the period, ranked by a configurable activity score that balances reply count and recency. The admin can tune how much weight each factor carries.</p><p><strong>Unread Discussions</strong></p><p>Personalised to each recipient — shows discussions they have not read yet, based on their own read history. This is the only section that differs between subscribers.</p><p><strong>New Members</strong></p><p>Members who joined during the period, shown with avatars and join date.</p><p><strong>Community Stats</strong></p><p>A four-number summary bar showing total posts, discussions, new members, and active users during the period. This always appears near the top of every email regardless of section order.</p><p><strong>Favorite Discussions</strong></p><p>The most liked or reacted-to discussions during the period. If <code>fof/reactions</code> is enabled, shows a per-emoji reaction breakdown. If only <code>flarum/likes</code> is installed, shows like counts. Requires at least one of those extensions to be active.</p><h3>Optional — require additional extensions</h3><p><strong>Leaderboard</strong> <em>(requires</em> <code>huseyinfiliz/leaderboard</code>)</p><p>Shows the top point-earners for the period with a podium display for the top three, a full ranked table for positions four and beyond, movement indicators showing who moved up or down, and a "biggest mover" spotlight for whoever gained the most points during the period.</p><p><strong>Badges</strong> <em>(requires</em> <code>fof/badges</code>)</p><p>Shows badges earned during the period — recent earners with their badges, the most-awarded badge of the period, and the rarest badge awarded.</p><p><strong>Pick'em</strong> <em>(requires</em> <code>huseyinfiliz/pickem</code>)</p><p>Shows upcoming pick'em matches members can still vote on, recent match results, and the current pick'em leaderboard standings.</p><p><strong>Gamepedia</strong> <em>(requires</em> <code>huseyinfiliz/gamepedia</code>)</p><p>Shows the most-discussed game pages from the period and newly added games.</p><p><strong>Awards</strong> <em>(requires</em> <code>huseyinfiliz/awards</code>)</p><p>Shows active and upcoming awards — including name, description, voting deadline countdown, category list, vote totals, and current front-runners when live vote display is enabled on the award.</p><hr><h2>Section Order</h2><p>Every section listed above can be reordered from the <strong>Digest Order</strong> tab in the admin panel. Use the arrows to set the sequence sections appear in each email. Only enabled sections appear in the list. The three core sections (Discussions, New Members, and Stats) are always shown regardless of order position.</p><hr><h2>Scheduling</h2><h3>How timing works</h3><p>You set the time you want digests to go out — for example 8 a.m. — and the extension fires at that time in whichever timezone you select. You choose your own timezone, not the server's. A forum run by an admin in Chicago should be set to Central Time and set to 8 a.m., even if the server itself is physically located somewhere else entirely.</p><h3>Single hour vs send window</h3><p><strong>Single hour:</strong> The extension dispatches one chunk of subscribers per scheduler run at the configured hour. For most small forums this means all subscribers are processed in one or two runs within the same minute.</p><p><strong>Send window:</strong> You set a start time and an end time — for example 2 a.m. to 5 a.m. — and the extension dispatches one chunk of subscribers per minute throughout that window. Each minute the scheduler fires, the next batch is processed and queued. Workers drain each batch in parallel as it arrives. This keeps server load low and steady instead of hitting everything at once. Recommended for forums with more than a few thousand subscribers.</p><p>When the send window is active, the extension tracks its own progress automatically. Once all subscribers for a given frequency have been processed, it stops on its own — it does not keep running until the window closes.</p><h3>User frequency choices</h3><p>Each user picks their own digest frequency from their account settings page:</p><ul><li><p><strong>Daily</strong> — one email every day at the configured time</p></li><li><p><strong>Weekly</strong> — one email on the configured day of the week</p></li><li><p><strong>Monthly</strong> — one email on the configured day of the month</p></li><li><p><strong>Off</strong> — no digest emails</p></li></ul><p>Admins can restrict which frequencies are available. A low-traffic forum might choose to offer only weekly and monthly and hide the daily option entirely. The unsubscribe preference page shown to users automatically reflects whichever options the admin has enabled.</p><hr><h2>Design and Themes</h2><p>Every email uses a table-based HTML layout that works reliably in all major email clients including Gmail, Outlook, Apple Mail, and mobile clients.</p><p>The email uses your forum's configured brand colours throughout — headings, buttons, and accent elements all pull from your forum's primary and secondary colour settings automatically.</p><p><strong>Light and dark mode:</strong> If <code>fof/nightmode</code> is installed, each subscriber's email theme automatically matches their night mode preference — members who use dark mode receive a dark-themed email. Members who have not set a preference receive the light version. If night mode is not installed, all emails use the light theme.</p><hr><h2>Unsubscribe</h2><p>Every email includes a secure unsubscribe link in the footer. Clicking it takes the subscriber to a preference page where they can choose a different frequency or opt out entirely.</p><p>The link is unique to each subscriber and valid for 90 days. Unlike some implementations, the link remains valid across multiple digest sends — it is only replaced when it expires or the subscriber uses it to change their preference. This means a user who receives a digest on Monday and clicks the link on Friday will always get a working page.</p><hr><h2>Admin Panel</h2><p>The admin panel is organised into four tabs.</p><h3>Settings</h3><p><strong>Content Limits</strong> — set the maximum number of items shown in each section: new discussions, active discussions, unread discussions, new members, leaderboard entries, badges, pick'em entries, and gamepedia entries. Also includes the featured discussion ID and the weighting controls for the hot score algorithm.</p><p><strong>Schedule</strong> — set your timezone, send time (start hour), optional send window end hour, weekly send day, and monthly send day. A live summary below the time dropdowns shows you exactly what mode you are in and when emails will go out.</p><p><strong>User Frequency Options</strong> — choose which frequency options are available to users on their account settings page.</p><p><strong>Extension Integrations</strong> — enable or disable each optional section individually. A toggle is only activatable when the required extension is installed and enabled in Flarum. Sections that are disabled here are removed from the digest entirely and do not appear in the Digest Order tab.</p><p><strong>Token Checker</strong> — paste any unsubscribe token to verify it is valid, see which user it belongs to, and confirm its expiry date. Useful for diagnosing unsubscribe link issues without sending an email.</p><h3>Digest Order</h3><p>Arrow-based ordering for all active sections. Changes save immediately and apply to all future digests. Sections that are not currently enabled are not shown here — enable them in the Settings tab first.</p><h3>Statistics</h3><p>Live statistics pulled from your forum's database:</p><ul><li><p><strong>Subscription Overview</strong> — total members, total digest subscribers, and the overall subscription rate as a percentage</p></li><li><p><strong>Subscribers by Frequency</strong> — how many subscribers are on each frequency, with a visual bar and a <strong>View</strong> button that slides open a paginated list of all subscribers for that frequency showing username, avatar, and last sent date</p></li><li><p><strong>Last Sent</strong> — the date and time each frequency was last sent</p></li><li><p><strong>Send History</strong> — one entry per frequency per day showing the total sent and skipped count. History is retained automatically: 30 daily entries, 52 weekly entries, and 24 monthly entries</p></li></ul><h3>Server Settings</h3><p>Everything related to how the extension uses your server, in one place. The page auto-detects your forum's installation path and generates ready-to-copy cron lines and config blocks using your actual server path.</p><ul><li><p><strong>Queue Settings</strong> — queue name, chunk size (subscribers dispatched per scheduler run), job delay, and maximum retry attempts</p></li><li><p><strong>Cron Setup</strong> — tailored setup instructions for your chosen queue backend: Sync, Database Queue, or Redis/Valkey. Each tab shows only what is relevant to that setup, including retry and backoff behaviour, send window guidance, and optional two-phase pre-population for very large forums</p></li><li><p><strong>Recommended Settings by Forum Size</strong> — a reference table covering 100 members through 100,000+ with suggested chunk size, worker count, and send mode for each tier</p></li></ul><hr><h2>Test Send</h2><p>From the Settings tab, any admin can send a live digest email to any address immediately — without affecting any subscriber records or timestamps. Choose a frequency and an optional theme (light or dark), enter any email address, and click Send. Use this to check your email layout, branding, and content before your first scheduled send goes out.</p><hr><h2>Requirements</h2><h3>Core requirements</h3><ul><li><p>PHP 8.1 or higher</p></li><li><p>Flarum 2.0 or higher</p></li><li><p>A working outbound mail configuration in your Flarum admin panel (SMTP, Mailgun, Postmark, etc.)</p></li><li><p>A server cron job running <code>schedule:run</code> every minute — this is the standard Flarum scheduler requirement shared by many other extensions</p></li></ul><h3>Queue driver</h3><p>By default Flarum uses the <strong>sync</strong> queue driver, which processes jobs during the web request rather than in the background. This is fine for very small forums but causes problems as your subscriber list grows:</p><p>| Subscribers | What happens on sync |</p><p>|---|---|</p><p>| Under \~50 | Fine — most servers handle it without issue |</p><p>| 50–200 | Slow page responses, occasional timeouts |</p><p>| 200+ | Regular timeouts, memory exhaustion on typical VPS hosting |</p><p>| 500+ | Effectively broken — posts fail or appear to hang |</p><p><strong>Flarum 2.x has a database queue driver built into core</strong> — no extension install required. To enable it, add this to your <code>config.php</code>:</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
    'driver' =&gt; 'database',
],```

For larger forums, Redis or Valkey with Laravel Horizon and Supervisor is the most scalable option. See the **Server Settings** page in the admin panel for full setup instructions tailored to your chosen approach.

### Optional integrations

| Extension | What it enables |

|---|---|

| `huseyinfiliz/leaderboard` | Leaderboard section |

| `fof/badges` | Badges section |

| `huseyinfiliz/pickem` | Pick'em section |

| `huseyinfiliz/gamepedia` | Gamepedia section |

| `huseyinfiliz/awards` | Awards section |

| `flarum/likes` | Favorite Discussions section |

| `fof/reactions` | Per-emoji reaction breakdown in Favorite Discussions |

| `fof/nightmode` | Per-user dark mode email theme |

---

## Installation

```composer require ernestdefoe/digest-mail
php flarum migrate```

Then enable the extension in your Flarum admin panel.

---

## Cron Setup

The only cron line required for all setups is the Flarum scheduler. Add it to your server's crontab by running `sudo crontab -u YOUR_WEB_USER -e`, replacing `YOUR_WEB_USER` with the user that owns your Flarum files. If you are unsure which user that is, run `ls -la /path/to/flarum` and check the owner column. Common values are:

* **Ubuntu/Debian** with Nginx or Apache → `www-data`
* **CentOS/RHEL** with Apache → `apache`
* **CentOS/RHEL** with Nginx → `nginx`
* **Shared hosting** → your hosting account username

```* * * * * cd /path/to/flarum &amp;&amp; php flarum schedule:run &gt;&gt; /dev/null 2&gt;&amp;1```

**If you are using the sync driver**, that is the only line you need.

**If you are using the database queue driver**, add a second line for the queue worker:

```* * * * * cd /path/to/flarum &amp;&amp; php flarum queue:work --queue=digest,default --max-time=55 --tries=3 --backoff=30 &gt;&gt; /dev/null 2&gt;&amp;1```

`--queue=digest,default` processes digest jobs first, then other Flarum notifications. `--max-time=55` stops the worker cleanly before the next cron fires. Add one additional worker line per parallel worker for larger forums.

**If you are using Redis or Valkey with Horizon and Supervisor**, the scheduler cron line is the only line you need. Do not add a `queue:work` cron line — Horizon is your persistent worker and runs continuously under Supervisor. Adding a `queue:work` cron on top would create competing workers.

Adjust `user` to match the user that owns your Flarum files (`www-data`, `apache`, `nginx`, or your hosting account username depending on your setup).

The **Server Settings** page in the admin panel generates ready-to-copy cron lines and config blocks using your actual server path and current Queue Settings values.

### Two-phase pre-population (50,000+ subscribers only)

For very large forums, you can pre-populate the queue with jobs before the send window opens so workers have no construction overhead when they start. Add this cron line 10 minutes before your configured send window start. For example, if your window starts at 2 a.m., run this at 1:50 a.m.:

```50 1 * * * cd /path/to/flarum &amp;&amp; php flarum digest:enqueue --frequency=daily --delay=600 &gt;&gt; /dev/null 2&gt;&amp;1```

The first number is the minute (50 = :50) and the second is the hour in 24-hour format (1 = 1 a.m.). Adjust both to match your setup.

---

## Console Commands

### `digest:send`

The main send command. Runs automatically via the scheduler every minute. Outside the configured send window it exits immediately. Inside the window it dispatches one chunk of subscribers and exits, leaving the rest for the next minute.

```# Normal run — respects time gate and window
php flarum digest:send

# Force a specific frequency, bypassing the time gate (useful for testing)
php flarum digest:send --frequency=daily

# Preview mode — shows eligible recipients and content without sending anything
php flarum digest:send --frequency=weekly --dry-run

# Test a single user by ID
php flarum digest:send --frequency=daily --user=1

# Override the queue name
php flarum digest:send --queue=high-priority

# Override the job delay in seconds
php flarum digest:send --delay=300```

### `digest:enqueue`

Pre-populates the queue with jobs but does not send them. Intended for very large forums that want to build all jobs ahead of time so workers have no construction overhead when the send window opens.

```# Pre-build all daily digest jobs with a 10-minute delay before they become available
php flarum digest:enqueue --frequency=daily --delay=600

# Preview how many users would be enqueued without actually doing it
php flarum digest:enqueue --frequency=weekly --dry-run```

---

## Performance and Scaling

The extension is built for efficiency at any subscriber count.

**Shared data caching:** Almost everything in a digest email is identical for every subscriber in the same frequency group — new discussions, hot discussions, new members, leaderboard, awards, badges, and all other sections are built once per send run and stored in cache for 2 hours. The only per-subscriber query is unread discussions. For a forum with 10,000 daily subscribers this means roughly 10,013 total database queries per send instead of 100,000+.

**Lightweight job storage:** Each background job stores only a user ID, frequency, and a reference to the cached shared data — typically under 500 bytes per job. The jobs table stays small and workers stay fast.

**Persistent unsubscribe tokens:** Each subscriber's unsubscribe token is generated once and reused across sends. It is only replaced when it expires (90 days) or the subscriber uses it. This ensures unsubscribe links in emails always work, regardless of how many sends have occurred since the email was received.

**Send window pacing:** With a send window configured, the extension dispatches one chunk of subscribers per minute throughout the window. Workers drain each chunk in parallel as it arrives. Server load stays low and steady across the entire window period.

**Recommended settings by forum size:**

| Forum Size | Chunk Size | Workers | Send Mode |

|---|---|---|---|

| 100–500 members | 200 | 1 | Single hour |

| 500–2,000 | 500 | 1 | Single hour |

| 2,000–5,000 | 1,000 | 2 | 1–2 hour window |

| 5,000–15,000 | 2,000 | 3 | 2–3 hour window |

| 15,000–50,000 | 5,000 | 5 | 2–4 hour window |

| 50,000–100,000 | 7,500 | 8 | 3–4 hour window |

| 100,000+ | 10,000 | 10+ | 4+ hour window |

For 50,000+ member forums, consider switching from the database queue driver to Redis or Valkey with Horizon and Supervisor for significantly higher throughput and real-time queue monitoring. The Server Settings page in the admin panel includes full step-by-step setup instructions for this configuration.

---

## Credits

Originally created by [Resofire](https://github.com/resofire). Rebranded and

maintained by [ernestdefoe](https://github.com/ernestdefoe), with full credit and

thanks to the original author.

## License

MIT — Copyright (c) 2026 Resofire</code></pre>]]></description><guid isPermaLink="false">29</guid><pubDate>Sat, 06 Jun 2026 16:08:54 +0000</pubDate></item><item><title>Topic Map &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/53-topic-map-support-and-discussion/</link><description><![CDATA[<h1>Topic Map</h1><p>A <a rel="external nofollow" href="https://flarum.org">Flarum 2</a> extension. A Discourse-style <strong>topic map</strong> under the first post of busy discussions: views, likes, outbound links, top participants and estimated read time at a glance — plus a <strong>Top Replies</strong> panel that jumps you straight to the most-liked answers.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/topic-map/main/github/topic-map.png" alt="Topic map with the Top Replies panel open" class="ipsRichText__align--block" loading="lazy"></p><h2>Features</h2><ul><li><p><strong>Stats bar</strong> on the first post once a discussion passes a reply threshold (admin setting): views · likes · links · participants (with avatars) · minutes-to-read.</p></li><li><p><strong>Top Replies</strong> — the most-liked replies with author + excerpt; click one to jump to that post. Works with <code>flarum/likes</code> <strong>or</strong> <code>fof/reactions</code> (the stat relabels itself "reactions"); hides when neither is installed.</p></li><li><p><strong>Links panel</strong> — the discussion's outbound links grouped by URL, tap the links stat to expand.</p></li><li><p><strong>View counting</strong> built in (guests count, one per browser session, visibility-checked). On forums running <code>ernestdefoe/bespoke</code>, Bespoke's view counter is used instead — one source of truth, never double-counted.</p></li><li><p>Everything is computed server-side and cached; a 400-post scan cap keeps huge topics cheap.</p></li><li><p>Fully translatable.</p></li></ul><h2>Installation</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum migrate
php flarum cache:clear```

## Updating

```composer update ernestdefoe/topic-map
php flarum migrate
php flarum cache:clear```

## Links

* [Packagist](https://packagist.org/packages/ernestdefoe/topic-map)
* [GitHub](https://github.com/ernestdefoe/topic-map)</code></pre>]]></description><guid isPermaLink="false">53</guid><pubDate>Sun, 05 Jul 2026 21:42:35 +0000</pubDate></item><item><title>GitHub README Paste &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/52-github-readme-paste-support-and-discussion/</link><description><![CDATA[<h1>GitHub README Paste — Flarum 2 extension</h1><p>Paste a GitHub repo URL into the Flarum composer and the URL is <strong>auto-replaced</strong> with the rendered README markdown.</p><h2>How it works</h2><ol><li><p>User pastes <code>https://github.com/owner/repo</code> into any composer (new discussion, reply, edit, private message).</p></li><li><p>The frontend recognizes it as a GitHub repo root URL and intercepts the paste.</p></li><li><p>It calls <code>POST /api/gh-readme/fetch</code> on the Flarum backend.</p></li><li><p>The backend fetches <code>https://api.github.com/repos/{owner}/{repo}/readme</code>, decodes the base64 payload, rewrites relative image / link / anchor URLs against the repo's HEAD branch on <code>raw.githubusercontent.com</code>, and returns the processed markdown.</p></li><li><p>The frontend replaces the URL in the composer with the README markdown. The user can edit freely from there.</p></li></ol><p>Subsequent pastes of the same repo are served from a 10-minute server-side cache so a popular forum doesn't burn GitHub's rate limit.</p><h3>Works with both composer types</h3><p>| Composer | Behavior |</p><p>| --- | --- |</p><p>| <strong>Default Flarum</strong> (textarea + <code>flarum/markdown</code>) | URL replaced inline by the markdown source. The post renders as formatted markdown at display time. A visible italic "Loading…" marker shows in the textarea during the fetch. |</p><p>| <code>fof/rich-text</code> (Tiptap WYSIWYG) | URL replaced by rich nodes — headings, paragraphs, lists, code blocks, blockquotes, images all appear formatted in the composer immediately. A toast notification shows during the fetch (no inline marker — finding a specific text node inside a ProseMirror document is brittle). |</p><p>Detection is automatic via the presence of <code>editor.editor</code> on the active driver. No setting needed.</p><h2>Install</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum cache:clear```

Then enable in **Admin → Extensions → GitHub README Paste**.

`flarum/markdown` is a `suggest` dep — without it the inserted markdown ends up in the post but renders as plain text rather than formatted headings/lists/code blocks.

## Configure

**Admin → Extensions → GitHub README Paste:**

* **GitHub Personal Access Token** *(optional)* — raises GitHub's API rate limit from 60/hour-per-IP (unauth) to 5000/hour. No scopes required for public repos.
* **Cache duration (minutes)** — how long the server caches each README before refetching. Default 10. Clamped 1–60.

## URL shapes accepted

| URL | Behavior |

| --- | --- |

| `https://github.com/owner/repo` | </code></pre><p><code><span class="ipsEmoji" title="">✅</span> expanded |  | `https://github.com/owner/repo/` | <span class="ipsEmoji" title="">✅</span> expanded |  | `https://github.com/owner/repo.git` | <span class="ipsEmoji" title="">✅</span> expanded (strips `.git`) |  | `https://www.github.com/owner/repo` | <span class="ipsEmoji" title="">✅</span> expanded |  | `https://github.com/owner/repo/tree/main` | <span class="ipsEmoji" title="">❌</span> left as-is (use the root URL) |  | `https://github.com/owner/repo/blob/main/file.md` | <span class="ipsEmoji" title="">❌</span> left as-is (file links, not repos) |  | `http://github.com/owner/repo` | <span class="ipsEmoji" title="">❌</span> rejected (must be https) |  | `https://gitlab.com/owner/repo` | <span class="ipsEmoji" title="">❌</span> not GitHub |  ## Security notes  * Strict URL allowlist (`github.com` host only). * Owner/repo regex-allowlisted to GitHub's own charset. * The backend never fetches the user-supplied URL directly — it constructs the API call from validated owner/repo segments. SSRF surface is the GitHub API host only. * Response body capped at 2 MB. * 10s connect + 15s total request timeout. * TLS verification on. * Endpoint requires an authenticated Flarum actor; throttled by Flarum's standard per-actor API throttler.  ## License  MIT — see [LICENSE](LICENSE).</code></p>]]></description><guid isPermaLink="false">52</guid><pubDate>Sun, 05 Jul 2026 21:42:35 +0000</pubDate></item><item><title>Armory &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/51-armory-support-and-discussion/</link><description><![CDATA[<h1>Armory</h1><p>A <strong>World of Warcraft armory</strong> for <a rel="external nofollow" href="https://flarum.org">Flarum 2</a>. Members sign in</p><p>with <strong>Battle.net</strong>, and the extension pulls their characters straight from the</p><p>Blizzard API — gear with hover tooltips, stats, talents, Mythic+/raid progress,</p><p>professions, PvP ratings, reputations and collections — on a tabbed, theme-aware</p><p>character page that looks at home in light or dark mode.</p><p>Free and open source (MIT). The companion <a rel="external nofollow" href="https://convoro.co">Convoro</a> build</p><p>shares the same data engine.</p><h2>Features</h2><ul><li><p><strong>Battle.net OAuth</strong> — one click to connect; characters sync automatically.</p></li><li><p><strong>Full character page</strong> at <code>/armory</code> with tabs:</p><ul><li><p><strong>Gear</strong> — every slot with a big 3D character render and Wowhead-style item tooltips (item level, stats, sockets, set bonuses, sell price).</p></li><li><p><strong>Stats</strong> — primary + secondary stats, defenses and resources.</p></li><li><p><strong>Talents</strong> — active spec, talents, and the in-game loadout import string.</p></li><li><p><strong>PvE</strong> — Mythic+ rating and best weekly runs, plus raid progress.</p></li><li><p><strong>Professions</strong> — primary and secondary, with tier skill.</p></li><li><p><strong>PvP</strong> — honor level and rated 2v2 / 3v3 / RBG ratings.</p></li><li><p><strong>Reputations</strong> and <strong>Achievements / Collections</strong> (points, mounts, pets).</p></li></ul></li><li><p><strong>Roster sidebar</strong> to switch between your characters; pick a <strong>main</strong>, hide alts.</p></li><li><p><strong>Role-Play tie-in</strong> — if <a rel="external nofollow" href="https://github.com/ernestdefoe/roleplay">ernestdefoe/roleplay</a> is installed, an <strong>Add to Role-Play</strong> button imports a WoW character as a playable Role-Play character: a combat sheet (HP + might/agility/wits/heart scaled from item level and primary stats) plus a deck of signature <strong>class ability cards</strong> whose damage dice scale with item level. Re-run after a gear upgrade to rescale.</p></li><li><p><strong>Theme-aware</strong> — colors follow your forum's light/dark scheme.</p></li><li><p><strong>Caching</strong> — character data is cached so the page stays fast and stays well</p><p>under Blizzard's rate limits.</p></li></ul><h2>Setup</h2><ol><li><p>Install:</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum migrate
php flarum cache:clear   ```</code></pre></li><li><p>Create a Battle.net API client at</p><p><a rel="external nofollow" href="https://develop.battle.net/access/clients">develop.battle.net/access/clients</a>.</p><p>Set the <strong>Redirect URL</strong> to <code>https://YOUR-FORUM/auth/battlenet/callback</code>.</p></li><li><p>In <strong>Admin → Armory</strong>, paste the <strong>Client ID</strong> and <strong>Client Secret</strong>, and</p><p>choose your default <strong>region</strong> (Americas / Europe / Korea / Taiwan).</p></li><li><p>Members open <strong>Armory</strong> from the navigation and click <strong>Connect Battle.net</strong>.</p></li></ol><h2>How it works</h2><p>Public character data (gear, stats, raids, …) is fetched with an app-level</p><p>client-credentials token, so refreshes never require the member to sign in</p><p>again. The member's <code>wow.profile</code> token is used only once — to discover which</p><p>characters belong to them.</p><h2>License</h2><p><a rel="" href="LICENSE">MIT</a> <span class="ipsEmoji">©</span> ernestdefoe</p>]]></description><guid isPermaLink="false">51</guid><pubDate>Sun, 05 Jul 2026 21:42:35 +0000</pubDate></item><item><title>Janitor &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/50-janitor-support-and-discussion/</link><description><![CDATA[<h1>Janitor</h1><p>Automated, rules-based discussion housekeeping for <strong>Flarum 2</strong>.</p><p>Define rules that periodically look inside chosen tags for discussions matching</p><p>conditions (age, tags, reply count) and then <strong>hide</strong>, <strong>lock</strong>, <strong>retag / move</strong>,</p><p>or <strong>delete</strong> them — so a busy section keeps itself tidy without manual moderator</p><p>work.</p><p>Inspired by the "auto-archive old/prefixed threads" plugins from other forum</p><p>software, rebuilt the Flarum way (tags instead of forum IDs).</p><h2>Features</h2><ul><li><p><strong>Rules</strong> — each rule has a <em>scope</em> (one or more tags, or all), <em>conditions</em>,</p><p>an <em>action</em>, and its own <em>run frequency</em>.</p></li><li><p><strong>Conditions</strong> — inactive/created for N days, also has / doesn't have certain</p><p>tags, minimum / maximum replies.</p></li><li><p><strong>Actions</strong> — hide, lock, unlock, add tag, remove tag, move (retag), or</p><p>permanently delete.</p></li><li><p><strong>Scheduler</strong> — due rules run automatically; you can also <strong>Run</strong> or</p><p><strong>Preview</strong> any rule on demand from the admin page.</p></li><li><p><strong>Global dry-run</strong> — preview everything: rules log what they <em>would</em> do and</p><p>change nothing. Flip it off when you're confident.</p></li><li><p><strong>Audit-log friendly</strong> — every live action dispatches the matching Flarum</p><p>domain event (<code>Hidden</code>, <code>Deleted</code>, tag/lock events), so audit-log /</p><p>action-log extensions record Janitor's actions automatically, attributed to an</p><p>admin. (Dry-run previews never emit them.)</p></li><li><p><strong>Safety</strong> — stickied and locked discussions are protected by default, every</p><p>run is capped (default 100 actions), permanent delete is opt-in per rule, and</p><p>every (would-be) action is written to an <strong>action log</strong>. A rule can opt in to</p><p><strong>include locked</strong> (e.g. archiving closed-and-locked sale threads) or</p><p><strong>include stickied</strong> discussions when that's exactly what it's for; the</p><p>Unlock action always includes locked discussions.</p></li><li><p><strong>Every condition is optional</strong> — a rule can match on tags alone (no</p><p>inactivity needed), on inactivity alone, or any combination.</p></li></ul><h2>Install</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum migrate
php flarum cache:clear```

Then enable **Janitor** in the admin panel and open its settings to add rules.

## Requirements: the scheduler

Janitor's automatic runs rely on Flarum's task scheduler, so your server must run

this cron entry (once a minute):

```* * * * * cd /path/to/forum &amp;&amp; php flarum schedule:run &gt;&gt; /dev/null 2&gt;&amp;1```

Without it, rules won't run on their own — but the **Run** / **Preview** buttons

on the settings page work regardless, and are the safest way to try a rule first.

## Tips

* Start with **Global dry-run** on and use **Preview** to see exactly which

  discussions a rule would hit (check the action log) before letting it act.
* Prefer **Hide** or **Move** over **Delete** — hidden discussions can be

  restored; deletion can't.
* "Inactive for N days" measures last activity by default — ideal for archiving

  stale threads in a busy tag.

## License

[MIT](https://github.com/ernestdefoe/janitor/blob/main/LICENSE.md) <span class="ipsEmoji">©</span> ernestdefoe</code></pre>]]></description><guid isPermaLink="false">50</guid><pubDate>Sun, 05 Jul 2026 21:33:24 +0000</pubDate></item><item><title>Maintenance &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/48-maintenance-support-and-discussion/</link><description><![CDATA[<h1>Maintenance</h1><p><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License" class="ipsRichText__align--block" loading="lazy"> <a rel="external nofollow" href="https://packagist.org/packages/ernestdefoe/maintenance"><img src="https://img.shields.io/packagist/v/ernestdefoe/maintenance.svg" alt="Latest Stable Version" class="ipsRichText__align--block" loading="lazy"></a></p><p>A <a rel="external nofollow" href="https://flarum.org">Flarum 2</a> extension. Adds <strong>Run Migrations</strong> and <strong>Publish Assets</strong> to the admin dashboard's tools menu — right beside Clear Cache, System Info and Toggle Advanced Page — so you can finish an extension install or update without ever opening a terminal.</p><h2>Features</h2><ul><li><p><strong>Run Migrations</strong> — the in-process equivalent of <code>php flarum migrate</code>: runs outstanding core and extension migrations, then reloads the admin so everything picks up the changes.</p></li><li><p><strong>Publish Assets</strong> — the equivalent of <code>php flarum assets:publish</code>: republishes core fonts and every enabled extension's assets.</p></li><li><p>Admin-only (both endpoints reject non-admins), and each run reports exactly what it did.</p></li><li><p>Perfect companion to the Extension Manager on shared hosting.</p></li><li><p>Fully translatable.</p></li></ul><h2>Installation</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum cache:clear```

## Updating

```composer update ernestdefoe/maintenance
php flarum cache:clear```

## Links

* [Packagist](https://packagist.org/packages/ernestdefoe/maintenance)
* [GitHub](https://github.com/ernestdefoe/maintenance)</code></pre>]]></description><guid isPermaLink="false">48</guid><pubDate>Sun, 05 Jul 2026 21:31:32 +0000</pubDate></item><item><title>Calendar &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/25-calendar-support-and-discussion/</link><description><![CDATA[<h1>Calendar &amp; Events for Flarum</h1><p><a rel="external nofollow" href="https://github.com/ernestdefoe/calendar/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://github.com/ernestdefoe/calendar/releases"><img src="https://img.shields.io/github/v/tag/ernestdefoe/calendar?label=release" alt="Latest version" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://flarum.org"><img src="https://img.shields.io/badge/Flarum-%5E2.0-orange.svg" alt="Flarum" class="ipsRichText__align--block" loading="lazy"></a></p><p>A full-featured, <strong>free</strong> calendar &amp; events extension for <strong>Flarum 2</strong>. Month and</p><p>list views, RSVPs, colour-coded categories, recurring events, cover images, a</p><p>proper <strong>iCal feed</strong>, one-click <strong>Google Calendar</strong> export, and a drop-anywhere</p><p><strong>Upcoming Events</strong> widget that looks right on the default theme — and integrates</p><p>natively with Bespoke and</p><p>Page Builder.</p><p>Built to feel premium. Priced at free.</p><hr><h2>Features</h2><ul><li><p><span class="ipsEmoji" title="">🗓️</span> <strong>Month, Week, Day &amp; list</strong> views with quick prev / today / next navigation.</p><p>Week/Day are true time grids with hour lines, a live "now" indicator, side-by-side</p><p>overlapping events, and double-click-to-create at the clicked time slot.</p></li><li><p><span class="ipsEmoji" title="">📍</span> <strong>Location</strong> on every event, rendered as a one-tap <strong>Google Maps</strong> link.</p></li><li><p><span class="ipsEmoji" title="">🔁</span> <strong>Recurring events</strong> (daily / weekly / monthly / yearly) via standard <code>RRULE</code>,</p><p>expanded on the fly so each occurrence shows on the right day.</p></li><li><p><span class="ipsEmoji" title="">✅</span> <strong>RSVP</strong> — members mark themselves <em>Going</em> or <em>Interested</em>, with live counts.</p></li><li><p><span class="ipsEmoji" title="">🎨</span> <strong>Categories with colours</strong> — filter the calendar and give each event a</p><p>coloured accent. Managed from a dedicated admin panel with a colour picker.</p></li><li><p><span class="ipsEmoji" title="">🖼️</span> <strong>Cover image</strong> per event — paste a URL, or <strong>upload a file</strong> directly when</p><p><a rel="external nofollow" href="https://github.com/FriendsOfFlarum/upload">FoF Upload</a> is installed (auto-detected;</p><p>falls back to a URL field otherwise).</p></li><li><p><span class="ipsEmoji" title="">📅</span> <strong>iCal export</strong> — a subscribable <code>feed.ics</code> for the whole calendar plus a</p><p>per-event <code>.ics</code> download (RFC 5545, proper escaping &amp; folding).</p></li><li><p><span class="ipsEmoji" title="">🟦</span> <strong>Google Calendar</strong> — "Add to Google Calendar" deep-links with title, time,</p><p>description and location pre-filled.</p></li><li><p><span class="ipsEmoji" title="">💬</span> <strong>Optional discussion thread</strong> per event (hybrid model) so members can</p><p>comment using Flarum's native discussion UI.</p></li><li><p><span class="ipsEmoji" title="">🧩</span> <strong>Upcoming Events widget</strong> — works standalone on the <strong>default theme</strong>, and</p><p>registers as a first-class widget/block in <strong>Bespoke</strong> and <strong>Page Builder</strong>.</p></li><li><p><span class="ipsEmoji" title="">🌓</span> <strong>Theme-aware</strong> — every colour resolves through Flarum's own CSS variables,</p><p>so it looks correct in light &amp; dark and on custom themes out of the box.</p></li><li><p><span class="ipsEmoji" title="">🔐</span> <strong>Permissions</strong> — separate "create events" and "manage all events" controls.</p></li></ul><h2>Installation</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum migrate
php flarum cache:clear```

Then open **Admin → Calendar** to configure it.

## Updating

```composer update ernestdefoe/calendar
php flarum migrate
php flarum cache:clear```

## Configuration

**Admin → Calendar** gives you:

| Setting | What it does |

| --- | --- |

| **Default view** | Month grid or upcoming list when the calendar opens. |

| **Week starts on** | Sunday or Monday. |

| **Index widget** | Show an "Upcoming events" widget on the forum index. |

| **Widget count** | How many upcoming events the widget lists. |

| **Link discussion** | Auto-create a discussion thread for each new event (for comments). |

| **Categories** | Add / rename / recolour / delete colour-coded categories. |

Two permissions are added under **Admin → Permissions**:

* **Create calendar events** — who can add events.
* **Manage all calendar events** — who can edit/delete events they don't own.

## The Upcoming Events widget

The widget is a self-contained component, so it shows up automatically wherever

your theme supports it:

* **Default theme** — appears in the index sidebar (toggle in admin).
* **Bespoke** — available in the widget tray as **Upcoming events**.
* **Page Builder** — available as an **Events** block.

## Calendar subscription (iCal)

Every calendar exposes a subscribable feed at:

```https://your-forum.example/calendar/feed.ics```

Paste that URL into Google Calendar (*Other calendars → From URL*), Apple

Calendar (*File → New Calendar Subscription*), or Outlook to keep events in sync.

Each event also has its own `.ics` download and an "Add to Google Calendar" link.

## How events are modelled

Events are their own records (title, time, location, recurrence, etc.). When

**Link discussion** is enabled, creating an event also spins up a normal Flarum

discussion linked to it, so comments, mentions, likes and notifications all work

exactly as members expect — no parallel comment system to learn.

## Compatibility

* Flarum `^2.0`
* PHP `^8.3`
* No required third-party extensions. Plays nicely with Bespoke &amp; Page Builder

  when present, and degrades gracefully when they aren't.
* **Optional:** [FoF Upload](https://github.com/FriendsOfFlarum/upload) — enables

  drag-free file uploads for event cover images.

## Contributing

Issues and PRs welcome. To build the front-end locally:

```cd js
npm install
npm run dev      # watch
npm run build    # production```

## License

[MIT](https://github.com/ernestdefoe/calendar/blob/main/LICENSE) <span class="ipsEmoji">©</span> ernestdefoe</code></pre>]]></description><guid isPermaLink="false">25</guid><pubDate>Thu, 04 Jun 2026 17:41:43 +0000</pubDate></item><item><title>OnAir for Flarum 2 &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/38-onair-for-flarum-2-support-and-discussion/</link><description><![CDATA[<h1>OnAir — Live Streaming for Flarum 2</h1><p><a rel="" href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT" class="ipsRichText__align--block" loading="lazy"></a></p><p>Bring live video into your community. Members go live from <strong>YouTube</strong> or <strong>Twitch</strong>,</p><p>and a <strong>LIVE NOW</strong> badge follows their avatar everywhere it appears — posts, the</p><p>discussion list, mentions, the header, the sidebar.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/onair/main/screenshots/onair-live-badge.png" alt="OnAir — the LIVE badge follows a streamer's avatar everywhere, with a Live Now sidebar widget" class="ipsRichText__align--block" loading="lazy"></p><p><strong>Free / MIT.</strong> The optional premium add-on <strong>OnAir+</strong></p><p>turns your forum into the whole platform — a built-in RTMP server (stream straight in</p><p>from OBS), in‑forum HLS playback, multistream, VOD, live chat, go‑live notifications and</p><p>scheduled streams. See the comparison below.</p><h2>Features</h2><ul><li><p><span class="ipsEmoji" title="">🔴</span> <strong>LIVE badge on every avatar</strong> — one <code>Avatar</code> override lights a streamer up everywhere.</p></li><li><p><span class="ipsEmoji" title="">▶️</span> <strong>YouTube + Twitch embed viewer</strong> — paste a channel/video URL and go live.</p></li><li><p><span class="ipsEmoji" title="">📡</span> <strong>Presence with graceful fallback</strong> — uses <code>flarum/realtime</code> for instant badge</p><p>updates when installed, transparently falls back to lightweight polling when it isn't.</p></li><li><p><span class="ipsEmoji" title="">🟥</span> <strong>Live Now widget + a</strong> <code>/onair</code> directory — see who's streaming at a glance.</p></li><li><p><span class="ipsEmoji" title="">🔐</span> <strong>Permissions + admin settings</strong> — who can go live, default provider, poll interval.</p></li><li><p><span class="ipsEmoji" title="">⏱️</span> <strong>Stale‑stream reaper</strong> — auto‑ends streams left running.</p></li></ul><h3>The Live directory</h3><p><img src="https://raw.githubusercontent.com/ernestdefoe/onair/main/screenshots/onair-directory.png" alt="The /onair live directory listing everyone currently streaming" class="ipsRichText__align--block" loading="lazy"></p><h2>OnAir vs OnAir+</h2><p>OnAir (this extension) is free and complete on its own for YouTube/Twitch streamers.</p><p><strong>OnAir+</strong> is a paid add‑on for communities that want to host streaming themselves.</p><p>| | <strong>OnAir</strong> (free) | <strong>OnAir+</strong> |</p><p>|---|:---:|:---:|</p><p>| LIVE badge on avatar, everywhere | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| Live Now widget + <code>/onair</code> directory | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| YouTube embed viewer | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| Twitch embed viewer | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| Realtime presence + polling fallback | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| Permissions + admin settings | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| Auto‑end stale streams | <span class="ipsEmoji" title="">✅</span> | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Built‑in RTMP server → in‑forum HLS</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Stream keys + creator studio</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Multistream / restream to YouTube + Twitch</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>VOD recordings</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Live chat overlay</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Go‑live notifications + follow a streamer</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Scheduled streams + reminders</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><p>| <strong>Concurrent viewer counts</strong> | — | <span class="ipsEmoji" title="">✅</span> |</p><h3>OnAir+ — stream straight into the forum</h3><p>Members broadcast from OBS to your own server; viewers watch an <code>hls.js</code> player inline,</p><p>with live chat beside it.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/onair/main/screenshots/onairplus-live-stream.png" alt="OnAir+ playing a live RTMP→HLS stream in the forum with the live chat panel" class="ipsRichText__align--block" loading="lazy"></p><h3>OnAir+ — creator studio</h3><p>Each streamer gets an ingest URL, a secret stream key, multistream targets, and a one‑click</p><p>key reset.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/onair/main/screenshots/onairplus-studio.png" alt="OnAir+ streaming studio showing the ingest server, masked stream key and playback URL" class="ipsRichText__align--block" loading="lazy"></p><h2>Install</h2><p><code>composer require ernestdefoe/onair</code></p><p>Then enable <strong>OnAir</strong> in the admin panel. Optionally install <code>flarum/realtime</code> for</p><p>instant (push) LIVE badges — OnAir detects it automatically. For self‑hosted streaming,</p><p>add <strong>OnAir+</strong> (<code>composer require ernestdefoe/onair-pro</code>).</p><h2>Development</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
npm install
npm run build      # or: npm run dev  (watch)```

A no‑backend concept render of the whole product lives in `preview/index.html`.

## Architecture notes

* **LIVE badge:** overrides the shared `Avatar` component (main‑bundle, safe to extend at

  init) and reads a serializer‑supplied `user.isLive()`.
* **Presence transport:** `app.onair.presence` picks `RealtimeTransport` when

  `flarum/realtime` is detected, else `PollingTransport`; both expose the same API.
* **Providers:** `app.onair.providers` (JS) + the `StreamProvider` interface (PHP) are the

  extension points **OnAir+** plugs its RTMP/HLS provider into.

## License

MIT <span class="ipsEmoji">©</span> Ernestdefoe</code></pre>]]></description><guid isPermaLink="false">38</guid><pubDate>Sun, 07 Jun 2026 19:39:26 +0000</pubDate></item><item><title>Role Play &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/47-role-play-support-and-discussion/</link><description><![CDATA[<h1>Role-Play for Flarum</h1><p><strong>Play a character, post in-character, and run a card-based tactical game — right inside your Flarum discussions.</strong></p><p><a rel="" href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://flarum.org"><img src="https://img.shields.io/badge/Flarum-2.0%2B-orange.svg" alt="Flarum 2.0+" class="ipsRichText__align--block" loading="lazy"></a></p><p>Role-Play turns an ordinary Flarum forum into a home for tabletop-style play. Members create characters, write posts <em>as</em> those characters, and storytellers can run full turn-based combat encounters — with dice, cards, initiative and live HP bars — without anyone leaving the thread.</p><p>It touches <strong>no core tables</strong> (everything lives in its own <code>rp_*</code> tables) and is <strong>free and MIT-licensed</strong>.</p><p></p><hr><h2>Three features, one extension</h2><h3><span class="ipsEmoji" title="">🎭</span> Characters</h3><p>Members manage their cast at <code>/characters</code> ("My Characters" in the account menu): a name, an accent colour, an optional avatar and bio. Characters are yours; archive them any time and their old posts keep their identity.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/roleplay/master/images/characters.png" alt="My Characters page" class="ipsRichText__align--block" loading="lazy"></p><h3><span class="ipsEmoji" title="">💬</span> Post in-character</h3><p>When replying, pick <strong>"Post as …"</strong> in the composer and your reply is authored as that character — its coloured badge and name replace your own, with a quiet <em>"Played by you"</em> underneath so nothing is hidden. Perfect for narrative threads where several people each speak as their characters.</p><h3><span class="ipsEmoji" title="">⚔️</span> A tactical card game</h3><p>This is where Role-Play goes further than any other Flarum RP add-on. Build a <strong>deck</strong> of cards, then run <strong>encounters</strong> — turn-based fights that play out live in the discussion sidebar.</p><hr><h2>The deck builder</h2><p>At <code>/deck</code> ("My Deck" in the account menu) each member crafts cards — <strong>abilities, items, spells and enemies</strong> — each with dice formulas the game engine actually rolls:</p><ul><li><p><strong>Attack roll</strong> (e.g. <code>1d20+5</code>) — checked against the target's defense</p></li><li><p><strong>Damage roll</strong> (e.g. <code>3d6</code>) — applied on a hit, <strong>doubled on a natural-max crit</strong></p></li><li><p>Optional <strong>defense</strong>, <strong>HP</strong>, <strong>cost</strong>, a <strong>Font Awesome icon</strong>, and a description</p></li><li><p>Mark a card <strong>public</strong> to share it into everyone's deck</p></li></ul><p><img src="https://raw.githubusercontent.com/ernestdefoe/roleplay/master/images/deck.png" alt="The deck / card builder" class="ipsRichText__align--block" loading="lazy"></p><p>Dice expressions are validated server-side — a malformed formula is rejected, never silently ignored.</p><hr><h2>Running an encounter</h2><p>Any member can start an encounter inside a discussion and becomes its <strong>storyteller (GM)</strong>. From the tracker in the sidebar you:</p><ol><li><p><strong>Build the field</strong> — add party members and foes by hand, <strong>spawn a foe straight from an enemy card</strong> (its HP and defense seed automatically), and let players <strong>join with one of their own characters</strong>.</p></li><li><p><strong>Roll initiative &amp; start</strong> — every combatant rolls <code>1d20 + agility</code>; the tracker sorts them into turn order.</p></li><li><p><strong>Play it out</strong> — on each turn the active combatant <strong>plays a card at a target</strong>. The engine rolls to-hit vs. defense, rolls damage on a hit (×2 on a crit), and updates HP. A rolling <strong>action log</strong> narrates every play — hits, misses and crits.</p></li><li><p><strong>Advance</strong> until one side is down — a <strong>Victory / Defeat banner</strong> appears, and the GM ends the encounter.</p></li></ol><p>The tracker shows the initiative order, colour-coded HP bars (green party / red foes), the active turn, and adapts its controls to who's looking — the GM drives the fight; a player only acts on their own character's turn.</p><h3>Live for the whole table</h3><p>When <a rel="external nofollow" href="https://flarum.org">flarum/realtime</a> is installed, every play, turn and HP change is <strong>broadcast over WebSocket</strong> — the whole table sees the fight update instantly, no refresh. Without realtime, the tracker falls back to a lightweight poll, so it still stays in sync.</p><hr><h2>Installation</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum cache:clear```

That's it — the six `rp_*` tables are created automatically on enable. Then:

* Members find **My Characters** and **My Deck** in their account menu.
* Anyone can start an encounter from a discussion's sidebar.
* For instant multi-viewer combat, install and configure **flarum/realtime** (optional).

### Requirements

* Flarum **2.0+**
* PHP 8.1+
* *(Optional)* flarum/realtime for live updates

---

## How the dice work

The engine (`src/Game.php`) is a small, pure core:

| Step | Rule |

|------|------|

| **Dice** | Any `XdY+Z` expression, e.g. `2d6+1`, `1d20`, `3d8-2` |

| **Initiative** | `1d20 + agility`, highest goes first |

| **To-hit** | Attack total ≥ target defense (defense `0` = always hits) |

| **Crit** | A natural maximum on any attack die → **double damage** |

| **Down** | A combatant at `0` HP is out; turns skip them |

---

## Building from source

The PHP runs as-is; the front-end compiles with the Flarum webpack toolchain:

```cd js
npm install
npm run build```

---

## License

[MIT](https://github.com/ernestdefoe/roleplay/blob/master/LICENSE) <span class="ipsEmoji">©</span> Ernest Defoe. Free to use, fork and build on.</code></pre>]]></description><guid isPermaLink="false">47</guid><pubDate>Sun, 28 Jun 2026 18:39:24 +0000</pubDate></item><item><title>Advanced Cookie Consent &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/46-advanced-cookie-consent-support-and-discussion/</link><description><![CDATA[<h1>Advanced Cookie Consent</h1><p>A GDPR / ePrivacy-style <strong>cookie consent</strong> extension for <strong>Flarum 2</strong>. Free and MIT-licensed.</p><p>Shows a clean cookie notice with <strong>Accept / Reject / Customize</strong>, and a granular <strong>Privacy Settings</strong> dialog with consent categories and a per-service transparency view — and, crucially, it can <strong>gate third-party scripts so they only load after consent</strong>.</p><h2>Features</h2><ul><li><p><strong>Cookie notice banner</strong> (bottom bar, corner box, or centered) with Accept, Reject and Customize, plus your Privacy Notice link.</p></li><li><p><strong>Granular Privacy Settings modal</strong> — per-category toggles (Necessary is always on) with expandable detail, plus a <strong>Services</strong> tab listing the third-party services and cookies in each category.</p></li><li><p><strong>Script gating</strong> — two ways to ensure tags only run after consent:</p><ul><li><p>Paste scripts per category in the admin panel; they load when that category is accepted.</p></li><li><p>Mark any script on the page as <code>&lt;script type="text/plain" data-cc-category="marketing"&gt;…&lt;/script&gt;</code> and it activates on consent.</p></li></ul></li><li><p><strong>Admin-defined categories</strong> (rename, add, remove, mark required) — defaults: Necessary, Performance, Functional, Marketing.</p></li><li><p><strong>Consent versioning</strong> — bump the version to re-prompt everyone when your policy changes.</p></li><li><p><strong>Do Not Track / Global Privacy Control</strong> — optionally auto-reject non-essential categories when the browser sends an opt-out signal.</p></li><li><p><strong>Fully stylable</strong> — layout (bottom bar / corner box / centered), light / dark / auto theme, custom accent colour, box width and corner radius, so it fits any site and screen size.</p></li><li><p><strong>Reopen anytime</strong> — a "Cookie settings" link, plus a JS API so a theme can place its own trigger.</p></li><li><p>Fully translatable; consent is stored locally (no personal data leaves the browser).</p></li></ul><h2>Screenshots</h2><p>| Cookie notice | Privacy settings |</p><p>| --- | --- |</p><p>| <img src="https://raw.githubusercontent.com/ernestdefoe/advanced-cookie-consent/main/screenshots/banner.png" alt="Cookie notice banner" class="ipsRichText__align--block" loading="lazy"> | <img src="https://raw.githubusercontent.com/ernestdefoe/advanced-cookie-consent/main/screenshots/settings.png" alt="Privacy settings modal" class="ipsRichText__align--block" loading="lazy"> |</p><p>Fully <strong>stylable</strong> so it fits any forum — choose the layout (bottom bar / corner box / centered), a light/dark/auto theme, your own accent colour, box width and corner radius:</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/advanced-cookie-consent/main/screenshots/styled.png" alt="Styled corner box, dark theme, custom accent" class="ipsRichText__align--block" loading="lazy"></p><h2>JavaScript API</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
window.cookieConsent.accepted('marketing'); // boolean
window.cookieConsent.onChange((c) =&gt; { /* … */ });
window.cookieConsent.acceptAll();
window.cookieConsent.rejectAll();```

## Installation

```composer require ernestdefoe/advanced-cookie-consent
php flarum cache:clear```

Then open **Admin → Advanced Cookie Consent** to set your text, categories and scripts.

## License

[MIT](https://github.com/ernestdefoe/advanced-cookie-consent/blob/main/LICENSE)</code></pre>]]></description><guid isPermaLink="false">46</guid><pubDate>Sun, 28 Jun 2026 18:38:48 +0000</pubDate></item><item><title>Google Fonts &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/36-google-fonts-support-and-discussion/</link><description><![CDATA[<h1>Google Fonts for Flarum</h1><p><a rel="external nofollow" href="https://github.com/ernestdefoe/google-fonts/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://packagist.org/packages/ernestdefoe/google-fonts"><img src="https://img.shields.io/packagist/v/ernestdefoe/google-fonts.svg" alt="Latest Stable Version" class="ipsRichText__align--block" loading="lazy"></a></p><p>Use <strong>any Google Font</strong> on your Flarum 2 forum. Pick a body font and a heading</p><p>font from the full Google Fonts library — applied site-wide, with a live preview</p><p>right in the admin panel.</p><h2>Features</h2><ul><li><p><span class="ipsEmoji" title="">🔎</span> <strong>Searchable picker</strong> for a curated list of popular Google Fonts, in the</p><p>admin settings — and you can type/paste <strong>any</strong> Google Font family name, even</p><p>ones not in the list.</p></li><li><p><span class="ipsEmoji" title="">✍</span>️ <strong>Separate body and heading fonts</strong>, so you can pair (e.g.) <em>Inter</em> body</p><p>text with <em>Playfair Display</em> headings.</p></li><li><p><span class="ipsEmoji" title="">👀</span> <strong>Live preview</strong> of each font directly in the admin panel.</p></li><li><p><span class="ipsEmoji" title="">⚡</span> <strong>Server-side injection</strong> of the Google Fonts stylesheet into the page</p><p><code>&lt;head&gt;</code> — no flash of unstyled text, no client round-trip.</p></li><li><p><span class="ipsEmoji" title="">🪶</span> No configuration files, no API key required.</p></li></ul><h2>Installation</h2><p><code>composer require ernestdefoe/google-fonts</code></p><p>Then enable <strong>Google Fonts</strong> in your admin panel.</p><h2>Usage</h2><ol><li><p>Go to <strong>Admin → Google Fonts</strong>.</p></li><li><p>Set a <strong>Body font</strong> and (optionally) a <strong>Heading font</strong>.</p></li><li><p>Start typing to search, or paste an exact family name from</p><p><a rel="external nofollow" href="https://fonts.google.com">fonts.google.com</a>.</p></li><li><p>Click <strong>Save</strong>. The fonts apply to your forum immediately.</p></li></ol><p>Leave a field blank to fall back to your theme's default font.</p><h2>Updating</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum cache:clear```

## License

[MIT](https://github.com/ernestdefoe/google-fonts/blob/main/LICENSE)</code></pre>]]></description><guid isPermaLink="false">36</guid><pubDate>Sun, 07 Jun 2026 01:17:56 +0000</pubDate></item><item><title>ESPN CFB Ticker &#x2014; Flarum 2 Extension</title><link>https://ernestdefoe.online/forums/topic/5-espn-cfb-ticker-flarum-2-extension/</link><description><![CDATA[<h1>ESPN CFB Ticker — Flarum 2 Extension</h1><p><a rel="" href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT" class="ipsRichText__align--block" loading="lazy"></a></p><p><a rel="external nofollow" href="https://flarum.org"><img src="https://img.shields.io/badge/Flarum-2.x-blue" alt="Flarum" class="ipsRichText__align--block" loading="lazy"></a></p><p>A live <strong>FBS college football</strong> scores ticker for <a rel="external nofollow" href="https://flarum.org">Flarum 2</a> forums, powered by the free public ESPN API. Scores scroll automatically across a sticky banner at the top (or bottom) of your forum, updating on a configurable interval.</p><hr><h2>Features</h2><ul><li><p><span class="ipsEmoji" title="">🏈</span> <strong>FBS-only</strong> — filters ESPN's API to Group 80 (NCAA Division I FBS)</p></li><li><p><span class="ipsEmoji" title="">📡</span> <strong>Live scores</strong> with a pulsing green dot for in-progress games</p></li><li><p><span class="ipsEmoji" title="">🏆</span> <strong>AP/Coaches rankings</strong> — shows <code>#N</code> next to ranked teams (Top 25)</p></li><li><p><span class="ipsEmoji" title="">🖼️</span> <strong>Team logos</strong> pulled directly from ESPN's CDN</p></li><li><p><span class="ipsEmoji" title="">⚙️</span> <strong>Admin settings</strong> — toggle on/off, top/bottom position, refresh interval, scroll speed</p></li><li><p><span class="ipsEmoji" title="">📱</span> <strong>Responsive</strong> — logos hidden on narrow screens to keep ticker readable</p></li><li><p><span class="ipsEmoji" title="">🔁</span> <strong>Seamless loop</strong> — CSS-only marquee with no layout jank</p></li><li><p><span class="ipsEmoji" title="">♻️</span> <strong>Auto-refresh</strong> — polls ESPN API on a configurable interval (default 60s)</p></li></ul><hr><h2>Requirements</h2><ul><li><p><strong>Flarum</strong> <code>^2.0</code></p></li><li><p><strong>PHP</strong> <code>^8.3</code></p></li><li><p>No external PHP dependencies</p></li></ul><hr><h2>Installation</h2><p><code>composer require ernestdefoe/espn-cfb-ticker</code></p><p>Then enable the extension in your Flarum admin panel under <strong>Extensions</strong>.</p><hr><h2>Building JavaScript</h2><p>If you're contributing or modifying the extension:</p><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
npm install
npm run build   # production build
npm run dev     # watch mode```

---

## Admin Settings

| Setting | Default | Description |

|---|---|---|

| Enable Ticker | `true` | Show/hide the ticker sitewide |

| Position | `top` | Sticky top or fixed bottom |

| Refresh Interval | `60` seconds | How often to poll ESPN API (min 15s) |

| Scroll Speed | `40` | Per-game animation multiplier (lower = faster) |

---

## How It Works

1. On page load the extension mounts a Mithril component outside Flarum's main app node.
2. The component `fetch()`es `https://site.api.espn.com/apis/site/v2/sports/football/college-football/scoreboard?groups=80&amp;limit=50` — the public ESPN API, no key required.
3. Games are rendered in a CSS `@keyframes` scroll animation. The track is duplicated so the loop is seamless.
4. A `setInterval` re-fetches on the configured interval, causing a Mithril redraw.

---

## ESPN API Notes

The ESPN public scoreboard API (`site.api.espn.com`) is unofficial and undocumented but has been widely used by developers for years. It requires no API key and returns JSON. The `groups=80` parameter restricts results to FBS schools.

---

## License

[MIT](https://github.com/ernestdefoe/espn-cfb-ticker/blob/main/LICENSE) <span class="ipsEmoji">©</span> 2026 ernestdefoe

&lt;https://ernestdefoe.online/extension/ernestdefoe/espn-cfb-ticker&gt;</code></pre>]]></description><guid isPermaLink="false">5</guid><pubDate>Sun, 17 May 2026 16:31:37 +0000</pubDate></item><item><title>Theme Toggle &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/13-theme-toggle-support-and-discussion/</link><description><![CDATA[<h1>Theme Toggle</h1><p>A small, theme-agnostic day/night/system picker for the Flarum 2 header. Drops into any Flarum 2 theme that respects the native <code>&lt;html data-theme="…"&gt;</code> signal (every theme that ships with or extends Flarum 2 does, including the default).</p><p><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License" class="ipsRichText__align--block" loading="lazy"></p><p><img src="https://img.shields.io/badge/Flarum-%5E2.0-orange.svg" alt="Flarum" class="ipsRichText__align--block" loading="lazy"></p><p><img src="https://img.shields.io/badge/PHP-%5E8.3-777bb4.svg" alt="PHP" class="ipsRichText__align--block" loading="lazy"></p><p><img src="https://img.shields.io/badge/TypeScript-strict-3178c6.svg" alt="TypeScript" class="ipsRichText__align--block" loading="lazy"></p><h2>Screenshots</h2><h3>Desktop — header button</h3><p>A compact icon button next to Search / Sign Up / Log In. The icon reflects the active choice (☾ dark, <span class="ipsEmoji" title="">☀</span> light, ◐ system).</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/theme-toggle/main/screenshots/desktop-header.png" alt="Desktop header" class="ipsRichText__align--block" loading="lazy"></p><h3>Desktop — dropdown open</h3><p>Five choices, each with a matching icon. The active choice is marked with a checkmark.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/theme-toggle/main/screenshots/desktop-dropdown.png" alt="Desktop dropdown" class="ipsRichText__align--block" loading="lazy"></p><h3>Mobile — slide-out drawer</h3><p>On phone-width viewports Flarum re-renders <code>HeaderSecondary</code> inside <code>.App-drawer</code>. The button switches to a labeled, full-width menu row so it lines up with Search / Sign Up / Log In.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/theme-toggle/main/screenshots/mobile-drawer.png" alt="Mobile drawer" class="ipsRichText__align--block" loading="lazy"></p><h2>Features</h2><ul><li><p><strong>Five choices.</strong> Dark, Dark (high contrast), Light, Light (high contrast), System.</p></li><li><p><strong>Native Flarum 2 signal.</strong> The extension only flips <code>&lt;html data-theme="…"&gt;</code> and <code>localStorage</code> — no theme-specific CSS, so it composes with any well-behaved Flarum 2 theme (default, <a rel="external nofollow" href="https://github.com/ernestdefoe/aurora">Aurora</a>, or any third-party theme).</p></li><li><p><strong>System mode honours OS preferences.</strong> When System is active, the theme follows <code>prefers-color-scheme</code> for light/dark and <code>prefers-contrast: more</code> for the <code>-hc</code> variants — so an accessibility user with macOS / Windows "Increase contrast" turned on automatically gets the right palette.</p></li><li><p><strong>Live OS updates.</strong> Changes to the OS theme or contrast preference are picked up immediately while the tab is open, with no reload.</p></li><li><p><strong>Persists per visitor.</strong> Your choice is stored in <code>localStorage</code> under <code>ernestdefoe-theme-toggle.choice</code> and re-applied on every page load before paint, so there's no FOUC.</p></li><li><p><strong>Respects the admin default.</strong> Until a visitor explicitly picks a choice, Flarum's <strong>Admin → Appearance → Color Scheme</strong> setting is left untouched.</p></li><li><p><strong>Mobile-aware UI.</strong> Renders as a compact icon button in the desktop header and as a labeled <code>"◐ Theme"</code> row inside the mobile slide-out drawer (where icon-only buttons would float disconnected from the surrounding Sign Up / Log In rows).</p></li><li><p><strong>Localized.</strong> All visible strings come from <code>locale/en.yml</code> and can be overridden in your forum's locale files.</p></li><li><p><strong>TypeScript end-to-end.</strong> Sources are authored in TypeScript and type-checked against Flarum core's bundled <code>.d.ts</code> files. <code>npm run check-typings</code> runs <code>tsc --noEmit</code>.</p></li></ul><h2>Compatibility</h2><ul><li><p>Flarum core <code>^2.0</code></p></li><li><p>PHP <code>^8.3</code></p></li><li><p>Pairs with any theme. Tested with the default theme and the Aurora theme.</p></li></ul><h2>Install</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
php flarum cache:clear```

Then enable **Theme Toggle** from the admin panel's Extensions page.

## Development

```cd js
npm install
npm run build           # production bundle (writes js/dist/forum.js)
npm run dev             # watch mode for development
npm run check-typings   # tsc --noEmit, requires `composer install` at repo root first```

The TypeScript path mapping in `js/tsconfig.json` points at `../vendor/flarum/core/js/dist-typings/`, so `composer install` at the repo root must run before `check-typings` can resolve `flarum/*` imports.

### Project layout

```extend.php                                Flarum extension bootstrap
composer.json                             Package manifest
locale/en.yml                             User-facing strings
less/forum.less                           Header + drawer styling
js/
  forum.ts                                Webpack entry point
  tsconfig.json                           Extends flarum-tsconfig
  src/forum/
    index.ts                              Initializer + HeaderSecondary hook
    theme.ts                              Choice/storage helpers + media listener
    components/ThemeToggle.tsx            The Dropdown component
  dist/forum.js                           Compiled bundle (committed)
screenshots/                              Images in this README```

## How it works

Flarum 2 ships four `data-theme` values: `light`, `light-hc`, `dark`, and `dark-hc`. Themes are expected to define their dark tokens as the default and their light tokens under `[data-theme^='light']`, with a high-contrast layer under `[data-theme^='light-hc']` / `[data-theme^='dark-hc']`. Because those selectors use `^=` (prefix match), setting `data-theme="light-hc"` activates *both* the regular light palette and its HC overrides via the cascade.

This extension just sets that attribute client-side:

* On boot, `theme.ts` reads the saved choice from `localStorage` and writes the corresponding string to `&lt;html data-theme="…"&gt;` **before** the initializer runs, so the page never paints in the wrong palette.
* The `ThemeToggle` component reads the same choice for its icon and dropdown state.
* When the user picks a new option, the choice is written to `localStorage`, `&lt;html&gt;` is updated, and Mithril redraws the button.
* In System mode, a `matchMedia` listener for `prefers-color-scheme` and `prefers-contrast: more` re-applies the choice live.

No theme-specific CSS, no setting payload, no server round-trip.

## Translations

Override any string by adding the matching key under `ernestdefoe-theme-toggle.forum.toggle.*` in your forum's locale file:

| Key                       | Default                  |

| ------------------------- | ------------------------ |

| `label`                   | `Theme`                  |

| `option_dark`             | `Dark`                   |

| `option_dark_hc`          | `Dark (high contrast)`   |

| `option_light`            | `Light`                  |

| `option_light_hc`         | `Light (high contrast)`  |

| `option_system`           | `System`                 |

## License

[MIT](https://github.com/ernestdefoe/theme-toggle/blob/main/LICENSE) <span class="ipsEmoji">©</span> Ernest Defoe</code></pre>]]></description><guid isPermaLink="false">13</guid><pubDate>Wed, 20 May 2026 15:21:57 +0000</pubDate></item><item><title>Aurora &#x2014; support and discussion</title><link>https://ernestdefoe.online/forums/topic/14-aurora-support-and-discussion/</link><description><![CDATA[<h1>Aurora Theme for Flarum</h1><p>An aurora-inspired theme for <a rel="external nofollow" href="https://flarum.org/">Flarum</a> featuring animated</p><p>gradient backdrops, glassmorphic panels, glowing accents, and a dark night-sky</p><p>palette.</p><p><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License" class="ipsRichText__align--block" loading="lazy"></p><p><img src="https://img.shields.io/badge/Flarum-%5E2.0-orange.svg" alt="Flarum" class="ipsRichText__align--block" loading="lazy"></p><p><img src="https://img.shields.io/badge/PHP-%5E8.3-777bb4.svg" alt="PHP" class="ipsRichText__align--block" loading="lazy"></p><p><strong>Flarum 1.x users:</strong> this branch targets Flarum 2.0. For Flarum 1.8.x see the</p><p><code>1.x</code> branch.</p><h2>Screenshots</h2><h3>Forum index</h3><p>Animated aurora backdrop, glassmorphic discussion cards, gradient text on unread titles,</p><p>a glowing pill for unread counts, stat widgets inside the welcome hero, and the</p><p>user-facing palette picker popover (shown open).</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/aurora/main/screenshots/forum-index.png" alt="Forum index" class="ipsRichText__align--block" loading="lazy"></p><h3>Discussion view</h3><p>Glassy posts with gradient usernames, accent-bordered blockquotes, themed inline code</p><p>and code blocks, and gradient-glow avatars.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/aurora/main/screenshots/discussion.png" alt="Discussion view" class="ipsRichText__align--block" loading="lazy"></p><h3>Admin settings</h3><p>Live color swatches, a gradient preview, and toggles for glassmorphism, glow, and</p><p>background animation.</p><p><img src="https://raw.githubusercontent.com/ernestdefoe/aurora/main/screenshots/admin-settings.png" alt="Admin settings" class="ipsRichText__align--block" loading="lazy"></p><h2>Highlights</h2><ul><li><p><strong>Animated aurora backdrop</strong> — drifting radial gradients in violet, cyan,</p><p>teal, pink, and magenta on a deep night-sky base.</p></li><li><p><strong>User palette picker</strong> — a circular gradient button in the header opens a</p><p>popover with six presets (Aurora, Sunset, Ocean, Forest, Nebula, Ember).</p><p>Choice persists per-visitor via <code>localStorage</code> and applies instantly.</p></li><li><p><strong>Hero widgets</strong> — Members, Discussions, Posts, and Online-now stat tiles</p><p>embedded inside the welcome hero, with live trend lines.</p></li><li><p><strong>Glassmorphic surfaces</strong> — frosted header, sidebar, discussion cards,</p><p>composer, modals, and dropdowns.</p></li><li><p><strong>Gradient buttons &amp; badges</strong> — primary buttons shimmer; unread counts pulse</p><p>with a cool glow.</p></li><li><p><strong>Glowing avatars &amp; focus rings</strong> — soft cyan/pink halos on hover and focus.</p></li><li><p><strong>Gradient scrollbar &amp; text</strong> — gradient-clipped headings, usernames, and</p><p>scrollbar thumb.</p></li><li><p><strong>Configurable</strong> — admin settings for gradient colors, accent color, and</p><p>toggles for glassmorphism, glow, and background animation.</p></li><li><p><strong>Accessible</strong> — honors <code>prefers-reduced-motion</code>, visible focus rings.</p></li></ul><h2>Palette presets</h2><p>| Preset | Gradient |</p><p>| ------- | -------------------------------------------------------- |</p><p>| Aurora | <code>#7c3aed</code> → <code>#4f46e5</code> → <code>#22d3ee</code> → <code>#14b8a6</code> <em>(default)</em> |</p><p>| Sunset | <code>#f97316</code> → <code>#f43f5e</code> → <code>#d946ef</code> → <code>#7c3aed</code> |</p><p>| Ocean | <code>#1e40af</code> → <code>#3b82f6</code> → <code>#06b6d4</code> → <code>#22d3ee</code> |</p><p>| Forest | <code>#15803d</code> → <code>#10b981</code> → <code>#22d3ee</code> → <code>#0ea5e9</code> |</p><p>| Nebula | <code>#a855f7</code> → <code>#d946ef</code> → <code>#6366f1</code> → <code>#3b82f6</code> |</p><p>| Ember | <code>#b91c1c</code> → <code>#ea580c</code> → <code>#f59e0b</code> → <code>#fbbf24</code> |</p><p>Add or override a preset by extending <code>PALETTES</code> in <code>js/src/forum/palettes.js</code>.</p><h2>Installation</h2><p><code>composer require ernestdefoe/aurora</code></p><p>Then enable <strong>Aurora Theme</strong> under <strong>Admin → Extensions</strong>.</p><h2>Configuration</h2><p>Open <strong>Admin → Extensions → Aurora Theme</strong> to customize:</p><p>| Setting | Default | Description |</p><p>| --- | --- | --- |</p><p>| Primary gradient — start | <code>#7c3aed</code> | First color of the primary gradient. |</p><p>| Primary gradient — end | <code>#22d3ee</code> | Last color of the primary gradient. |</p><p>| Accent color | <code>#f472b6</code> | Warm accent used for hover halos. |</p><p>| Enable glassmorphism | <code>on</code> | Frosted-glass panels with backdrop blur. |</p><p>| Enable glow effects | <code>on</code> | Soft glows on hover, focus, and unread items. |</p><p>| Animate aurora background | <code>on</code> | Drifting gradient blobs in the backdrop. |</p><h2>Development</h2><pre spellcheck="" class="ipsCode language-plaintext" data-language="Plain Text"><code>
cd aurora/js
npm install
npm run build      # production bundle
npm run dev        # watch mode```

### Project layout

```extend.php              Flarum extension bootstrap
composer.json           Package manifest
less/
  forum.less            Forum-facing styles
  admin.less            Admin-facing styles
  variables.less        Color palette, radii, easings
  mixins.less           .aurora-glass, .aurora-text-gradient, ...
  animations.less       drift, shimmer, pulse, float, fade-up
js/
  forum.js, admin.js          Webpack entry points
  src/forum/index.js          Frontend bootstrap: settings, scroll header, ripple
  src/forum/palettes.js       Palette presets + apply/load/store helpers
  src/forum/palette-picker.js Header button + popover injection
  src/forum/hero-widgets.js   Welcome-hero stat tiles
  src/admin/index.js          Admin entrypoint (re-exports extend)
  src/admin/extend.js         Flarum 2 Admin extender — settings registry
  dist/                       Compiled bundles (committed)
resources/locale/
  en.yml                English admin strings```

## Compatibility

* Flarum core `^2.0.0-beta` (built against `2.0.0-rc.1`)
* PHP `^8.3`
* Modern browsers with `backdrop-filter` support. Older browsers gracefully

  degrade to solid dark surfaces.

Need Flarum 1.x? Switch to the `1.x`

branch — it targets `flarum/core ^1.8.0` and uses the legacy `app.extensionData`

settings API.

## License

[MIT](https://github.com/ernestdefoe/aurora/blob/main/LICENSE) <span class="ipsEmoji">©</span> Ernest Defoe</code></pre>]]></description><guid isPermaLink="false">14</guid><pubDate>Thu, 21 May 2026 02:33:52 +0000</pubDate></item></channel></rss>
