@hagicode/hagilight · Standalone Astro example

Explore Hagilight core, without Starlight.

A bilingual, standalone Astro tour of the shared components and build integrations in @hagicode/hagilight.

Explore the features

Live on this page

These are real package components, rendered here rather than recreated as mockups.

Opt-in page · built-in presentation

Root transit

The root opens @hagicode/hagilight-core/RootTransit before forwarding here. Its styling, route sweep, static continuation link and navigation are bundled, and it shows one random image from the img-gen startup splash while it forwards (@hagicode/hagilight-core/splash-images holds the image paths; splash={false} opts out). A departures board scrolls through the HagiCode ecosystem sites in the page language and stops on this site (@hagicode/hagilight-core/root-transit-board builds its rows; board={false} hides it). @hagicode/hagilight-core/root-transit exposes the tested URL and lifecycle helpers.

Evidence: Open the site root to see the transition, or follow its continuation link immediately.

import RootTransit from '@hagicode/hagilight-core/RootTransit';

<RootTransit destination="/en-US/" siteName="Hagilight" />

Live in footer · build-time resolver

Build line

The footer ends with Branch, Commit, and Built. @hagicode/hagilight-core/build-info formats them in the browser, while @hagicode/hagilight-core/build-info-resolver reads Git and the HAGILIGHT_BUILD_BRANCH and HAGILIGHT_BUILD_COMMIT overrides at build time.

Evidence: The footer copyright line shows this demo’s branch, its seven-character commit, and the UTC build time.

import { buildInfoItems } from '@hagicode/hagilight-core/build-info';
import { resolveBuildInfo } from '@hagicode/hagilight-core/build-info-resolver';

const items = buildInfoItems(resolveBuildInfo({ root: process.cwd() }));

Build output · schema version 1

Site metadata file

The build writes .well-known/hagilight.metadata.json with site identity, locales, build facts, discovery artifacts, and analytics on/off flags. @hagicode/hagilight-core/site-metadata holds the contract, @hagicode/hagilight-core/site-metadata-writer writes it in Node, and @hagicode/hagilight-core/site-metadata-ownership decides which integration writes it.

Evidence: This demo build contains .well-known/hagilight.metadata.json, and its discovery block lists the llms.txt and sitemap that the build produced.

import { buildSiteMetadata, serializeSiteMetadata } from '@hagicode/hagilight-core/site-metadata';

const json = serializeSiteMetadata(buildSiteMetadata({ generator, site, build, discovery, analytics }));

Live component · remote campaign optional

Promotion banner

PromotoBanner prefers an eligible remote campaign and uses the localized fallback when none is available; @hagicode/hagilight-core/promoto-analytics reports impressions, dismissals and paging to PostHog, and @hagicode/hagilight-core/promotions exposes the typed campaign loader, and @hagicode/hagilight-core/promoto-banner exposes the framework-neutral custom element that the Docusaurus package mounts.

Evidence: The banner is mounted on this page; its fallback CTA jumps to the footer, where the component hides itself.

import PromotoBanner from '@hagicode/hagilight-core/PromotoBanner';

<PromotoBanner locale="en-US" fallback={fallbackCard} />

Page head and build outputs

These integrations produce metadata, a browser icon, or a feed—not additional page widgets.

Live in document head

SEO head

SEOHead emits a route-specific canonical URL plus Open Graph and Twitter title/description metadata.

Evidence: Inspect this page’s document head and view-source for its canonical and sharing fields.

import SEOHead from '@hagicode/hagilight/SEOHead';

const site = Astro.site.href;
const pageUrl = new URL(Astro.url.pathname, site).href;

<SEOHead
  site={site}
  page={{ url: pageUrl, title, description }}
  structuredData={pageStructuredData}
/>

Build-time tools

SEO helpers and schema

Utilities build safe canonical and JSON-LD data; seoSchema validates optional frontmatter fields; classifyOgImage reports whether a preview image format is crawler-readable.

Evidence: The JSON-LD scripts in this page head contain only the demo site and page facts.

import { buildBreadcrumbStructuredData } from '@hagicode/hagilight-core/seo';
import { seoSchema } from '@hagicode/hagilight-core/seo-schema';
import { classifyOgImage } from '@hagicode/hagilight-core/og-image';

const pageSeo = seoSchema.parse({ seo: { title, description } });
const imageFormat = classifyOgImage('/social/card.avif'); // 'convertible'

Build-time helper

Entity definition

getEntityDefinition returns the one shared sentence that defines the product, in the requested locale with an en-US fallback. buildSoftwareApplicationStructuredData turns product facts into SoftwareApplication JSON-LD.

Evidence: The definition is the single source for the page lead, the llms.txt summary and the SoftwareApplication description.

import { getEntityDefinition } from '@hagicode/hagilight-core/entity-definition';
import { buildSoftwareApplicationStructuredData } from '@hagicode/hagilight-core/seo';

const definition = getEntityDefinition(Astro.currentLocale); // falls back to en-US
const app = buildSoftwareApplicationStructuredData({
  name: 'Example App',
  applicationCategory: 'DeveloperApplication',
  operatingSystem: 'Linux',
  description: definition,
});

