Build Readymag
KINDAreplaces $20/mosaves $240/yrback to the verdict
A page builder for editorial sites whose hard problems are a layout model that survives a phone screen, publishing deterministic static output with no runtime dependency, and motion that a reader can switch off.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the editor and the publish step.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - have readyfree tiers are common, otherwise pennies
Why The output has no runtime, so hosting it is genuinely just a folder, and proving that on a real host is the test that the rule zero claim is true.
Get it Any static host, an object store with website serving, or a small machine with a web server.
Verify
The published folder is served and every page loads with the builder switched off - have readya few pounds a year, certificates free
Why An editorial site lives at a name people type, and certificate renewal is the operational chore that comes with owning the publishing rather than renting it.
Get it Any registrar, with automatic certificates from your host or a certificate client on your own machine.
Verify
The site loads over TLS at the name and renewal is automated - have readyfree for open families, otherwise per licence
Why Web font licences differ sharply on self-hosting and the publish step refuses a font whose licence note is empty, which is deliberate.
Get it Open licence families, or a licence that explicitly permits self-hosting.
Verify
Each font file has a licence note recorded and the publish succeeds - decidefree
Why Every layout row, every preview and every publish check is defined against this list, and adding one later means revisiting every section on every page.
Get it Pick two or three widths and write them into the configuration before building a page.
Verify
The list is in the configuration and the editor opens at the narrowest
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- sites(id, name, base_path, default_locale, created_at) - pages(id, site_id, slug, title, description, ordinal, published_version_id) · slug is the URL and is validated once, at creation - sections(id, page_id, ordinal, kind, content_json) · kind is a small closed set: cover, text, gallery, quote, embed - layouts(section_id, breakpoint, layout_json) · one row per breakpoint, so the narrow view is data rather than an accident - assets(id, site_id, path, kind, bytes, width, height, sha256, licence_note) · images and fonts, with the licence written down at upload - publishes(id, site_id, version, output_path, started_at, finished_at, file_count, bytes, status) · every publish kept, so rolling back is a directory swap - motion(section_id, effect, duration_ms, reduced_alternative) · every effect names what it does when motion is reduced, or it cannot be saved
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DATABASE_PATH | required | ./data/site.db | Pages, sections, layouts. Half of what you back up. |
ASSETS_DIR | required | ./data/assets | Images and fonts with their licence notes. The other half. |
OUTPUT_ROOT | required | ./out | One directory per publish version, with a pointer to the live one. |
PUBLISH_KEEP_VERSIONS | required | 5 | How many publishes to retain. Rollback is a swap between these. |
BREAKPOINTS | required | 360,768,1280 | The narrowest is the one the editor opens at and the one publish requires. |
IMAGE_WIDTHS | required | 480,960,1920 | Generated at upload, emitted as a source set. |
EDITOR_BIND | required | 127.0.0.1:3000 | Localhost. The editor is never part of the published site. |
The build, in order
Sections, not coordinates
A page is an ordered list of sections whose layout is defined per breakpoint.
An open set becomes a component library and then becomes your whole weekend.
Files
src/model/sections.tsPer-breakpoint rows make the narrow view a thing you can require.
Files
src/model/layouts.tsPeople design what they look at first.
Files
src/editor/Canvas.tsx
done when · tick each as it passeswatch out- Storing an absolute position for every element is what makes a freeform editor feel good for an afternoon and produces a site that is unreadable on a phone, which is where most of the traffic will come from. Store a layout per breakpoint, require the narrow one to be set before a page can publish, and refuse to publish a page whose narrow layout has never been looked at.
Publishing a folder that needs nothing
A publish writes static files that render with the builder switched off.
A half-published site is worse than an old one.
Files
src/publish/build.tstest/interrupt.test.tsCheap, mechanical, and it catches every slug typo before a reader does.
Files
src/publish/verify.tsByte identical output turns a diff into a review.
Files
src/publish/render.ts
done when · tick each as it passeswatch out- Writing the output over the live folder page by page means a publish that fails halfway leaves a site that is half the new version and half the old one, with broken links between the two, and it happens at exactly the moment somebody is sharing the link. Build into a temporary directory, verify the file count and the internal links, then swap.
Type and pictures that do not shift the page
Fonts are self-hosted with a recorded licence and images ship at sensible sizes with known dimensions.
Doing it at publish time makes every publish slow instead of one upload.
Files
src/assets/images.tsThe one line that stops the page jumping under the reader's thumb.
Files
src/publish/render.tsFonts are the asset most often used without permission, and it is the operator who is liable.
Files
src/assets/fonts.ts
done when · tick each as it passeswatch out- Shipping the original camera image and letting the browser scale it sends several megabytes to a phone for a picture displayed at four hundred pixels, and omitting the intrinsic dimensions makes the text jump down the page while each one loads. Generate widths at upload, emit the source set, and always write the dimensions.
Motion a reader can switch off
Every effect has a defined reduced-motion behaviour and nothing moves for longer than the reader allows.
A required field is the only version of this that survives a deadline.
Files
src/model/motion.tstest/motion.test.tsThe reader's own setting does the work; you just have to honour it.
Files
src/publish/css.tsAuthors design for what they can see.
Files
src/editor/MotionPanel.tsx
done when · tick each as it passeswatch out- Parallax and entrance animations with no reduced-motion path make a portfolio actively unpleasant for readers with vestibular sensitivity, and the fix is a media query rather than a redesign. The CSS Media Queries Level 5 draft defines prefers-reduced-motion for exactly this case, WCAG 2.2 makes disabling interaction-triggered animation a AAA criterion, and its Level A criterion on pausing moving content applies to anything that starts by itself and runs past a few seconds. Store a reduced alternative per effect and let the query pick it.
Rollback, backup and handing the site overproduct builder
A bad publish is one command to undo and the whole site can leave with its owner.
Rollback becomes a swap instead of an investigation.
Files
src/publish/versions.tsOutput is a rendering; source is what somebody can edit in five years.
Files
src/export/source.tsEither one alone restores to a site with holes in it.
Files
scripts/backup.shdocs/operations.md
done when · tick each as it passeswatch out- Keeping only the current output means the fastest way to recover from a publish that broke the homepage is to find the mistake under pressure, with the broken version live the entire time. Keep the previous versions, make rollback a swap of a symbolic link, and practise it once before you need it.
That is the whole plan for Readymag. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Arbitrary visual editing of any element.
- Managed hosting, forms and analytics.
- Multi-author editing and client handoff.
- A template gallery.
- CMS collaboration and client handoff
- managed hosting, forms, and analytics
- general-purpose visual editing
- large template and component libraries
- A second locale per page, which the section model already almost supports
- A simple content import from Markdown files, once the section kinds have settled
- A print stylesheet, which editorial sites benefit from more than most and costs one file
Need the files? The project pack on the verdict page hands your agent the whole brief · more website builders.