Day 1 (monorepo + Node layout engine): - Turborepo + pnpm workspaces with apps/web, apps/render-worker, and packages for types, layout-engine, prompts, api-lib. - @banner-studio/types: BannerSpec contract, every layer kind, ResolvedLayer, zod schemas mirroring each interface. - @banner-studio/layout-engine: Dropflow WASM wrapper, text measurement, shrink-to-fit, push_siblings, resolveLayout. Snapshot-tested. Day 2 (browser parity + AI pipeline): - Layout engine ./browser subpath: same resolveLayout in the browser via Dropflow WASM build. Quarantined wasm-locator import (dropflow 0.5.1 exports gap). - Cross-group push_siblings bug fix: deltas now thread through group recursion via a shared accumulator; regression test added. - DEMO_TEMPLATE_300x250 promoted to packages/layout-engine/src/templates/. - @banner-studio/prompts: versioned extract + generate prompts with zod-defined tool schemas (claude-sonnet-4-6, forced tool-use). - @banner-studio/api-lib: CSV feed loader, extract/generate/route-node/ assemble agents, orchestrator returning fully-resolved BannerSpec. Generate agent retries on character-limit overflow. - apps/web (Next.js 14 App Router): /api/generate route, /parity diff page, promise-singleton browser engine init. - feeds/demo.csv with five hand-authored rows of varied length. - SLICE_DEVIATIONS.md documents the five intentional gaps from ARCHITECTURE.md with V1 reversal paths. Verified end-to-end: POST /api/generate against the live Claude API returns three resolved BannerSpecs and two honestly-skipped rows (overflow after two attempts). 26 unit + integration tests passing.
47 lines
1.8 KiB
JavaScript
47 lines
1.8 KiB
JavaScript
#!/usr/bin/env node
|
|
// Copies the dropflow wasm bundle and the Inter TTFs into apps/web/public
|
|
// so the browser can fetch them. Run with `pnpm prepare:web-assets`.
|
|
//
|
|
// Uses require.resolve so the dropflow lookup works across npm/pnpm/yarn
|
|
// without hardcoding node_modules/.pnpm paths.
|
|
|
|
import { mkdir, copyFile } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { createRequire } from 'node:module';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const repoRoot = path.resolve(__dirname, '..');
|
|
// dropflow is a dep of @banner-studio/layout-engine, not the root package, so
|
|
// resolve relative to that package's location.
|
|
const require = createRequire(
|
|
path.join(repoRoot, 'packages', 'layout-engine', 'package.json')
|
|
);
|
|
|
|
const publicDir = path.join(repoRoot, 'apps', 'web', 'public');
|
|
const fontsDir = path.join(publicDir, 'fonts');
|
|
|
|
async function main() {
|
|
await mkdir(publicDir, { recursive: true });
|
|
await mkdir(fontsDir, { recursive: true });
|
|
|
|
// dropflow wasm: resolve via an exported subpath, then walk to dropflow.wasm
|
|
// (which is also in `exports` as ./dropflow.wasm — resolve it directly).
|
|
const wasmSrc = require.resolve('dropflow/dropflow.wasm');
|
|
const wasmDst = path.join(publicDir, 'dropflow.wasm');
|
|
await copyFile(wasmSrc, wasmDst);
|
|
console.log(`copied dropflow.wasm -> ${path.relative(repoRoot, wasmDst)}`);
|
|
|
|
// Inter TTFs from infra/fonts.
|
|
for (const file of ['Inter-Regular.ttf', 'Inter-Bold.ttf']) {
|
|
const src = path.join(repoRoot, 'infra', 'fonts', file);
|
|
const dst = path.join(fontsDir, file);
|
|
await copyFile(src, dst);
|
|
console.log(`copied ${file} -> ${path.relative(repoRoot, dst)}`);
|
|
}
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|