# How to Post on MemoryZone

A plain-English tutorial for editors of **MemoryZone — Webzine for the
Havenless Culture-Terrorist**. No login. No database. No admin panel.
Posts are files. You win when you upload the right files to the right
folders.

There are **two ways** to add a post:

- **Easy way** — open `/make-post.html` in your browser, fill a form,
  click "GENERATE FILES", upload the two outputs. Recommended.
- **Manual way** — create the files and JSON entry yourself with any
  text editor. Good to know how this works.

Both produce the same thing. Pick whichever is less annoying.

---

## 1. What is a post, exactly?

A post is **two pieces of data**:

| Piece | Where | What it is |
|---|---|---|
| **Body file** | `/posts/<slug>.txt` or `/posts/<slug>.md` | The actual writing. Plain text (preserves line breaks) or Markdown (rendered as HTML). |
| **Manifest entry** | one JSON object inside `/posts/index.json` | Metadata the site needs: id, title, category, date, image, file path. |

When the site loads, it fetches `posts/index.json`, sorts the list
newest-first by `date`, and renders the archive from that. When you click
a post, it fetches the matching body file and displays it.

Images, if any, live in `/images/` and are referenced by path in the
manifest entry.

---

## 2. The easy way — use `/make-post.html`

1. In your browser, open **`https://your-site-url/make-post.html`**.
   (During Emergent preview: the same URL with `/make-post.html` appended.)
2. Fill in:
   - **Title** — the big headline. ALL CAPS reads loudest.
   - **Slug** — auto-filled from the title. Lowercase, hyphens only.
     This becomes the post's URL: `/post.html?id=<slug>`.
   - **Category** — Poetry / Comics / Politics / News / Game.
   - **Date** — defaults to today. Used for sorting newest-first.
   - **Image path** (optional) — either a relative path like
     `images/my-photo.jpg` or an external URL like
     `https://example.com/pic.png`.
   - **Body format** — `txt` (plain text, preserves whitespace) or `md`
     (Markdown — use `# headings`, `**bold**`, lists, links, etc.).
   - **Body** — the writing itself.
3. Click **GENERATE FILES**. Two things appear below the form:
   - A **Download <slug>.txt** (or `.md`) button — the body file.
   - A **JSON snippet** to paste into `/posts/index.json` — with
     "Copy JSON" and "Download Snippet" buttons.
4. **Upload** to your host:
   1. Put the downloaded body file in `/posts/`.
   2. If you have an image, put it in `/images/` (or wherever the path
      says).
   3. Open `/posts/index.json` in your host's file editor. Paste the JSON
      snippet right after the opening `[`. Make sure every entry except
      the last one ends with a comma. Save.
5. Refresh the home page. The new post shows up at the top.

That's the whole flow. The generator never sends anything anywhere — all
the JSON creation and file download happens in your browser.

---

## 3. The manual way — for when you're feeling purist

### 3a. Write the body file

Pick a **slug**. Lowercase, hyphens, no spaces:

```
bad-dreams-07
```

Create a file:

- Plain text: `/posts/bad-dreams-07.txt`
- Or markdown: `/posts/bad-dreams-07.md`

