Página Editorial Mono
Una página de aterrizaje maquetada como una revista: tinta sobre papel, un titular con una fina línea de "número", un encabezado en Instrument Serif lo suficientemente grande para leerse al otro lado de la habitación, una introducción con capitular, luego columnas numeradas divididas por líneas finas, spreads de características que alternan lados con figuras enmarcadas y pies de foto ("Fig. 1"), una cita destacada centrada en cursiva, una lista de preguntas, una línea de cierre y un colofón estilo máquina de escribir. Negro sobre blanco cálido por defecto; claro sobre casi negro, o con un color de acento para las palabras en cursiva, cambiando tres colores.
Tú describes la página en page.json, o dejas que un script la redacte a partir del README del proyecto. La construcción la verifica y escribe out/index.html, un solo archivo con su CSS (y out/assets/ para las imágenes). Para un producto que aún no ha salido, el hero contiene un formulario de lista de espera real que envía los datos a Formspree, Netlify Forms, Buttondown o cualquier endpoint; para uno que ya está disponible, dos botones.
Qué necesitas
- Node.js 18 o más reciente. No necesitas instalar nada más.
- Chrome, Chromium o Edge para las comprobaciones (los scripts lo encuentran; configura
CHROME_PATHsi no lo hacen). - Para una lista de espera: una cuenta con un servicio de formularios, o un endpoint que acepte un envío de formulario.
- Acceso a Internet cuando se abra la página, para sus Google Fonts (Instrument Serif, Newsreader, Inter e IBM Plex Mono). Sin conexión, la página usa fuentes del sistema.
La carpeta de esta habilidad es <skill> a continuación: la carpeta donde se encuentra este SKILL.md.
Pasos
1. Redactar desde el README
node <skill>/scripts/from-readme.mjs README.md page.json
Lee el README (y el package.json que lo acompaña, si existe) y escribe un page.json que ya se puede construir: el nombre, el eslogan como primer titular, la introducción como entradilla, una lista de "Características" cuyos elementos comienzan con un nombre en negrita como columnas, los comandos de instalación e inicio rápido como una figura de terminal, otras secciones como spreads de características (con su captura de pantalla o código), una sección de preguntas frecuentes, y el repositorio como un botón. Omite insignias, logotipos, filas de enlaces, tablas de contenido, secciones de licencia y contribuciones.
Nunca escribe texto propio más allá de etiquetas como "Empezar", y termina con tres listas. Trabájalas con la persona:
- Escribir con la persona: siempre el titular, y cada título de característica que siga siendo un encabezado del README ("Instalar", "Cómo funciona").
- Recortar para ajustar: texto que acortó en un límite de oración o palabra. Vuelve a leer cada uno.
- En el README pero no en la página: secciones y características para las que no tenía espacio. Intercámbialas si son más importantes.
Sin README, o con uno muy breve, escribe page.json a partir de las notas de la persona, el sitio actual o la documentación, empezando desde uno de los ejemplos.
2. Decidir qué pide el hero
-
Aún no lanzado: una lista de espera. Pregunta qué servicio recoge los correos electrónicos y configura
hero.form:providerConfiguración Qué poner en formformspreeCrea un formulario en formspree.io; su URL termina con el ID del formulario. El más sencillo en cualquier hosting. "id": "xayzbqwe"netlifySolo cuando la página está desplegada en Netlify; los registros aparecen en la pestaña Formularios del sitio. "name": "waitlist"buttondownUn boletín de Buttondown. Las personas obtienen la página de confirmación de Buttondown. "username": "yourname"endpointCualquier otra cosa que acepte un envío de formulario: tu API, o la URL de actionde un formulario de lista de correo (Mailchimp, Kit, Loops y similares)."url": "https://…","field"si no esemail(Mailchimp usaEMAIL),"ajax": falsepara servicios de listasCon
ajax(el valor predeterminado excepto para Buttondown) la página envía el formulario con JavaScript y muestrasuccessoerroren su lugar; sin JavaScript, o con"ajax": false, es un envío de formulario normal. Un endpoint usado conajaxdebe responder con un 2xx y, si está en otro dominio, permitir el origen de la página (CORS). Todos los proveedores excepto Buttondown obtienen un campo oculto anti-spam; descarta los registros donde esté relleno. Cada botón "Unirse" en la página (la barra, el cierre) se desplaza al formulario y coloca el cursor en él. -
Ya disponible:
hero.actionscon un botónprimary(descargar, registrarse, instalar) y unosecondaryopcional (documentación, fuente). Apúntalos a URLs reales o a#get-starteden la página.
3. Escribir la página
Copia el ejemplo más cercano y reemplaza todo: examples/quietly/page.json (una lista de espera, claro) o examples/galley/page.json (una herramienta de código abierto, oscuro, redactado desde examples/galley/README.md).
| Campo | Qué es | Límite |
|---|---|---|
brand.name, brand.href | El nombre en la parte superior izquierda, configurado en la serif de visualización | 24 |
nav[] | Hasta 5 { "label", "href" }. Los enlaces #id deben apuntar a algo en la página (abajo) | 16 |
action | El botón en la parte superior derecha; por defecto: la acción principal del hero. false para ninguno | 22 |
issue[] | Hasta 3 líneas cortas debajo de la barra, en versalitas: una edición, las partes del producto, una fecha de lanzamiento o versión. En teléfonos solo se muestran la primera y la última | 40 cada una |
hero.title | El titular. *palabra* la pone en cursiva (en theme.accent si está configurado), \n rompe la línea (hasta 3 líneas) | 64 |
hero.lede | Qué es, para quién y por qué, en una o dos oraciones. La primera letra se convierte en capitular ("dropcap": false para desactivarlo) | 300 |
hero.form o hero.actions | Paso 2. Textos del formulario: placeholder (32), button (22), success, error (120). Botones: { "label", "href" } (26) | – |
hero.note | Una línea pequeña debajo del formulario o los botones: cuándo se envían las invitaciones, qué enviarás, la licencia | 100 |
columns[] | 2 a 4 { "kicker", "title", "text" }, numerados 01, 02… ID de sección highlights | 24, 44, 220 |
features[] | Hasta 4 spreads: kicker (28), title (72, *cursiva* funciona), text (420; una línea en blanco comienza un párrafo), points (hasta 4, 90 cada uno), id (para enlaces de navegación), figure (abajo) | – |
quote | { "text", "cite" }, una cita real de una persona real que aceptó. Omítelo si no es así | 220, 60 |
faq | title (40, por defecto "Antes de que preguntes") y de 1 a 8 items de { "q", "a" }. ID de sección faq | 100, 500 |
closing | kicker (28), title (64), text (220), action (por defecto: la acción principal del hero). ID de sección closing | – |
footer.items[], links[] | Hasta 3 líneas en el colofón (por defecto "Nombre © año") y hasta 6 enlaces | 48, 20 |
theme | paper e ink (hex; ink debe alcanzar 7:1 sobre paper), accent opcional; fuentes display, serif, sans, mono (familias de Google Fonts); fonts ("" para ninguna, o tu URL) | – |
meta | title (70) y description (170) para la búsqueda y las vistas previas de enlaces; url, image (una imagen de vista previa de enlace https), icon, lang | – |
Los campos de texto aceptan Markdown en línea: código, enlaces, negrita y cursiva.
Figuras. Cada característica puede tener una, dibujada en un marco con una sombra offset dura y un caption opcional (90), numerada "Fig. 1", "Fig. 2" hacia abajo en la página. Los spreads con figura alternan lados; los que no tienen figura colocan el título junto al texto.
type | Campos | Úsalo para |
|---|---|---|
image | src (un archivo junto a page.json: png, jpg, webp, avif, gif o svg; o una URL https) y alt (160): qué muestra la imagen | Una captura de pantalla real, una foto, una ilustración |
window | title (40), subtitle (60), sidebar (hasta 6 elementos, 20 cada uno; active selecciona el resaltado, por defecto 0), rows (1 a 6 de meta (8), label (48), tag (14), fill true/false) | La pantalla principal de una aplicación, dibujada en el estilo de la página |
stats | items: 2 a 4 de value (10) y label (60) | Números que son reales y con fuente |
code | code (hasta 14 líneas de 64 caracteres; las líneas con $ obtienen un prompt, las líneas con # y // están atenuadas) y title (24) para la barra del marco, ej. "Terminal" | Comandos de instalación y primer uso, un archivo de configuración |
Consejos de escritura: el titular dice lo que obtiene el lector, en sus palabras, en las menos palabras posibles; deja que una palabra lleve la cursiva. Los títulos de columna son afirmaciones cortas ("Silencio por defecto."), no nombres de características. Cada número, cita, cliente y afirmación debe provenir de la persona, del README o de una fuente que ellos indiquen. Una figura window debe mostrar lo que realmente hace el producto; sus filas pueden ser ejemplos inventados, como una pantalla de muestra, así que indícalo en el pie de foto si aparecen nombres.
4. Construir
node <skill>/scripts/build.mjs page.json out
Enumera cada problema en page.json de una sola vez (campos faltantes, texto que excede su límite, un enlace de navegación a un id que no está en la página, colores que no contrastan) y no escribe nada hasta que se solucionen. Luego indica dónde se envía el formulario y enumera lo que solo la persona puede confirmar: la cita, los números, las figuras de ventana.
5. Verificar y mirar
node <skill>/scripts/check.mjs out/index.html
node <skill>/scripts/try-form.mjs out/index.html # con un formulario de lista de espera
node <skill>/scripts/screenshot.mjs out/index.html
check.mjscarga la página a 390, 768, 1024 y 1440 píxeles y debe deciroken cada uno: nada más ancho que la pantalla o cortado, contraste legible en todas partes, texto alternativo, un campo de formulario etiquetado, un h1, sin niveles de encabezado saltados. Las líneas marcadas con·merecen un vistazo pero no lo hacen fallar.try-form.mjsregistra con[email protected]en Chrome sin interfaz gráfica contra un sustituto del servicio de formularios en esta máquina (nada llega al real) y muestra lo que se envió, lo que ve el visitante después y lo que ve cuando el servicio falla. Debe terminar conEl formulario funciona.screenshot.mjsguardaout/screens/desktop.pngymobile.png. Mira ambas: ¿la primera pantalla dice qué es?, ¿algún titular se rompe mal?, ¿algún spread está desequilibrado (acorta el texto o la figura)?
6. Publicarlo
Sube out/index.html y out/assets/ a cualquier hosting estático: Netlify, Vercel, Cloudflare Pages, GitHub Pages, S3. Para mantener la página en el repositorio del proyecto, añade la construcción a sus scripts, ej. "landing": "node tools/landing/build.mjs landing/page.json public" después de copiar build.mjs, inline.mjs, markup.mjs y color.mjs a tools/landing/.
Con una lista de espera, regístrate una vez en la página en vivo con la dirección de la persona y confirma que llega al servicio. Enlaza una política de privacidad desde footer.links cuando la página recoja correos electrónicos; pide a la persona su URL.
Solución de problemas
build: arregla page.json primero: cada línea nombra el campo y qué cambiar.apunta a nada en la página: un enlace de navegación o botón a#algoque no es unidaquí. Los spreads de características obtienen uno con"id"; los propios de la página son#join(el formulario),#highlights,#faqy#closing.no contrasta: los colorestheme.paperytheme.inkno alcanzan una relación de contraste de 7:1. La herramienta de verificación muestra la relación actual. Elige un papel más claro, una tinta más oscura, o ambos.fuente no encontrada: el nombre de la familia no coincide con el nombre de la fuente en Google Fonts, o la fuente no tiene el peso o la cursiva que la página necesita. Usa el nombre exacto de la familia.no se puede cargar la página en el navegador: abreout/index.htmldirectamente en el navegador. La página funciona con el protocolofile://, pero el formulario (con ajax) y las fuentes requieren un servidor.- El formulario no se envía en vivo: revisa la configuración del servicio. Para Netlify Forms, la página debe estar desplegada en Netlify. Para Formspree, el ID del formulario debe ser correcto. Para un endpoint, la URL debe ser accesible y responder correctamente (2xx para éxito, CORS configurado si se usa ajax).
- La página se ve diferente en el móvil: la maquetación es responsiva. Las columnas se apilan, los spreads se reorganizan y las figuras se redimensionan. Usa las capturas de pantalla para comprobar el aspecto en todos los tamaños.