README.md
README.md is a file in Bane's Lab Social Share. 113 lines of code and 0 definitions.
<!-- Auto-generated 2026-10-04T16:25Z v8 -->
# @banes-lab/social-share
<!-- concern:overview -->
## Purpose
The entry points live under `runtime/entrypoints/`.
`stage.entrypoint.ts` is the browser entry of the stage page. With no query, it lays out every registered card at every profile it declares and plays each timeline at the output frame rate, with hot reload on every plugin, stylesheet, shader, helper and config edit. With `?card=<id>&profile=<id>`, it mounts one card at full size and exposes a frame hook for capture.
`card.entrypoint.ts` validates every card, opens the same stage over HTTPS in a headless browser, resamples each timeline at the output rate by evaluating the expressions at fractional frames, and captures every sample. It encodes the frames into one lossless master video through ffmpeg. From the master it derives, at each output scale per profile, an animated GIF with a palette built for that loop and a playable MP4. Beside them it writes a PNG still of the key frame and an animated WebP, all named `<card>-w<width>-h<height>.<profile>.generated.<ext>` under the public share folder. An MP4 takes the nearest even size its codec requires.
The export records each card and profile's spec hash in the share ledger and writes the page-to-image map the web member's head reads. Each page links the largest GIF of its card's share profile, at or below three-quarter size, that fits the share size limit. It declares no video, because a platform shows a declared video as a player behind a play button, while an animated GIF plays in the preview on its own. The MP4 stays in the share folder for posting by hand.
`validation.entrypoint.ts` is the gate step. It validates every spec on every frame and holds every looping card to a loop with no visible seam. It holds every page the site registers to exactly one card, and every card to its page's tone, headline, tagline and the site marks. It then reports a missing image, an orphan image, a ledger hash that differs from the current spec's hash, and a stale share map.
Cards live in `cards/<id>/`, one folder per page holding a `plugins/<id>.plugin.ts` that calls `registerCard(createPageCard({ id, page }), import.meta.url)`, plus any styles and shaders of its own. The page template reads the page's accent, icon, headline and tagline from the web member's page record, so every card shares one composition in its own tone. The barrel under `core/plugins/` discovers the plugins by glob, and the folder name is the card id.
Every failure is loud:
- an unknown curve, effect, anchor, card or profile throws
- a shader that fails to compile throws with its compiler messages
- a stage error fails the capture
- a missing ffmpeg names the install
- a browser call that errors, closes or stalls rejects
<!-- /concern:overview -->
<!-- concern:use -->
## When to use
- Giving a new page the share image the gate demands. Declare the page's accent and share copy on its record, and add a card folder whose plugin calls the page template with the page id. Preview it with `npm run social:dev`, then export with `npm run social`.
- Changing how an existing card looks or moves. Edit its plugin, stylesheet, shader or layout data while the preview runs, then export again so the gate's hash check passes.
- Adding a target size or platform. Add a profile to the output config, and every card that lists it renders at it on the next export.
## When NOT to use
- Designing a one-off share image outside the brand. Every card is built from the page template, and the gate reports a card that leaves its page's tone or drops a brand part.
- Rendering images at request time. The export is deterministic and on demand, and the site serves only the committed files.
<!-- /concern:use -->
<!-- concern:charts -->
## Architecture charts
The structure, logical-flow and dependency diagrams derived from the source AST live in [_code.info.generated/mermaid-charts.generated.md](./_code.info.generated/mermaid-charts.generated.md).
<!-- /concern:charts -->
<!-- concern:install -->
## Install
A private workspace member resolved through the root `package.json` workspaces list. One `npm install` at the repo root is the whole setup. It declares its `@banes-lab/*`, `@govlab/*`, `@project/*` and `@ssot/*` siblings and no third-party dependency of its own, because the image encoder and the WebGPU types are root dependencies. The export and the gate step need a Chrome or Edge binary, a card with a shader layer renders on the GPU, and the export needs an `ffmpeg` binary on the path.
## Quick start
```sh EXAMPLE: Preview every card live while editing
npm run social:dev
```
```sh EXAMPLE: Export every card's stills, animations, videos and the share map
npm run social
```
```sh EXAMPLE: Export one card
npm run social -- --card grammar
```
```sh EXAMPLE: Check every card and its exported images the way the gate does
node banes-lab.root/banes-lab.social-share/runtime/entrypoints/validation.entrypoint.ts
```
```ts EXAMPLE: Register a page's card from its plugin, with the brand mark its page declares
import { FAQ_CARD } from "#core/ids/card.ids";
import { FAQ_PAGE } from "@banes-lab/web/core/ids/page.ids.ts";
import { createPageCard } from "#core/factories/page.factory";
import { registerCard } from "#core/registries/card.registry";
registerCard(createPageCard({ id: FAQ_CARD, page: FAQ_PAGE }), import.meta.url);
```
<!-- /concern:install -->
<!-- concern:api -->
## API
The package exposes no public API.
<!-- /concern:api -->
<!-- concern:config -->
## Configuration
- `configuration/configs/card.config.ts` — the target profiles and their pixel sizes, the profile and scale the site links, the share size limit, the default timeline, the output frame duration, the output scales, the GIF dither, palette mode and palette size, the video quality and the WebP quality.
- `configuration/constants/card.constants.ts` — the timeline bounds, the shader uniform slots, the loop seam tolerances, the stage's class names, query parameters and page hooks, and the output and work file names.
- `core/schemas/card.schema.ts` — the style keys a layer may set and the bounds a placement and an opacity must stay inside on every frame.
- `configuration/data/page.data.ts` — the page template's timeline, its wide and square layout for the mark, the byline and the address, the text column's sizes, leading and gaps, and the motion values of the title glow, the rule shimmer and the pools.
- `configuration/data/site.data.ts` — the site host and the text marks every card must show: the site name and the author's byline.
<!-- /concern:config -->
<!-- concern:deps -->
## Dependencies
- `@banes-lab/build-scripts`
- `@banes-lab/web`
- `@govlab/argv`
- `@govlab/canonical-write`
- `@govlab/context`
- `@ssot/paths`
- `@ssot/secrets`
<!-- /concern:deps -->
<!-- concern:ai-context -->
## AI context
- The preview and the export run the same stage page, so a card looks the same in both by construction.
- An animation layer never plays on its own clock: the stage decodes its image and draws the frame the card's time selects, so the capture is deterministic and the loop stays in step.
- The share ledger holds one spec hash per card and profile. The file names carry no hash, so the gate reads the ledger to tell a current image from a stale one.
- Card ids, page ids and the copy a reader sees come from the web member's ids, records and strings modules, and a plugin never spells them.
- A card serves exactly one page by its type, so the page-to-card mapping cannot fan out. The gate closes the other direction by demanding one card for every registered page.
- A new card id outside the closed subject vocabulary is a maintainer-approved taxonomy edit before its folder exists.
<!-- /concern:ai-context -->
<!-- concern:domains -->
## Domains
This package serves these software domains, which `_manifest.json` declares in `domains` from the two-tier software-domain vocabulary (`meta → sub`):
- **developer-tooling** — code-generation
<!-- /concern:domains -->
<!-- concern:quality-governance -->
## Quality governance
The canonical quality catalog resolves the quality concepts that govern this package. `_manifest.json` declares them in `governedBy`, and a lint package derives them from the concepts its own rules enforce. Each maps to the custom lint rules that enforce it:
- **separation-of-concerns** — _complexity_
- **type-safety** — _correctness_
<!-- /concern:quality-governance -->
<!-- concern:disposal -->
## Disposal
- Remove the member's workspace entry and its `social` and `social:dev` scripts from the root `package.json`, and its `social` id from the docs members list in the governance config.
- Remove its governed-root entry from `containers` and `specialContainers` in `.govlab/shared/configs/taxonomy.config.ts`.
- Remove the `social`, `shares`, `shareMap` and `shareLedger` keys from the `app` branch and the `social` key from the testing branch of `project.paths/paths.yaml`.
- Remove the share map import from the web member's page renderer, the member row and the social validation step from the gate's stage list, delete the directory and the share folder, reinstall, run the gate.
<!-- /concern:disposal -->
<!-- concern:rendering-and-healing -->
## Rendering And Healing
- Each card and profile is fingerprinted from its resolved frames, the encoding settings, the bytes of the images it shows and the stylesheets the stage loads. The ledger records the fingerprint each pair was rendered from.
- `npm run social` renders only the pairs whose fingerprint changed or whose files are missing, and reports the rest as up to date. `--force` renders every pair, and `--card <id>` narrows to one card.
- The gate's validation step heals outdated outputs on its own: with valid specs it renders exactly the outdated pairs, rewrites the ledger and the share map, checks again, and fails on anything still out of date. A spec finding is reported, never healed.
<!-- /concern:rendering-and-healing -->
<!-- concern:metrics -->
---
experimental · 0 exports · 7 deps · 0 principles · 2 concepts
<!-- /concern:metrics -->