feat: Add poster-generator AgentKit#77
Conversation
📝 WalkthroughWalkthroughAdds a new Next.js poster generation app under Changes
Sequence DiagramsequenceDiagram
actor User
participant Browser as Poster Studio UI
participant API as Next.js API (/api/generate-poster)
participant Lamatic as Lamatic GraphQL Service
User->>Browser: Enter prompt & click Generate
Browser->>Browser: Validate prompt (Zod)
Browser->>API: POST /api/generate-poster { prompt }
API->>API: Validate prompt (Zod)
API->>Lamatic: POST /endpoint (Bearer + project headers, executeWorkflow)
activate Lamatic
Lamatic->>Lamatic: Execute workflow (Intent → Design Spec → Code Gen)
Lamatic-->>API: JSON response (data.executeWorkflow / errors)
deactivate Lamatic
API->>API: Parse/normalize response (status, html_code, poster_name)
alt errors / validation issues
API-->>Browser: { is_valid: false, validation_issues }
Browser->>User: Show issues
else success
API-->>Browser: { is_valid: true, html_code, poster_name }
Browser->>Browser: Render iframe preview, measure, enable exports (HTML/PNG/JPG/SVG)
User->>Browser: Trigger export/download
Browser->>User: Provide file
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip CodeRabbit can use oxc to improve the quality of JavaScript and TypeScript code reviews.Add a configuration file to your project to customize how CodeRabbit runs oxc. |
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (5)
kits/agentic/poster-generator/flows/poster-generator/meta.json (1)
4-7: Populate metadata fields before publishing.Line 4–7 are empty, which makes the kit harder to discover and validate in registries/docs tooling.
Suggested update
- "tags": "", - "testInput": "", - "githubUrl": "", - "documentationUrl": "", + "tags": "nextjs, lamatic, poster, generator, agentic", + "testInput": "A retro 70s jazz concert poster in Tokyo with moody orange and blue tones and bold stylized typography.", + "githubUrl": "https://github.com/Lamatic/AgentKit/tree/main/kits/agentic/poster-generator", + "documentationUrl": "https://github.com/Lamatic/AgentKit/pull/77",kits/agentic/poster-generator/.env.example (1)
1-4: Consider alphabetical ordering and adding a trailing newline.Static analysis flagged that keys are not alphabetically ordered and there's no trailing newline. These are minor formatting nits.
✨ Suggested fix
-LAMATIC_PROJECT_ENDPOINT= -LAMATIC_FLOW_ID= -LAMATIC_PROJECT_ID= -LAMATIC_PROJECT_API_KEY= +LAMATIC_FLOW_ID= +LAMATIC_PROJECT_API_KEY= +LAMATIC_PROJECT_ENDPOINT= +LAMATIC_PROJECT_ID= +kits/agentic/poster-generator/app/layout.tsx (1)
16-32: Consider adding Next.js metadata for SEO.The layout is missing a
metadataexport. Adding title and description improves SEO and provides better browser tab labeling.✨ Suggested addition
import type { Metadata } from "next" export const metadata: Metadata = { title: "Poster Studio", description: "Design posters with pure intent using AI-powered generation", }kits/agentic/poster-generator/app/api/generate-poster/route.ts (1)
54-56: Consider handling malformed JSON separately for clearer error responses.If
request.json()throws aSyntaxError(malformed JSON), it falls through to the generic catch block and returns HTTP 500. Returning HTTP 400 would be more appropriate for client-side input errors.♻️ Proposed improvement
export async function POST(request: Request) { try { - const parsedInput = requestSchema.parse(await request.json()) + let body: unknown + try { + body = await request.json() + } catch { + return NextResponse.json( + { + is_valid: false, + validation_issues: ["Invalid JSON in request body"], + poster_name: "poster", + design_spec: null, + intent: null, + }, + { status: 400 } + ) + } + const parsedInput = requestSchema.parse(body)kits/agentic/poster-generator/app/page-helpers.ts (1)
80-92: Dimension fallback uses||which treats0as falsy.The chain
rect.width || element.scrollWidth || ...will skip over0values and continue to fallbacks. While this is likely intentional (treating zero-dimension elements as needing fallbacks), it means a legitimately zero-sized element will getdefaultPosterDimensionsinstead. This is probably fine for this use case but worth being aware of.ℹ️ Alternative using nullish coalescing for explicit zero handling
If you want to preserve explicit
0values (unlikely needed here):- const width = Math.round( - rect.width || element.scrollWidth || element.offsetWidth || element.clientWidth || defaultPosterDimensions.width - ) + const width = Math.round( + [rect.width, element.scrollWidth, element.offsetWidth, element.clientWidth] + .find((v) => v > 0) ?? defaultPosterDimensions.width + )
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 77bdbdf4-6962-4d95-bac8-41c0e129ce1d
⛔ Files ignored due to path filters (5)
kits/agentic/poster-generator/app/favicon.icois excluded by!**/*.icokits/agentic/poster-generator/package-lock.jsonis excluded by!**/package-lock.jsonkits/agentic/poster-generator/public/docs/celestial-julian-invitation.pngis excluded by!**/*.pngkits/agentic/poster-generator/public/docs/home-page.pngis excluded by!**/*.pngkits/agentic/poster-generator/public/docs/subhi-dairy-diwali-bulk-promotion-poster.pngis excluded by!**/*.png
📒 Files selected for processing (34)
kits/agentic/poster-generator/.env.examplekits/agentic/poster-generator/.gitignorekits/agentic/poster-generator/.prettierignorekits/agentic/poster-generator/.prettierrckits/agentic/poster-generator/README.mdkits/agentic/poster-generator/app/api/generate-poster/route.tskits/agentic/poster-generator/app/globals.csskits/agentic/poster-generator/app/layout.tsxkits/agentic/poster-generator/app/page-helpers.tskits/agentic/poster-generator/app/page.tsxkits/agentic/poster-generator/app/utils.tskits/agentic/poster-generator/components.jsonkits/agentic/poster-generator/components/.gitkeepkits/agentic/poster-generator/components/theme-provider.tsxkits/agentic/poster-generator/components/ui/accordion.tsxkits/agentic/poster-generator/components/ui/alert.tsxkits/agentic/poster-generator/components/ui/button.tsxkits/agentic/poster-generator/components/ui/card.tsxkits/agentic/poster-generator/components/ui/separator.tsxkits/agentic/poster-generator/components/ui/skeleton.tsxkits/agentic/poster-generator/components/ui/textarea.tsxkits/agentic/poster-generator/eslint.config.mjskits/agentic/poster-generator/flows/poster-generator/README.mdkits/agentic/poster-generator/flows/poster-generator/config.jsonkits/agentic/poster-generator/flows/poster-generator/inputs.jsonkits/agentic/poster-generator/flows/poster-generator/meta.jsonkits/agentic/poster-generator/hooks/.gitkeepkits/agentic/poster-generator/lib/.gitkeepkits/agentic/poster-generator/lib/utils.tskits/agentic/poster-generator/next.config.mjskits/agentic/poster-generator/package.jsonkits/agentic/poster-generator/postcss.config.mjskits/agentic/poster-generator/public/.gitkeepkits/agentic/poster-generator/tsconfig.json
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (4)
kits/agentic/poster-generator/app/page.tsx (4)
72-90:⚠️ Potential issue | 🔴 CriticalKeep export rendering sandboxed or script-free.
This helper loads model-generated poster HTML into an unsandboxed same-origin
srcdociframe before capture. Because the flow explicitly permits inline<script>, PNG/JPG/SVG export currently gives untrusted poster code access to the app origin during export. Use an isolated origin or load a script-stripped document for capture.
339-370:⚠️ Potential issue | 🟠 MajorCapture the poster root, not
documentElement.Using
doc.documentElementties raster export to the hidden iframe’s 2000×2000 viewport, so PNG/JPG can include framing whitespace or the wrong aspect ratio.getPosterRoot()andgetElementDimensions()already provide the same element-selection contract the preview path uses.Proposed fix
- const target = doc.documentElement - const targetWidth = Math.max( - target.scrollWidth, - target.clientWidth, - defaultPosterDimensions.width - ) - const targetHeight = Math.max( - target.scrollHeight, - target.clientHeight, - defaultPosterDimensions.height - ) + const target = getPosterRoot(doc) + const { width: targetWidth, height: targetHeight } = getElementDimensions(target) const computedBackground = doc.defaultView - ? doc.defaultView.getComputedStyle(doc.body).backgroundColor + ? doc.defaultView.getComputedStyle(target).backgroundColor : ""
402-417:⚠️ Potential issue | 🟠 MajorOnly export SVG when the poster itself is a single styled SVG.
Falling back to the first nested
svgcan download just a decorative fragment of an HTML/CSS poster, and serializing the bare node drops document-level styles/font imports. Gate SVG export to a real poster-root SVG (or an explicitly marked export root), then inline the relevant styles before serialization.Proposed fix
- const rootSvg = - targetRoot.tagName.toLowerCase() === "svg" - ? targetRoot - : targetRoot.querySelector("svg") ?? doc.querySelector("svg") + const rootSvg = + targetRoot.tagName.toLowerCase() === "svg" ? targetRoot : null if (!rootSvg) { setSvgNotice( - "This poster uses CSS/HTML layout rather than a root SVG — PNG or JPG export is recommended." + "This poster is not authored as a single root SVG — PNG or JPG export is recommended." ) return } + // Inline relevant document styles/fonts into `rootSvg` before serialization. const xml = new XMLSerializer().serializeToString(rootSvg)
463-468:⚠️ Potential issue | 🟠 MajorBoth prompt textareas still need accessible names.
Placeholder text is not a stable accessible name, so screen readers do not get a proper label for either the main prompt or the refine control. Add a
<label>oraria-labelto both fields.Proposed fix
<Textarea value={promptValue} onChange={(e) => setPromptValue(e.target.value)} + aria-label="Describe the poster you want to generate" placeholder="e.g. A retro 70s jazz concert poster in Tokyo, featuring moody orange and blue tones, bold stylized typography..." className="w-full min-h-35 sm:min-h-40 p-4 sm:p-6 text-base sm:text-lg bg-transparent border-0 focus-visible:ring-0 focus-visible:ring-offset-0 shadow-none resize-none" /> @@ <Textarea value={promptValue} onChange={(e) => setPromptValue(e.target.value)} + aria-label="Refine the current poster prompt" className="min-h-30 text-sm resize-y border-0 focus-visible:ring-0 shadow-none pt-4 bg-transparent" placeholder="Change the prompt to iterate..." />Also applies to: 568-573
🧹 Nitpick comments (1)
kits/agentic/poster-generator/flows/poster-generator/config.json (1)
126-132: Makeid="poster"part of the HTML-generation contract.The preview/export helpers in
kits/agentic/poster-generator/app/page-helpers.ts:19-76look forid="poster"first, but this node never tells the HTML generator to put that id on the fixed-size poster root. The current note inIntent Parsercannot enforce the final markup, so root selection falls back to heuristics. Add the requirement here on the root container/root SVG.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2cd459f7-769c-4d08-8234-5266fac3c2a8
⛔ Files ignored due to path filters (1)
kits/agentic/poster-generator/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (9)
kits/agentic/poster-generator/.stylelintrc.jsonkits/agentic/poster-generator/README.mdkits/agentic/poster-generator/app/page-helpers.tskits/agentic/poster-generator/app/page.tsxkits/agentic/poster-generator/components/ui/button.tsxkits/agentic/poster-generator/components/ui/textarea.tsxkits/agentic/poster-generator/flows/poster-generator/README.mdkits/agentic/poster-generator/flows/poster-generator/config.jsonkits/agentic/poster-generator/package.json
✅ Files skipped from review due to trivial changes (5)
- kits/agentic/poster-generator/.stylelintrc.json
- kits/agentic/poster-generator/components/ui/textarea.tsx
- kits/agentic/poster-generator/README.md
- kits/agentic/poster-generator/flows/poster-generator/README.md
- kits/agentic/poster-generator/package.json
🚧 Files skipped from review as they are similar to previous changes (2)
- kits/agentic/poster-generator/components/ui/button.tsx
- kits/agentic/poster-generator/app/page-helpers.ts
What This Kit Does
poster-generatoris a Next.js app + Lamatic flow that turns a natural-language idea into a finished poster file, then lets you preview and export it as HTML, PNG, JPG, or SVG.Providers & Prerequisites
How to Run Locally
cd kits/agentic/poster-generatornpm installcp .env.example .envand fill in valuesnpm run devLive Preview
https://agent-kit-pg.vercel.app/
Lamatic Flow
Flow ID:
b378c16d-98ad-4c40-937f-df127e825dc7npm run dev.env.examplehas no secrets, only placeholdersREADME.mddocuments setup and usagekits/<category>/<kit-name>/config.jsonis present and validflows/folder