@czap/astro
v0.10.0
Published
The Astro integration for LiteShip: render adaptive UI as islands with the `client:satellite` directive and resolve device tiers on the server for first paint.
Maintainers
Readme
@czap/astro
Astro 7 integration that compiles your boundary definitions at build time and activates their state evaluators on the client.
Install this directly when your site is built on Astro 7 — this is the integration most LiteShip projects install first. The other
@czap/*runtime packages arrive with it.
Install
pnpm add @czap/astro @czap/core effect@betaeffect must be the Effect 4 beta (effect@beta) — a bare pnpm add effect installs 3.x and fails the peer check.
30 seconds
// astro.config.mjs
import { defineConfig } from 'astro/config';
import { integration as czap } from '@czap/astro';
export default defineConfig({ integrations: [czap()] });
// src/boundaries.ts — a boundary names where one state becomes the next
import { Boundary } from '@czap/core';
export const viewport = Boundary.make({
input: 'viewport.width',
at: [[0, 'stacked'], [768, 'split']],
hysteresis: 20, // 20px of grace so the state doesn't flicker
});---
// src/pages/index.astro
import Satellite from '@czap/astro/Satellite';
import { viewport } from '../boundaries.js';
---
<Satellite boundary={viewport}>
<section>Resize the window.</section>
</Satellite>Drag the window edge across 768px: the wrapper's data-czap-state attribute flips between stacked and split for your CSS to key on. No client:* attribute needed — the integration's injected boot script activates the evaluator.
czap({ middleware: true }) auto-wires capability detection, so the common case needs no src/middleware.ts; it populates a typed Astro.locals.czap.tiers.{tier,motion,design} (no cast). Astro 7 hosts that need CZAP before Astro's page pipeline can use czapFetchLayer() from @czap/astro/fetch-layer. Boundaries can also bind live audio.amplitude / audio.beat signals (driveAudioFromAnalyser from @czap/astro/runtime), and the dev boundary inspector ships as an Astro dev-toolbar app (toggle from the toolbar icon).
Continuous authored motion has a production runtime: czap({ motion: { enabled: true } }) registers client:motion, the JS FLOOR for the scroll-scrubbed reveal. Native animation-timeline CSS (from MotionCompiler) owns the scrub where supported; everywhere it is not, client:motion reads the SSR-inlined lowered program off data-czap-motion-program and drives writeContinuousMap every frame — sampling the SAME Easing.spring the native linear() compiled from, so the two paths render one identical curve. The continuous tween is a leaf write (never a graph patch); prefers-reduced-motion with a settle policy pins the final pose with no tween. Runnable in examples/showcase at /motion.
Responsive media adapts at the host: Astro.locals.czap.responsiveMedia(intent) derives Save-Data / DPR caps from the request's Client Hints and projects a ResponsiveMedia.intent through the ONE effective-candidate law (selectCandidates in @czap/core). Every artifact — src, srcset, each <source>, the preload imagesrcset — derives from that set, so under Save-Data the whole picture is capped to the light asset and a high-DPR client can never re-fetch the heavy hero. The middleware also merges the responsive Vary axis (Sec-CH-DPR, Save-Data) into the response so a CDN keys the two representations apart. projectResponsiveMediaForRequest / applyResponsiveMediaVary are the standalone route-handler helpers. Runnable in examples/showcase at /responsive-media (and examples/cloudflare-astro on the Workers edge).
Where it sits
The host integration most apps touch: it registers @czap/vite (build-time boundary scanning and CSS), injects @czap/detect's device-tier probe, and rigs the client directives backed by @czap/web (DOM morphing, SSE, LLM streams) and @czap/worker (off-thread evaluation), with @czap/edge supplying SSR tier detection for the optional middleware. Boundary authoring itself lives in @czap/core; Cloudflare deploys add @czap/cloudflare on top. See the
package surfaces map
for the full layout.
If it does nothing
If data-czap-state never changes on resize, the boot script was never injected — confirm czap() is in integrations in astro.config.mjs. Astro's own client:visible / client:idle directives do not wire the evaluator; Satellite (or satelliteAttrs(...) spread onto any element) emits the data-czap-directive="satellite" marker the boot scanner looks for.
Docs
- Getting started
- LiteShip for Astro static sites — the authoring mental model
- Glossary — the vocabulary used above
- API reference — generated from source
Part of LiteShip — powered by the CZAP engine (Content-Zoned Adaptive Projection), distributed as @czap/* packages.
