a1dbc2ea34
Records brainstorming findings: Snow Fall block vocabulary, 15 options evaluated, Admin2 JS injection blocker, Grav vs Keystatic comparison. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WPJztrVGbwic2xTG7G9fjM
175 lines
8.7 KiB
Markdown
175 lines
8.7 KiB
Markdown
# Story Editing Research
|
||
|
||
Brainstorming session — 2026-06-20. Notes on options for improving the story editing
|
||
experience in Admin2. Not a plan — a reference to revisit once real story writing reveals
|
||
what actually matters.
|
||
|
||
---
|
||
|
||
## The core problem
|
||
|
||
Stories use shortcode syntax (`[scrolly-section image="x.jpg"]…[/scrolly-section]`) authored
|
||
in a single big markdown textarea in Admin2. Three pain points, roughly equal weight:
|
||
|
||
1. **Fragile syntax** — easy to typo a shortcode and get no useful error
|
||
2. **Writing blind** — no preview while editing; you don't see the result until you view the page
|
||
3. **Mobile unusable** — Admin2 is desktop-focused; the markdown textarea on a phone is painful
|
||
|
||
---
|
||
|
||
## What Keystatic / Sanity / Shorthand taught us
|
||
|
||
All three tools represent content as a **typed, ordered list of blocks** — not a text string.
|
||
|
||
In Keystatic the editing flow is: write prose normally → click "+" → pick a block type from a
|
||
list → fill in a form with labelled fields → the block appears as an opaque card in the editor.
|
||
Authors never see markup. Each block type (hero, gallery, scrolly section) has a typed schema
|
||
(image picker, text fields, selects). Sanity's Portable Text uses the same model. Shorthand
|
||
(used by BBC, Reuters, National Geographic) is a purpose-built CMS for exactly this kind of
|
||
immersive storytelling — their section vocabulary is the best reference for what block types
|
||
matter in practice.
|
||
|
||
**Key insight:** the gap between Grav and these tools is entirely on the authoring side.
|
||
Grav's rendering (Twig templates, shortcodes, parallax effects) is perfectly capable.
|
||
The problem is that Admin2 was not designed for structured block content authoring.
|
||
|
||
---
|
||
|
||
## Snow Fall block vocabulary
|
||
|
||
The canonical block types that appear across all immersive storytelling platforms:
|
||
|
||
| Block | What it does | Fields |
|
||
|---|---|---|
|
||
| **Hero** | Full-bleed opening image/video + title. Chapter opener. | image, headline, subtitle, text position, animation (static / ken-burns) |
|
||
| **Narrative text** | Prose reading column. The writing block. | body (markdown) |
|
||
| **Full-bleed media** | Single image/video edge-to-edge, no text. Visual pause. | image, caption, credit |
|
||
| **Image + caption** | Photo at configurable width with caption below. | image, caption, credit, width (column / full / bleed) |
|
||
| **Scrollytelling** | Text panels scroll over a fixed or animated background. | background image, panels (each: headline + body) |
|
||
| **Photo gallery** | Multi-image carousel/grid → lightbox. | images (each: file + caption + credit) |
|
||
| **Pull quote** | Typographically large extracted quote. | quote text, attribution, optional background |
|
||
| **Chapter break** | Major section transition with background image. | image, title, chapter number |
|
||
| **Grid / side-by-side** | 2–3 column photo+text pairs. | columns array |
|
||
| **Embed** | YouTube, Vimeo, audio, map. | URL, caption |
|
||
|
||
Current Grav shortcodes cover: hero (ken-burns), scrollytelling (scrolly-section), gallery
|
||
(snap-gallery), pull-quote, chapter-break. Missing from the vocabulary: narrative text as an
|
||
explicit block, full-bleed media, image+caption, grid, embed.
|
||
|
||
---
|
||
|
||
## The two fundamental approaches
|
||
|
||
### A — Blueprint-as-blocks (no shortcodes)
|
||
|
||
Replace the markdown body with a `list` field in the story blueprint. Each list item is a
|
||
block with a `type` selector + type-specific sub-fields. Content lives in frontmatter YAML;
|
||
the Twig template loops over blocks and renders each one with the right partial. No shortcode
|
||
syntax at all.
|
||
|
||
**Solves all three pain points.** Admin2 form fields are mobile-reasonable. Structure is
|
||
explicit and impossible to mis-type.
|
||
|
||
**One limitation:** Grav's native `list` field doesn't hide/show fields based on the selected
|
||
type. Every block card shows ALL fields for ALL block types; the template ignores the unused
|
||
ones. It's visually cluttered but functionally correct. This is a solvable UX problem (Grav
|
||
roadmap, or a future Admin2 extension) — the data model stays the same when it improves.
|
||
|
||
### B — Enhanced markdown (keep shortcodes, improve authoring UX)
|
||
|
||
Keep the markdown textarea; add tooling on top to reduce friction. Multiple options here
|
||
(see section below), but all hit an architectural constraint: Admin2 serves its SPA via
|
||
`echo $html; exit` which bypasses Grav's entire output pipeline. Standard plugin hooks
|
||
for injecting assets don't fire in Admin2. Any JS-based editor enhancement requires either
|
||
a fragile output-buffering hack or patching Admin2's pre-built `app/index.html` directly.
|
||
|
||
---
|
||
|
||
## 15 options researched
|
||
|
||
### Options that work natively (no Admin2 hacking required)
|
||
|
||
**1. Blueprint-as-blocks** — structured YAML fields per block, native Admin2 form rendering.
|
||
Best long-term solution for non-technical story editing and mobile. Medium effort (blueprint
|
||
YAML + Twig template rework). The field-clutter limitation is real but acceptable.
|
||
|
||
**2. page-inject sub-pages** — each story block is a standalone Grav sub-page; the parent
|
||
story injects them in sequence via `[plugin:page-inject]`. Editing = opening sub-pages
|
||
individually. More flexible than blueprint-as-blocks for reusable content but creates
|
||
more pages to manage and Admin2 navigation friction.
|
||
|
||
**3. New shortcodes via YAML + Twig** — shortcode-core supports YAML-configured Twig
|
||
shortcodes out of the box (`shortcode-core.yaml` + a Twig file in the theme). No plugin
|
||
needed. Used to add `full-bleed` and `image-caption` to the story-blocks plugin.
|
||
|
||
**4. Obsidian + Gitea git sync** — write stories in Obsidian on desktop or mobile with
|
||
snippet templates for shortcodes. Push to Gitea; webhook deploys to production. Zero dev
|
||
work. Good mobile writing experience. No image upload from mobile; requires comfort with git.
|
||
|
||
**5. `/story-editor` custom page** — a purpose-built page (like `/gpx-manager`) that presents
|
||
story blocks as drag-reorderable cards with typed forms, talks to the Grav API, designed
|
||
mobile-first. Highest effort; best mobile result. Would use the "one custom plugin" slot.
|
||
|
||
### Options blocked by Admin2's architecture
|
||
|
||
All of these require injecting JavaScript or CSS into Admin2 pages, which is architecturally
|
||
blocked (Admin2 bypasses Grav's output pipeline with `echo $html; exit`):
|
||
|
||
- EasyMDE / SimpleMDE drop-in (split-pane markdown preview)
|
||
- CodeMirror 6 autocomplete + syntax highlighting for shortcodes
|
||
- Toast UI Editor (WYSIWYG ↔ markdown toggle)
|
||
- Tiptap custom shortcode nodes
|
||
- Milkdown
|
||
- Slash-command / shortcode palette
|
||
- Toolbar-at-bottom CSS (mobile improvement)
|
||
- Web Speech API dictation button
|
||
|
||
**Workaround:** patch Admin2's pre-built `app/index.html` directly. Survives until the next
|
||
Admin2 update; a `make patch-admin2` command would re-apply it. Viable for a personal blog
|
||
but adds a maintenance step.
|
||
|
||
### Paid option
|
||
|
||
**Grav Editor Pro ($75)** — TipTap/ProseMirror-based WYSIWYM editor, confirmed Admin2-
|
||
compatible (listed as an optional dependency in the Admin2 README ≥ v2.0.1). When paired
|
||
with shortcode-core, shortcodes appear as visual green blocks with a modal form per type.
|
||
This is the cleanest story editing experience available without building it yourself. Ruled
|
||
out based on preference to avoid paid tools.
|
||
|
||
---
|
||
|
||
## Honest CMS comparison: Grav vs Keystatic for storytelling
|
||
|
||
**Wrong conclusion:** Grav can't do Snow Fall storytelling.
|
||
|
||
**Right conclusion:** Grav's rendering side (parallax, scrollytelling, ken-burns, galleries)
|
||
is fully capable. The authoring experience for structured block content is the genuine weak
|
||
point — and the options to improve it cleanly within Admin2 are limited.
|
||
|
||
Keystatic + a modern frontend (Astro, Next.js) would give a better editorial experience for
|
||
story authoring, but at the cost of migrating away from Grav and building a separate frontend.
|
||
For a solo travel blogger who is the only author, Grav with an improved shortcode setup or
|
||
blueprint-as-blocks is good enough. Keystatic's advantage is significant for publications with
|
||
multiple non-technical editors writing daily.
|
||
|
||
---
|
||
|
||
## What was actually done (2026-06-20)
|
||
|
||
- Added `full-bleed` shortcode to `story-blocks` plugin (PHP class + CSS)
|
||
- Added `image-caption` shortcode to `story-blocks` plugin (PHP class + CSS), with
|
||
`width` parameter: `column` (default) / `full` / `bleed`
|
||
- Next step when ready to revisit: write some actual stories, then decide whether
|
||
blueprint-as-blocks or the app/index.html patch route is worth pursuing
|
||
|
||
---
|
||
|
||
## References
|
||
|
||
- [Keystatic content components](https://keystatic.com/docs/content-components)
|
||
- [Sanity Portable Text](https://www.sanity.io/docs/portable-text)
|
||
- [Shorthand storytelling sections](https://shorthand.com/features/sections/)
|
||
- [Grav Editor Pro](https://getgrav.org/premium/editor-pro)
|
||
- [Admin2 GitHub](https://github.com/getgrav/grav-plugin-admin2)
|
||
- [shortcode-core](https://github.com/getgrav/grav-plugin-shortcode-core)
|