Live in browser tab · build integration

Favicon

The Astro integration adds the bundled favicon; the package also exports the favicon.ico asset for static copying.

Evidence: Look at the browser tab icon. The integration injects its data URI into the generated page head.

import { hagilightFavicon } from '@hagicode/hagilight/integration';
import { resolveFaviconHeadEntry } from '@hagicode/hagilight-core/favicon';
import favicon from '@hagicode/hagilight-core/favicon.ico';

integrations: [hagilightFavicon()]
<link rel="icon" href={favicon} type="image/x-icon" />

Live build output · localized integration

RSS feed

The integration generates locale-specific routes from site-owned feed data; the core RSS renderer remains available for consumer-owned routes, and @hagicode/hagilight-core/rss-ownership lets a Starlight plugin in the same project own the routes.

Evidence: Use the RSS link in the header or footer to open the English or current-language feed.

import { hagilight, type RssFeedCallback } from '@hagicode/hagilight/integration';

integrations: [hagilight({ rss: { getFeed: './src/rss-feed.ts' } })]

Body content

Markdown images are normalized while the site builds; the page adds no runtime script for them.

Build-time Markdown plugin · automatic with hagilight()

Content images

Markdown and MDX body images outside picture elements get lazy and async loading defaults plus the hagilight-content-image class. Author-set loading and decoding values are kept.

Evidence: The sample below comes from a Markdown file with a relative local image and a site-root image; their img elements carry the marker class.

import { rehypeContentImages } from '@hagicode/hagilight-core/content-images';

// Automatic with hagilight(); opt out with hagilight({ contentImages: false })

Shared data

Packaged data and contracts that other sites can read without keeping their own copy.

Packaged data · browser-safe contract, Node loaders and raw JSON

Comparison article data

The comparison articles ship inside the package. @hagicode/hagilight-core/comparison-articles holds the browser-safe contract, @hagicode/hagilight-core/comparison-articles-source loads the packaged files in Node, and @hagicode/hagilight-core/comparison-articles-data/*.json imports one article as raw JSON.

Evidence: The data is not rendered on this page; the example shows how a consumer reads it.

import { buildStructuredArticleRootManifest } from '@hagicode/hagilight-core/comparison-articles-source';
import { validateStructuredArticleDetail } from '@hagicode/hagilight-core/comparison-articles';
import claude from '@hagicode/hagilight-core/comparison-articles-data/en-US/claude-vs-hagicode.json' with { type: 'json' };

const manifest = await buildStructuredArticleRootManifest();
const article = validateStructuredArticleDetail(claude);

Optional integrations

PostHog runs in production on this showcase. Google Analytics and 51LA remain optional examples.

Optional · production-only scripts

PostHog, Google Analytics and 51LA

The hagilight() integration injects PostHog with the supplied project key, no props needed; Google Analytics and 51LA require an ID. All three emit third-party tracking scripts only in production builds. GoogleAnalytics also reports clicks on tagged links as link_click or download_click events; @hagicode/hagilight-core/analytics-events exposes the typed tag builders. @hagicode/hagilight-core/posthog-events holds the closed PostHog event vocabulary, the property sanitizer and the cta_click capture helper. @hagicode/hagilight-core/posthog-interactions installs the delegated observers for Pagefind search, code copy buttons and promotion impressions; they only read the DOM and never throw.

Evidence: PostHog is injected once into every page head by the integration. Production visits send activity to the shared HagiCode project.

// astro.config.mjs: hagilight() injects PostHog into every production head.
hagilight({ analytics: { posthog: { enabled: false } } }); // opt out

// Custom head only: render the shared component once when the integration is not the owner.
import PostHog from '@hagicode/hagilight-core/PostHog';
import { posthogInitScript } from '@hagicode/hagilight-core/posthog';

<PostHog />

import GoogleAnalytics from '@hagicode/hagilight-core/GoogleAnalytics';
import Analytics51LA from '@hagicode/hagilight-core/Analytics51LA';

{import.meta.env.PUBLIC_GA_ID && <GoogleAnalytics measurementId={import.meta.env.PUBLIC_GA_ID} />}
{import.meta.env.PUBLIC_51LA_SITE_ID && <Analytics51LA siteId={import.meta.env.PUBLIC_51LA_SITE_ID} />}

import { gaEventAttributes } from '@hagicode/hagilight-core/analytics-events';

<a href="/download" {...gaEventAttributes({ category: 'download', label: 'customDownload', location: 'footer' })}>Download</a>

Markdown body images

Body images in this Markdown file are normalized at build time by hagilight(), with no runtime script.

A teal and lime gradient with a cream circle, used as a relative local image

A warm gradient stored in the source assets folder and imported by the page

Images outside a <picture> element get loading="lazy", decoding="async", and the hagilight-content-image class. Values the author already set are kept. Pass contentImages: false to hagilight() to turn this off for the site.

Promotion example: eligible remote campaigns may replace this local fallback. It links to the footer to demonstrate the component’s visibility behavior.