Write the post. Line breaks and blank lines are preserved verbatim for
`.txt` files — perfect for poems and ASCII. Markdown files get rendered
with [marked](https://marked.js.org/): use `# H1`, `## H2`, `**bold**`,
`*italic*`, `[link](https://…)`, lists, blockquotes, images, code blocks.

### 3b. Add the manifest entry

Open `/posts/index.json`. It's a JSON array. Add a new object **at the
top** (newest first is conventional, though the site sorts client-side
by `date` anyway):

```json
[
  {
    "id":       "bad-dreams-07",
    "title":    "BAD DREAMS #07",
    "category": "poetry",
    "date":     "2026-05-02",
    "image":    "",
    "file":     "posts/bad-dreams-07.txt"
  },
  {
    "id":       "the-poetry-update",
    "title":    "THE POETRY UPDATE",
    "category": "poetry",
    "date":     "2026-05-02",
    "image":    "",
    "file":     "posts/the-poetry-update.txt"
  }
]
```

**Valid values:**

| Field | Rules |
|---|---|
| `id` | `[a-z0-9-]+`. Used as the URL id and must be unique across posts. |
| `title` | Anything, rendered as the `<h1>`. |
| `category` | Exactly one of `poetry`, `comics`, `politics`, `news`, `game`. |
| `date` | `YYYY-MM-DD`. Used for sorting and display. |
| `image` | Empty string, a relative path (`images/pic.jpg`), or a full URL. |
| `file` | Path relative to the site root. Must end `.txt` or `.md`. |

Common JSON gotchas:

- No trailing comma after the **last** object in the array.
- Every key and string value must be double-quoted.
- If you break the JSON, the whole site shows an error — use
  [jsonlint.com](https://jsonlint.com/) to validate.

### 3c. Upload

Drop the two changed files (`posts/<slug>.txt` and `posts/index.json`)
onto your host via whatever upload mechanism it gives you — FTP, SFTP,
Netlify drop, GitHub commit, cPanel file manager, rsync, USB stick, etc.

Refresh. The post is live.

---

## 4. Images

1. Drop the image into `/images/`. Example: `/images/bad-dreams-07.jpg`.
2. In that post's manifest entry, set:
   ```
   "image": "images/bad-dreams-07.jpg"
   ```
   Or use an external URL:
   ```
   "image": "https://i.imgur.com/abc123.jpg"
   ```
3. The image is shown **only on the full post page**, as a hero at the
   top. Lists and the homepage stay text-only.

Supported formats: whatever your browser can render — JPEG, PNG, GIF,
WEBP, SVG. No size limit on the client; your host may have one.

---

## 5. Markdown cheat sheet

If you save your body as `.md`, these get rendered:

```markdown
# Biggest heading
## Smaller heading

**Bold**, *italic*, ~~strike~~.

[A link](https://example.com)

> A blockquote. Good for epigraphs.

- A bullet
- Another bullet

1. Numbered
2. List

`inline code` and fenced blocks:

```
code block
```

![An image](images/pic.jpg)

---
```

The rendered CSS uses the Manhunter palette — magenta borders on
blockquotes and images, yellow inline code on a dark background, cyan
rules. It matches the zine without any extra work from you.

---

## 6. Editing & deleting

- **Change the body** — edit the `.txt` / `.md` file. No JSON change needed.
- **Change title / date / category / image** — edit that post's entry in
  `posts/index.json`.
- **Delete a post** — remove its entry from `posts/index.json`. You can
  also delete the body file and image — they're just orphan bytes at
  that point.

The site has no cache of its own. As soon as the files on disk change
and the browser refreshes, you see the new state.

---

## 7. Older / newer navigation

Every post detail page has **OLDER** and **NEWER** buttons at the bottom,
computed from `posts/index.json` at page-load time. You don't wire these
manually — as soon as your new post is in the manifest, it's linked
automatically.

---

## 8. When things break

| Symptom | Usual cause |
|---|---|
| Home page stuck on "DECODING SIGNAL" | `posts/index.json` has a syntax error — validate with jsonlint.com. |
| Post URL shows "404 — SIGNAL LOST" | The `id` in the URL doesn't match any `id` in the manifest, or the manifest file couldn't load. |
| Post body shows "Could not load post" | The `file` path in the manifest is wrong or the body file wasn't uploaded. |
| Image doesn't appear | Case-sensitive path mismatch, wrong folder, or the file wasn't uploaded. |
| Markdown shows as raw `#` symbols | The body file ended in `.txt` — rename to `.md` and update the `file` field. |

---

## 9. Deploying the whole site

The site is just `/app/frontend/public/`. Everything in there is static.

### Options
- **GitHub Pages / GitLab Pages** — commit and push, enable Pages. Free.
- **Netlify / Cloudflare Pages** — drag-and-drop the folder.
- **Neocities** — upload via their UI; infinitely in-spirit.
- **A VPS with nginx** — serve the folder as document root.
- **Locally** — `cd /app/frontend/public && python3 -m http.server`.

If your host serves directory indexes, URLs like `/posts/` might list
the folder publicly. That's fine — nothing here is secret.

### Before uploading, you probably want to remove:
- The `<script src="…/emergent-main.js">` line in `/index.html`'s `<head>`.
- The `<a id="emergent-badge">` block near the end of `/index.html`'s `<body>`.

Both are only useful inside Emergent's preview environment.

---

That's the whole tutorial. File in. File out. Signal live.
