Mono Editorial Landing
Eine Landingpage wie aus einer Zeitschrift: Tinte auf Papier, ein Masthead mit einer dünnen „Ausgabe“-Zeile, eine Headline in Instrument Serif, groß genug, um sie quer durch einen Raum zu lesen, eine Einleitung mit Initial, dann nummerierte Spalten, geteilt durch Haarlinien, Feature-Spreads, die die Seiten mit gerahmten Abbildungen und Bildunterschriften („Fig. 1“) abwechseln, ein zentriertes kursives Pull-Quote, eine Liste von Fragen, eine Schlusszeile und ein Colophon im Schreibmaschinen-Stil. Standardmäßig Schwarz auf warmem Weiß; Hell auf fast Schwarz, oder mit einer Akzentfarbe für die kursiven Wörter, durch Ändern von drei Farben.
Du beschreibst die Seite in page.json oder lässt ein Skript sie aus dem README des Projekts erstellen. Der Build prüft sie und schreibt out/index.html, eine Datei mit CSS (und out/assets/ für Bilder). Für ein Produkt, das noch nicht veröffentlicht ist, enthält der Hero ein echtes Wartelisten-Formular, das an Formspree, Netlify Forms, Buttondown oder einen beliebigen Endpunkt sendet; für ein veröffentlichtes Produkt zwei Buttons.
Was du brauchst
- Node.js 18 oder neuer. Nichts zu installieren.
- Chrome, Chromium oder Edge für die Prüfungen (die Skripte finden sie; setze
CHROME_PATH, wenn sie es nicht tun). - Für eine Warteliste: ein Konto bei einem Formular-Dienst oder einen Endpunkt, der ein Formular-Post akzeptiert.
- Internetzugang, wenn die Seite geöffnet wird, für ihre Google Fonts (Instrument Serif, Newsreader, Inter und IBM Plex Mono). Ohne Internet verwendet die Seite Systemfonts.
Das Verzeichnis dieses Skills ist <skill> unten: das Verzeichnis, in dem sich diese SKILL.md befindet.
Schritte
1. Aus dem README entwerfen
node <skill>/scripts/from-readme.mjs README.md page.json
Es liest das README (und package.json daneben, falls vorhanden) und schreibt eine page.json, die bereits erstellt wird: den Namen, den Slogan als erste Überschrift, die Einleitung als Lead, eine „Features“-Liste, deren Einträge mit einem fettgedruckten Namen als Spalten beginnen, Installations- und Schnellstartbefehle als Terminal-Abbildung, andere Abschnitte als Feature-Spreads (mit ihrem Screenshot oder Code), einen FAQ-Bereich als Fragen und das Repository als Button. Es überspringt Badges, Logos, Link-Reihen, Inhaltsverzeichnisse, Lizenz- und Mitwirkenden-Abschnitte.
Es schreibt nie eigenen Text über Labels wie „Get started“ hinaus und endet mit drei Listen. Gehe sie mit der Person durch:
- Mit der Person schreiben: immer die Überschrift und jeden Feature-Titel, der noch eine README-Überschrift ist („Installieren“, „So funktioniert es“).
- Anpassen: Text, den es an einem Satz- oder Wortende gekürzt hat. Lies jeden noch einmal.
- Im README, aber nicht auf der Seite: Abschnitte und Features, für die es keinen Platz gab. Tausche sie ein, wenn sie wichtiger sind.
Ohne README oder mit einem dünnen Readme schreibe page.json aus den Notizen der Person, der aktuellen Website oder der Dokumentation, beginnend mit einem der Beispiele.
2. Entscheiden, was der Hero verlangt
-
Noch nicht gestartet: eine Warteliste. Frage, welcher Dienst die E-Mails sammelt, und setze
hero.form:providerEinrichtung Was in formsetzenformspreeErstelle ein Formular auf formspree.io; seine URL endet mit der ID des Formulars. Am einfachsten auf jedem Host. "id": "xayzbqwe"netlifyNur, wenn die Seite auf Netlify bereitgestellt wird; Anmeldungen erscheinen unter dem Reiter „Forms“ der Site. "name": "waitlist"buttondownEin Buttondown-Newsletter. Leute erhalten Buttondowns eigene Bestätigungsseite. "username": "deinname"endpointAlles andere, das ein Formular-Post akzeptiert: deine API, oder die action-URL eines Mailinglisten-Formulars (Mailchimp, Kit, Loops und ähnliche)."url": "https://…","field", wenn es nichtemailist (Mailchimps istEMAIL),"ajax": falsefür ListendiensteMit
ajax(Standard, außer für Buttondown) sendet die Seite das Formular mit JavaScript und zeigtsuccessodererroran Ort und Stelle; ohne JavaScript oder mit"ajax": falseist es ein normales Formular-Post. Ein Endpunkt, der mitajaxverwendet wird, muss mit 2xx antworten und auf einer anderen Domain die Herkunft der Seite erlauben (CORS). Jeder Anbieter außer Buttondown erhält ein verstecktes Spam-Trap-Feld; lasse Anmeldungen fallen, bei denen es ausgefüllt ist. Jeder „Join“-Button auf der Seite (die Leiste, der Abschluss) scrollt zum Formular und setzt den Cursor hinein. -
Bereits veröffentlicht:
hero.actionsmit einemprimary-Button (Download, Anmeldung, Installation) und einem optionalensecondary(Dokumentation, Quelle). Verweise auf echte URLs oder auf#get-startedauf der Seite.
3. Schreibe die Seite
Kopiere das nächstgelegene Beispiel und ersetze alles: examples/quietly/page.json (eine Warteliste, hell) oder examples/galley/page.json (ein Open-Source-Tool, dunkel, entworfen aus examples/galley/README.md).
| Feld | Was es ist | Grenze |
|---|---|---|
brand.name, brand.href | Der Name oben links, gesetzt in der Display-Serife | 24 |
nav[] | Bis zu 5 { "label", "href" }. #id-Links müssen auf etwas auf der Seite verweisen (unten) | 16 |
action | Der Button oben rechts; Standard: die Hauptaktion des Heroes. false für keine | 22 |
issue[] | Bis zu 3 kurze Zeilen unter der Leiste, in Kapitälchen: eine Ausgabe, die Teile des Produkts, ein Startdatum oder eine Version. Auf Telefonen werden nur die erste und die letzte angezeigt | 40 pro Zeile |
hero.title | Die Überschrift. *wort* setzt es kursiv (in theme.accent, falls festgelegt), \n bricht die Zeile (bis zu 3 Zeilen) | 64 |
hero.lede | Was es ist, für wen und warum, in ein oder zwei Sätzen. Der erste Buchstabe wird zu einem Initial ("dropcap": false zum Ausschalten) | 300 |
hero.form oder hero.actions | Schritt 2. Formulartexte: placeholder (32), button (22), success, error (120). Buttons: { "label", "href" } (26) | – |
hero.note | Eine kleine Zeile unter dem Formular oder den Buttons: wann Einladungen verschickt werden, was du senden wirst, die Lizenz | 100 |
columns[] | 2 bis 4 { "kicker", "title", "text" }, nummeriert 01, 02… Abschnitts-ID highlights | 24, 44, 220 |
features[] | Bis zu 4 Spreads: kicker (28), title (72, *kursiv* funktioniert), text (420; eine Leerzeile beginnt einen Absatz), points (bis zu 4, 90 pro), id (für Nav-Links), figure (unten) | – |
quote | { "text", "cite" }, ein echtes Zitat einer echten Person, die zugestimmt hat. Sonst weglassen | 220, 60 |
faq | title (40, Standard „Before you ask”) und 1 bis 8 items von { "q", "a" }. Abschnitts-ID faq | 100, 500 |
closing | kicker (28), title (64), text (220), action (Standard: die Hauptaktion des Heroes). Abschnitts-ID closing | – |
footer.items[], links[] | Bis zu 3 Zeilen im Colophon (Standard „Name © year”) und bis zu 6 Links | 48, 20 |
theme | paper und ink (Hex; Ink muss 7:1 auf Paper erreichen), optional accent; Schriftarten display, serif, sans, mono (Google Fonts-Familien); fonts ("" für keine, oder deine URL) | – |
meta | title (70) und description (170) für Suche und Link-Vorschauen; url, image (ein https-Link-Vorschaubild), icon, lang | – |
Textfelder akzeptieren Inline-Markdown: code, links, fett und kursiv.
Abbildungen. Jedes Feature kann eine haben, gezeichnet in einem Rahmen mit einem harten Offset-Schatten und einem optionalen caption (90), nummeriert „Fig. 1”, „Fig. 2” auf der Seite. Spreads mit einer Abbildung wechseln die Seiten; Spreads ohne Abbildung setzen den Titel neben den Text.
type | Felder | Verwende es für |
|---|---|---|
image | src (eine Datei neben page.json: png, jpg, webp, avif, gif oder svg; oder eine https-URL) und alt (160): was das Bild zeigt | Einen echten Screenshot, ein Foto, eine Illustration |
window | title (40), subtitle (60), sidebar (bis zu 6 Einträge, 20 pro; active wählt den hervorgehobenen aus, Standard 0), rows (1 bis 6 von meta (8), label (48), tag (14), fill true/false) | Den Hauptbildschirm einer App, gezeichnet im Seitenstil |
stats | items: 2 bis 4 von value (10) und label (60) | Zahlen, die wahr und belegt sind |
code | code (bis zu 14 Zeilen mit 64 Zeichen; $ -Zeilen erhalten eine Eingabeaufforderung, #- und //-Zeilen sind abgedunkelt) und title (24) für die Leiste des Rahmens, z.B. „Terminal“ | Installations- und erste Befehle, eine Konfigurationsdatei |
Schreibtipps: Die Überschrift sagt, was der Leser bekommt, in seinen Worten, in so wenigen Worten wie nötig; lass ein Wort die Kursivschrift tragen. Spaltentitel sind kurze Aussagen („Silence by default.”), keine Feature-Namen. Jede Zahl, jedes Zitat, jeder Kunde und jede Behauptung muss von der Person, dem README oder einer Quelle, auf die sie verweisen, stammen. Eine window-Abbildung muss zeigen, was das Produkt wirklich tut; ihre Zeilen können erfundene Beispiele sein, als beispielhafter Bildschirm, also sage das in der Bildunterschrift, wenn Namen erscheinen.
4. Erstellen
node <skill>/scripts/build.mjs page.json out
Es listet jedes Problem in page.json auf einmal auf (fehlende Felder, Text über dem Limit, ein Nav-Link zu einer ID, die nicht auf der Seite ist, Farben, die nicht kontrastieren) und schreibt nichts, bis sie behoben sind. Dann sagt es, wohin das Formular sendet, und listet auf, was nur die Person bestätigen kann: das Zitat, die Zahlen, die Window-Abbildungen.
5. Prüfen und ansehen
node <skill>/scripts/check.mjs out/index.html
node <skill>/scripts/try-form.mjs out/index.html # mit einem Wartelisten-Formular
node <skill>/scripts/screenshot.mjs out/index.html
check.mjslädt die Seite bei 390, 768, 1024 und 1440 px und muss bei jedemoksagen: nichts breiter als der Bildschirm oder abgeschnitten, lesbarer Kontrast überall, Alt-Text, ein beschriftetes Formularfeld, ein H1, keine übersprungenen Überschriften-Ebenen. Zeilen, die mit·markiert sind, sind einen Blick wert, lassen sie aber nicht durchfallen.try-form.mjsmeldet sich mit[email protected]in Headless Chrome gegen einen Stellvertreter für den Formular-Dienst auf dieser Maschine an (nichts erreicht den echten) und zeigt, was gesendet wurde, was der Besucher danach sieht und was sie sehen, wenn der Dienst fehlschlägt. Es muss mitThe form works.enden.screenshot.mjsspeichertout/screens/desktop.pngundmobile.png. Sieh dir beide an: Sagt der erste Bildschirm, was es ist, bricht eine Überschrift schlecht um, ist ein Spread schief (kürze den Text oder die Abbildung)?
6. Veröffentlichen
Lade out/index.html und out/assets/ auf einen beliebigen statischen Host hoch: Netlify, Vercel, Cloudflare Pages, GitHub Pages, S3. Um die Seite im Repository des Projekts zu behalten, füge den Build zu seinen Skripten hinzu, z.B. "landing": "node tools/landing/build.mjs landing/page.json public" nach dem Kopieren von build.mjs, inline.mjs, markup.mjs und color.mjs nach tools/landing/.
Mit einer Warteliste melde dich einmal auf der Live-Seite mit der eigenen Adresse der Person an und bestätige, dass sie den Dienst erreicht. Verlinke eine Datenschutzerklärung von footer.links, wenn die Seite E-Mails sammelt; frage die Person nach ihrer URL.
Fehlerbehebung
build: fix page.json first: Jede Zeile nennt das Feld und was zu ändern ist.points at nothing on the page: Ein Nav- oder Button-Link zu#something, das hier keineidist. Feature-Spreads erhalten eine mit"id"; die eigenen IDs der Seite sind#join(das Formular),#highlights,#faqund#closing.link to external site is not a secure URL: Diehrefeines Nav- oder Action-Links muss mithttps://beginnen.icon is not a secure URL:meta.iconmuss eine https-URL sein, die auf eine PNG- oder SVG-Datei verweist.image at … is not available: Diesrceiner Bildabbildung muss auf eine vorhandene Datei verweisen (ob relativ zupage.jsonoder eine absolute https-URL, die 200 zurückgibt).- Build bleibt hängen: Die Skripte schreiben Fehler nach
stderrund beenden sich mit Code 1, aber eine Pipeline oder ein Editor kann die Ausgabe verstecken. Führenode <skill>/scripts/build.mjs … 2>&1aus. - Formular erreicht den Dienst nicht: Der
id- oderurl-Wert ist die häufigste fehlerhafte Angabe. Überprüfe in der Dokumentation des Dienstes den Endpunkt und ob der Dienst CORS fürajaxerlaubt. - Formular zeigt nach dem Absenden
error: Öffne die Seite ohneajax("ajax": false); wenn das funktioniert, liegt es an CORS oder daran, dass"field"falsch ist. Öffne die DevTools (Netzwerk-Tab), um zu sehen, was dein Endpunkt zurücksendet. **check sagt 'text below fold …'**: Die Seite ist länger als der Bildschirm; das ist bei einer Magazinseite normal.- Schriftart wird nicht geladen: Der Name der Google Fonts-Familie unterscheidet sich möglicherweise von der Suchleiste von Google Fonts: Verwende den genauen Namen (z.B. für „Source Code Pro:400,400i,600“). Prüfe die Netzwerk-Registerkarte der DevTools auf 404-Fehler.