Build Swipe Pages

KINDAback 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 section-based page builder whose hard problems are publishing without ever serving a half-written page, keeping the editor's own code out of what visitors download, and refusing to publish a page that misses a stated performance budget.

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

RuntimeNext.js 15 with TypeScript for the editor only, never for the published outputOutputStatic HTML, CSS and images written to a directory, no client frameworkStorageSQLite holding sections, page versions and publish recordsPublishWrite to a new content-addressed directory, then swap a symlinkBudgetA measured budget check that blocks the publish, not a lint warning

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

    Get it nodejs.org, or your version manager. open ↗

    Verify node --version prints v22 or higher

  2. installfree

    Why The budget gate needs a real measurement rather than an estimate, and this is the part people skip and then wonder why the page is slow.

    Get it Install a headless browser your measurement script can drive.

    Verify The measurement script prints paint and interaction figures for a sample page

  3. free to a few pounds a month

    Why The published output is plain files, so this can be a small server, object storage or a static host, and picking it first stops the output drifting towards one vendor's conventions.

    Get it Any host that serves a directory over HTTPS.

    Verify An exported folder serves correctly from it with no build step

  4. have readyaround ten pounds a year

    Why Custom domain verification and certificate issuance are the two steps that turn this from a demo into something you can point traffic at.

    Get it Any registrar; you need to be able to add a TXT and an A or CNAME record.

    Verify A TXT record you add is visible from a public resolver

  5. decidefree

    Why Chosen before the first section is written, these constrain the design; chosen afterwards they get raised until they pass.

    Get it Write down the HTML, CSS and JavaScript byte ceilings, the third-party origin count, and the paint and interaction figures you will hold to.

    Verify The numbers appear in the configuration file and in the README

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- pages(id, slug, title, created_at, archived_at)
- page_versions(id, page_id, version, sections_json, theme_json, created_at, published_at) · immutable once published
- sections(version_id, ordinal, kind, props_json) · kind is one of a closed list, and an unknown kind fails validation rather than rendering empty
- assets(id, page_id, path, sha256, width, height, bytes, mime) · dimensions are stored because the markup needs them
- publishes(id, version_id, output_dir, started_at, finished_at, state, bytes_html, bytes_css, bytes_js, lcp_ms, inp_ms, rolled_back_from)
- submissions(id, page_id, version_id, received_at, fields_json, source_ref, spam_reason) · written before anything else runs
- domains(id, page_id, hostname, verified_at, cert_state)
- Every published page maps to exactly one immutable version row, so rollback is pointing the symlink at the previous output directory rather than regenerating anything.

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/pages.dbPages, versions, assets, publishes and submissions.
OUTPUT_ROOTrequired./outContent-addressed publish directories and the served symlink.
PUBLISH_KEEPrequired10How many previous publishes to retain for rollback.
BUDGET_JS_BYTESrequired0Zero is a reasonable starting value for a static landing page.
BUDGET_CSS_BYTESrequired30000Measured on the rendered output, not on source files.
BUDGET_LCP_MSrequired2500Check the current published threshold before setting this.
BUDGET_INP_MSrequired200Check the current published threshold before setting this.
SUBMISSION_RATE_PER_HOURrequired20Per hashed address. Rejections are stored with a reason, not dropped.

The build, in order

  1. A page that is data

    Sections are typed rows validated against a closed list, and the HTML is derived from them.

    1. Every open field is an unbudgeted script waiting to happen.

      Files src/sections/schema.tssrc/sections/index.ts

    2. Deterministic output is what makes rollback and hashing meaningful.

      Files src/render/page.tstests/render.test.ts

    3. Including in a field that looks harmless, like a footer note.

      Files src/sections/schema.tstests/no-raw-html.test.ts

    done when · tick each as it passes
    watch out
    • An open-ended section that accepts arbitrary HTML turns the builder into a text editor with extra steps, and the first time a client pastes an embed the page ships a third-party script you never budgeted for and cannot measure. Keep the list closed, validate props against a schema, and make adding a kind a code change.
  2. Publishing that cannot half happen

    A publish writes a complete output directory and becomes live in one atomic step, with rollback.

    1. The hash of the output is the name, so identical input publishes nothing new.

      Files src/publish/render.ts

    2. One syscall, not a copy loop through a live directory.

      Files src/publish/swap.tstests/publish-atomic.test.ts

      terminal
      ln -sfn out/<hash> out/current.tmp && mv -Tf out/current.tmp out/current
    3. The cheapest possible fix at eleven at night.

      Files src/publish/rollback.ts

    done when · tick each as it passes
    watch out
    • Rendering straight into the served directory means a visitor arriving during the write gets a page with half its stylesheet, and because the write takes under a second you will never reproduce it and will blame the host. Render elsewhere, verify the directory is complete, then swap.
  3. Responsive without a breakpoint editor

    One authored layout adapts by rule, and images never move the page while it loads.

    1. Two numbers per scale beats four breakpoints per element.

      Files src/render/theme.ts

    2. Emitted into the markup so nothing shifts as images arrive.

      Files src/assets/upload.tstests/assets.test.ts

    3. Nobody checks the phone view if checking it is a separate click.

      Files src/app/editor/preview.tsx

    done when · tick each as it passes
    watch out
    • Letting the editor set values per breakpoint feels like control and produces four layouts that drift apart, so the phone version is six months behind the desktop one and nobody notices because nobody previews it. Author once with rules, and let the preview show three widths side by side rather than offering three editors.
  4. A performance budget that blocks the publish

    A page that misses the stated budget cannot go live until it is fixed or the budget is changed on purpose.

    1. Before it is live, not in a report afterwards.

      Files src/publish/budget.tstests/budget.test.ts

    2. Check the current published thresholds for the metrics you record.

      Files scripts/measure.mjssrc/publish/measure.ts

    3. A warning in a build log is not a budget.

      Files src/publish/index.ts

    done when · tick each as it passes
    watch out
    • Shipping the editor's own framework to the visitor is the standard way a page builder produces slow pages, because the bundle that makes the editing experience pleasant is downloaded by every visitor who will never edit anything. Publish static files with a JavaScript ceiling measured in kilobytes and let the gate fail the publish when a section kind starts importing a component library.
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.