Polski CMS dla Astro. Lokalny, git-native, z wbudowanym panelem SEO.
Status: early / v0.1 — soft launch. Repo nie jest jeszcze na npm (uruchamiasz z klona, patrz Quick start). API i config mogą się jeszcze zmienić przed v1.
Blask to lokalny CMS do Astro 6+. Edytujesz wpisy w przeglądarce
(localhost), a Blask zapisuje pliki .md w twoim repo Astro i pcha
zmiany do git. Zero bazy danych, zero chmury, zero kont.
| Narzędzie | Astro 6 | Panel SEO | Redirecty | Polski-native |
|---|---|---|---|---|
| Keystatic | ❌ (PR #1527) | ❌ | ❌ | ❌ |
| Sveltia CMS | ❌ | ❌ | ❌ | |
| Decap CMS | ❌ | ❌ | ❌ | |
| Pages CMS | ✅ | ❌ | ❌ | ❌ |
| Blask | ✅ | ✅ | ✅ | ✅ |
Blask nie jest jeszcze na npm — na razie uruchamiasz ją z lokalnego klona repo. Komenda
npx blask initzadziała po publikacji pakietu.
# 1. sklonuj Zorzę obok swojego projektu Astro:
git clone https://github.com/maciekpaszkiewicz/blask.git
cd blask && npm install
# 2. wygeneruj blask.config.ts w root'cie swojego projektu Astro:
node bin/blask.mjs init /sciezka/do/projektu-astro
# 3. uruchom Zorzę wskazując na swój projekt:
BLASK_PROJECT=/sciezka/do/projektu-astro npm run dev
# i otwórz http://localhost:3001
⚠️ Bezpieczeństwo: Blask nie ma wbudowanej autoryzacji i ma pełny dostęp do zapisu plików +git pushw twoim repo. Trzymaj ją nalocalhost— nigdy nie wystawiaj portu publicznie bez autoryzującego reverse proxy (patrzSECURITY.md).
- Schema-driven UI — formularz auto-generowany z twoich Zod schem Content Collections
- Live preview — iframe twojego Astro dev servera, odświeża się po zapisie
- Panel SEO 17 checków w 4 sekcjach (Podstawy / Treść / AI GEO / Linki) — z patent-driven sygnałami: citable fragment density, entity salience, topic-sentence length, inline attribution, human-likeness composite. Każdy check ma rozwijany hint z numerem patentu.
- Live SERP preview — Google-style miniatura wyniku z badge'em domeny
- Social card preview — Open Graph (1200×630), X (1200×675), LinkedIn — platform-accurate rendering + warnings o brakujących polach
- JSON-LD generator + validator — Article, FAQPage, HowTo,
BreadcrumbList z auto-detect typu, copy-to-clipboard, walidacją
Verified Entity Status (sameAs/url/image/knowsAbout) i fact-data
alignment audit (liczby w schemie muszą zgadzać się z body).
Wystawia
<BlaskHead />jako Astro component (single-file, copy-paste) — to co panel zwalidował, ląduje 1:1 w twoim<head> - Redirecty — zarządzaj 301/302, automatyczne dodanie przy rename slug
- TipTap editor — markdown body z bidirectional serializacją
- Command palette — ⌘K do szybkiej nawigacji
- Multi-collection — sidebar tabs dla każdej kolekcji z
src/content/ - i18n — UI po polsku (default) lub angielsku
- Modern stack — Next.js 16, React 19, Tailwind 4, React Compiler
Panel SEO i generator JSON-LD czytają poniższe pola jeśli istnieją we frontmatterze wpisu. Wszystkie są opcjonalne — Blask działa z pustym frontmatterem, ale każde wypełnione pole odblokowuje kolejny fragment walidacji / silniejszą encję w schemie.
| Pole | Typ | Do czego |
|---|---|---|
title |
string |
Headline + Article.headline + SERP title |
description |
string |
Meta description + Article.description |
seoTitle |
string |
Override title w <title> i SERP preview |
seoDescription |
string |
Override description w meta |
focusKeyword |
string |
Driver dla 5 checków SEO (in-title / in-desc / first-para / density / entity salience) |
pubDate |
Date |
Article.datePublished |
updatedDate |
Date |
Article.dateModified |
canonical |
URL |
<link rel="canonical"> + check w panelu |
noindex |
boolean |
Ostrzeżenie w schemie + SERP preview |
tags |
string[] |
Lista tagów (chip input w AutoForm) |
tldr |
string[] |
Jeśli ≥3 items → auto-detekcja FAQPage schema |
schemaType |
'Article' | 'FAQPage' | 'HowTo' |
Wymusza typ JSON-LD |
locale |
string |
Article.inLanguage (default pl-PL) |
| Pole | Typ | Do czego |
|---|---|---|
image |
URL/path |
Article.image + fallback dla OG |
imageAlt |
string |
Alt text check (≥10 chars) |
ogImage |
URL/path |
Override dla Open Graph card |
| Pole | Typ | Do czego |
|---|---|---|
author |
string |
Person.name (lub Organization.name przy authorType) |
authorType |
'Person' | 'Organization' |
Default Person |
authorImage |
URL/path |
Person.image — silniejsza disambiguation |
authorUrl |
URL/path |
Link do dedykowanej strony autora (np. /autor/imie/) |
authorJobTitle |
string |
Person.jobTitle |
authorBio |
string |
Person.description |
authorKnowsAbout |
string[] |
Topical authority (Source Authority for Entity — US8244689B2) |
authorSameAs |
URL[] |
LinkedIn / ORCID / GitHub / Wikidata — verified entity |
| Pole | Typ | Do czego |
|---|---|---|
publisherType |
'Organization' | 'Person' |
Default Organization |
publisherLogo |
URL/path |
Wymagane przez Google Rich Results dla Article |
publisherSameAs |
URL[] |
LinkedIn company page, Wikidata, GitHub org |
Skopiuj do swojego src/content.config.ts i wyeksportuj jako named
export (Blask importuje przez blask.config.ts):
import { defineCollection, z } from 'astro:content';
export const blogSchema = z.object({
title: z.string().min(10).max(70),
description: z.string().max(165).optional(),
pubDate: z.date(),
updatedDate: z.date().optional(),
tags: z.array(z.string()).default([]),
focusKeyword: z.string().optional(),
schemaType: z.enum(['Article', 'FAQPage', 'HowTo']).default('Article'),
tldr: z.array(z.string()).optional(),
// Obrazki
image: z.string().optional(),
imageAlt: z.string().optional(),
ogImage: z.string().optional(),
// Encja autora — opcjonalne, im więcej, tym silniejsza disambiguation
author: z.string().default('Anna Kowalska'),
authorUrl: z.string().optional(),
authorImage: z.string().optional(),
authorJobTitle: z.string().optional(),
authorBio: z.string().optional(),
authorKnowsAbout: z.array(z.string()).optional(),
authorSameAs: z.array(z.string().url()).optional(),
// Encja wydawcy
publisherLogo: z.string().optional(),
publisherSameAs: z.array(z.string().url()).optional(),
// SEO advanced
canonical: z.string().url().optional(),
noindex: z.boolean().default(false),
});
const blog = defineCollection({ schema: blogSchema });
export const collections = { blog };Potem w blask.config.ts:
// blask.config.ts — plain object export (działa bez instalowania paczki).
// Po publikacji `blask` na npm możesz owinąć to w `defineConfig(...)`
// dla podpowiedzi typów: import { defineConfig } from 'blask'.
import { blogSchema } from './src/content.config';
export default {
site: { name: 'Mój blog', domain: 'mojblog.pl', defaultAuthor: 'Anna Kowalska' },
collections: { blog: { schema: blogSchema } },
};Uwaga: jeśli
blogSchemaimportujesz zastro:content, jegozto Zod 3. Blask introspektuje schematy przez Zod 4 — zbuduj schema zwykłymimport { z } from "zod"(Zod 4), inaczej formularz Fields będzie pusty.
Next.js 16 · React 19 (+ React Compiler) · TypeScript 5 · Tailwind 4 · TipTap 3 · Zod 4 · simple-git · jiti · node:fs/promises
┌─────────────────────────┐ ┌─────────────────────────┐
│ Twój projekt Astro │ │ Blask (CMS) │
│ (np. ~/sites/blog/) │ ◄─────► │ localhost:3001 │
│ │ read │ (Next.js 16) │
│ src/content/blog/*.md │ write │ │
│ src/content.config.ts │ │ ┌───────────────────┐ │
│ blask.config.ts │ │ │ Schema-driven UI │ │
│ src/redirects.json │ │ │ (AutoForm + Zod) │ │
│ .git/ │ │ └───────────────────┘ │
└──────────┬──────────────┘ │ ┌───────────────────┐ │
│ │ │ SEO panel │ │
│ git push │ │ + SERP preview │ │
▼ │ └───────────────────┘ │
┌─────────────────────────┐ │ ┌───────────────────┐ │
│ GitHub (deploy) │ │ │ Redirects 301/302│ │
│ GitHub Actions → │ │ └───────────────────┘ │
│ Cloudflare/Vercel/... │ └─────────────────────────┘
└─────────────────────────┘
Zero bazy danych, zero chmury, zero kont. Pliki .md żyją w twoim repo,
Blask jest tylko narzędziem do edycji.
Blask generuje JSON-LD i pokazuje walidację w UI, ale finalnie schema
musi wyemitować twoja strona Astro. Najmniej tarcia: skopiuj
astro/BlaskHead.astro z repo Zorzy do src/components/ twojej
strony i wstaw w <head>:
---
// src/layouts/BlogLayout.astro
import BlaskHead from '../components/BlaskHead.astro';
const { entry } = Astro.props;
---
<html lang="pl">
<head>
<BlaskHead
entry={entry}
siteName="Mój blog"
siteDomain="mojblog.pl"
defaultAuthor="Anna Kowalska"
collection="blog"
/>
</head>
<body><slot /></body>
</html>Komponent emituje <title>, meta description, robots, canonical, OG,
Twitter Card i dwa bloki <script type="application/ld+json"> (główna
schema + BreadcrumbList). Logika lustruje src/lib/schema-generator.ts
z Zorzy — czyli to co pokazał panel SEO ("schema passes validation")
jest dokładnie tym co dostaje twój <head>. Zero external runtime
dependencies, jeden plik, copy-paste.
Pełna dokumentacja w astro/README.md.
git clone https://github.com/maciekpaszkiewicz/blask.git
cd blask
npm install
# w innym katalogu — twoja strona Astro z plikiem blask.config.ts
BLASK_PROJECT=/path/to/your/astro-site npm run devPatrz ARCHITECTURE.md dla docelowej architektury,
ROADMAP.md dla planowanych funkcji w v1, oraz
CONTRIBUTING.md jeśli chcesz dorzucić PR.
Soft launch (obecny stan):
- ✅ Schema-driven AutoForm z Zod
- ✅ Multi-collection sidebar
- ✅ Panel SEO (17 checków w 4 sekcjach, w tym AI/GEO)
- ✅ JSON-LD generator + validator (Article/FAQPage/HowTo/BreadcrumbList) z fact-data alignment audit
- ✅ Social card preview (OG / X / LinkedIn)
- ✅ SERP preview (Google-style)
- ✅ Redirecty 301/302 z auto-add przy rename
- ✅ CLI
npx blask init - ✅ i18n EN + PL
Kolejna iteracja (v1, po walidacji community) — patrz
ROADMAP.md:
- Plugin system / custom widgets
- Image management (drag&drop, WebP)
- Multi-theme (poza butelkową zielenią)
- Documentation site
- Testy (Playwright + Vitest)
MIT © 2026 Blask Contributors