Build Readymag

KINDAreplaces $20/mosaves $240/yrback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

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.

estimated effort weekendthe files for this build are in the project pack

EditorNext.js 15 with TypeScript, running on localhost onlyStorageSQLite holding page source, plus an assets folderOutputA folder of static files per publish, written atomicallyLayoutSections with per-breakpoint overrides, never free pixel positioningFontsSelf-hosted files with the licence recorded beside them

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. 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

  2. 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

  3. 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

  4. 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

  5. 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.

VariableNeededExampleWhere the value comes from
DATABASE_PATHrequired./data/site.dbPages, sections, layouts. Half of what you back up.
ASSETS_DIRrequired./data/assetsImages and fonts with their licence notes. The other half.
OUTPUT_ROOTrequired./outOne directory per publish version, with a pointer to the live one.
PUBLISH_KEEP_VERSIONSrequired5How many publishes to retain. Rollback is a swap between these.
BREAKPOINTSrequired360,768,1280The narrowest is the one the editor opens at and the one publish requires.
IMAGE_WIDTHSrequired480,960,1920Generated at upload, emitted as a source set.
EDITOR_BINDrequired127.0.0.1:3000Localhost. The editor is never part of the published site.

The build, in order

  1. Sections, not coordinates

    A page is an ordered list of sections whose layout is defined per breakpoint.

    1. An open set becomes a component library and then becomes your whole weekend.

      Files src/model/sections.ts

    2. Per-breakpoint rows make the narrow view a thing you can require.

      Files src/model/layouts.ts

    3. People design what they look at first.

      Files src/editor/Canvas.tsx

    done when · tick each as it passes
    watch 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.
  2. Publishing a folder that needs nothing

    A publish writes static files that render with the builder switched off.

    1. A half-published site is worse than an old one.

      Files src/publish/build.tstest/interrupt.test.ts

    2. Cheap, mechanical, and it catches every slug typo before a reader does.

      Files src/publish/verify.ts

    3. Byte identical output turns a diff into a review.

      Files src/publish/render.ts

    done when · tick each as it passes
    watch 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.
  3. 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.

    1. Doing it at publish time makes every publish slow instead of one upload.

      Files src/assets/images.ts

    2. The one line that stops the page jumping under the reader's thumb.

      Files src/publish/render.ts

    3. Fonts 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 passes
    watch 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.
  4. Motion a reader can switch off

    Every effect has a defined reduced-motion behaviour and nothing moves for longer than the reader allows.

    1. A required field is the only version of this that survives a deadline.

      Files src/model/motion.tstest/motion.test.ts

    2. The reader's own setting does the work; you just have to honour it.

      Files src/publish/css.ts

    3. Authors design for what they can see.

      Files src/editor/MotionPanel.tsx

    done when · tick each as it passes
    watch 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.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more website builders.