@hagicode/hagilight-starlight 0.7.1-dev.80.1.bc52dbd → 0.7.1-dev.82.1.769c313

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  ---
2
- import { Image } from 'astro:assets';
2
+ import { Picture } from 'astro:assets';
3
3
  import { gaEventAttributes } from '@hagicode/hagilight-core/analytics-events';
4
4
  import { resolveSiteLinks } from '@hagicode/hagilight-core/links';
5
5
  import { getArticlePromotionCopy } from './dist/article-promotion.js';
@@ -90,11 +90,13 @@ const gallery = copy.gallery.flatMap((item) => {
90
90
  {gallery.map((item) => (
91
91
  <li>
92
92
  <figure>
93
- <Image
93
+ <Picture
94
94
  src={item.image}
95
95
  alt={item.alt}
96
96
  width={item.image.width}
97
97
  height={item.image.height}
98
+ formats={['avif', 'webp']}
99
+ fallbackFormat="jpeg"
98
100
  widths={[480, 800, item.image.width]}
99
101
  sizes="(min-width: 50rem) 560px, 100vw"
100
102
  loading="lazy"
@@ -314,6 +316,10 @@ const gallery = copy.gallery.flatMap((item) => {
314
316
  margin: 0;
315
317
  }
316
318
 
319
+ .hagilight-article-promotion picture {
320
+ display: block;
321
+ }
322
+
317
323
  .hagilight-article-promotion img {
318
324
  display: block;
319
325
  width: 100%;
package/README.md CHANGED
@@ -85,14 +85,26 @@ The gallery images and pillar icons live in `assets/showcase/`, with a provenanc
85
85
 
86
86
  Every asset passes the same audit before it is committed: the current `HagiCode` brand, no Steam or other retired-channel content, no third-party promotion, no credentials, private repository names, or personal data, and rasters at least 1200 px wide. A removable offending region may be cropped out, and the crop is recorded. Pick images in this order to keep traffic low: an audited existing image converted to WebP, then a hand-authored SVG, then a newly generated raster only when neither fits. Generated art is an illustration, never a replica of the product UI, contains no text or logos, is captioned as an illustration, is reviewed by a person, and records its prompt and parameters (never credentials). Generation is an authoring step; the package never calls a generator.
87
87
 
88
- Budgets, enforced by `npm test`: 768 KiB for all showcase images together, 200 KiB per raster (WebP only), and 8 KiB per SVG. Images are served through Astro's image pipeline as responsive, content-hashed files, load lazily with low priority, and sit after the article body, so a reader who does not reach the end downloads none of them.
88
+ Budgets for the shipped sources, enforced by `npm test`: 768 KiB for all showcase sources together, 200 KiB per raster source (WebP only), and 8 KiB per SVG. `npm run build:example` also checks the built output: each delivered raster variant at most 200 KiB, the variants of one format at most 768 KiB together, and each AVIF variant smaller than the WebP variant of the same width.
89
+
90
+ Each gallery image renders as a `<picture>` with an AVIF source, a WebP source, and a JPEG `<img>` fallback, at widths 480, 800, and the native width. The tiers are derived at the consumer's build from the shipped WebP, with the `sharp` service that Astro already bundles, so no conversion runs outside the site's own build and no external service is involved. The chain needs a transforming image service: with the passthrough `astro/assets/services/noop` service the tiers serve the original bytes, and the plugin logs one warning. Opaque images use the JPEG tier. The JPEG tier cannot carry transparency, so an image that needs alpha needs a PNG tier, which the component does not offer yet, and a budget review before it is added.
91
+
92
+ Images are served through Astro's image pipeline as responsive, content-hashed files, load lazily with low priority, and sit after the article body, so a reader who does not reach the end downloads none of them.
93
+
94
+ Measured on `examples/demo-starlight-web` with one warm build each: the nine AVIF variants total 139.0 KiB (largest 41.4 KiB) and the nine JPEG variants total 387.4 KiB (largest 118.2 KiB). The shipped WebP sources are unchanged. The build took 21.6 s without the tiers and 20.4 s with them, a difference within run-to-run noise. A browser that supports AVIF downloads one variant per image, the AVIF one.
95
+
96
+ #### Adopting and verifying
97
+
98
+ Upgrading `@hagicode/hagilight`, `@hagicode/hagilight-starlight`, and `@hagicode/hagilight-core` together is the whole change. It needs no configuration, dependency, script, or CI step: the consumer's existing build derives the tiers. If the build logs the passthrough image service warning, remove the `image` service override or use the default `sharp` service.
99
+
100
+ To check a deployed site, run `curl -sI https://<site>/_astro/<file>.avif` with a real file name from the built `dist/_astro`; it should report `Content-Type: image/avif`. `docs` also previews on Azure Static Web Apps, so check that preview as well. Any host header fix belongs to the owning repository, not to this package.
89
101
 
90
102
  #### Keep it in sync
91
103
 
92
104
  The copy and assets mirror `repos/web` and `repos/docs` in the HagiCode monorepo, which this package never edits.
93
105
 
94
106
  - **Copy:** edit `src/article-promotion-copy/<locale>.ts` (every locale must keep the same fields, feature ids, and gallery ids). Terminology is pinned in `GLOSSARY` in `src/article-promotion-copy/index.ts`, seeded from the product locale files in `repos/web/src/locales/<locale>/`. `HagiCode`, `OpenSpec`, `Hero Dungeon`, `Microsoft Store`, and `Windows` are never translated.
95
- - **Images:** audit the candidate, crop and convert it to WebP, add or update its `manifest.json` entry, register it in the `galleryImages` map in `ArticlePromotion.astro`, and add a caption and text alternative in every locale. The gallery mosaic places the first, second, and third catalog entries as the left top, left bottom, and right tall slot, so keep the gallery at three images or revisit the placement in the component's `@container (min-width: 36rem)` block. `npm test` checks that the manifest, the files, the component registry, and the copy agree.
107
+ - **Images:** audit the candidate, crop and convert it to WebP (the AVIF and JPEG tiers are derived at build time, so an opaque image needs no extra file), add or update its `manifest.json` entry, register it in the `galleryImages` map in `ArticlePromotion.astro`, and add a caption and text alternative in every locale. The gallery mosaic places the first, second, and third catalog entries as the left top, left bottom, and right tall slot, so keep the gallery at three images or revisit the placement in the component's `@container (min-width: 36rem)` block. `npm test` checks that the manifest, the files, the component registry, and the copy agree.
96
108
  - **Badge:** the product id is parsed from the Store URL and the badge language map lives in `src/windows-download.ts`. Re-check both against `repos/docs/src/components/MicrosoftStoreBadge.tsx` and the official site when the Store listing or the supported languages change.
97
109
 
98
110
  The plugin footer and direct `/Footer` and `/PromotoFooter` components append
package/dist/index.js CHANGED
@@ -27,6 +27,8 @@ function optionalBoolean(record, key, label) {
27
27
  }
28
28
  return value;
29
29
  }
30
+ const NOOP_IMAGE_SERVICE = 'astro/assets/services/noop';
31
+ const NOOP_IMAGE_SERVICE_WARNING = '@hagicode/hagilight-starlight: the Astro image service is the passthrough no-op, so the showcase AVIF and JPEG tiers will serve the original bytes. Use the default sharp service or another transforming image service.';
30
32
  const GOOGLE_ID_PATTERN = /^G-[A-Z0-9]+$/u;
31
33
  const FIFTY_ONE_LA_ID_PATTERN = /^[A-Za-z0-9_-]+$/u;
32
34
  const DEFAULT_GOOGLE_ANALYTICS_ID = 'G-EN03FMT2Q4';
@@ -316,8 +318,11 @@ const isNotFound = /(?:^|\\/)404(?:\\.html)?\\/?$/u.test(Astro.url.pathname);
316
318
  }
317
319
  updateConfig({ vite: { plugins: [vitePlugin] } });
318
320
  },
319
- 'astro:config:done'() {
321
+ 'astro:config:done'({ config, logger }) {
320
322
  unregisterRssOwner();
323
+ if (config.image?.service?.entrypoint === NOOP_IMAGE_SERVICE) {
324
+ logger.warn(NOOP_IMAGE_SERVICE_WARNING);
325
+ }
321
326
  },
322
327
  },
323
328
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hagicode/hagilight-starlight",
3
- "version": "0.7.1-dev.80.1.bc52dbd",
3
+ "version": "0.7.1-dev.82.1.769c313",
4
4
  "type": "module",
5
5
  "description": "Starlight plugin and components for HagiCode documentation",
6
6
  "repository": {
@@ -53,7 +53,7 @@
53
53
  "assets/showcase/*"
54
54
  ],
55
55
  "dependencies": {
56
- "@hagicode/hagilight-core": "0.7.1-dev.80.1.bc52dbd"
56
+ "@hagicode/hagilight-core": "0.7.1-dev.82.1.769c313"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "@astrojs/starlight": "^0.42.4",