Skip to content

feat: Add poster-generator AgentKit#77

Merged
amanintech merged 4 commits intoLamatic:mainfrom
uttam-li:feat/poster-generator
Mar 27, 2026
Merged

feat: Add poster-generator AgentKit#77
amanintech merged 4 commits intoLamatic:mainfrom
uttam-li:feat/poster-generator

Conversation

@uttam-li
Copy link
Copy Markdown
Contributor

@uttam-li uttam-li commented Mar 21, 2026

What This Kit Does

poster-generator is 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

  • Models: Gemini 3 Flash Preview

How to Run Locally

  1. cd kits/agentic/poster-generator
  2. npm install
  3. cp .env.example .env and fill in values
  4. npm run dev

Live Preview

https://agent-kit-pg.vercel.app/

Lamatic Flow

Flow ID: b378c16d-98ad-4c40-937f-df127e825dc7

  • Kit runs locally with npm run dev
  • .env.example has no secrets, only placeholders
  • README.md documents setup and usage
  • Folder structure follows kits/<category>/<kit-name>/
  • config.json is present and valid
  • All flows exported in flows/ folder
  • Vercel deployment works
  • Live preview URL works end-to-end
home-page
  • Overview: Adds Poster Studio AgentKit — Next.js app + Lamatic flow that turns natural-language prompts into exportable posters (HTML/PNG/JPG/SVG) with live preview (https://agent-kit-pg.vercel.app/).
  • Workflow: API trigger → Intent Parser → Design Spec Builder → Poster Code Generation (Lamatic flow id b378c16d-98ad-4c40-937f-df127e825dc7); uses Instructor LLM nodes (Gemini 3 Flash Preview recommended).
  • API: New POST /api/generate-poster route (Zod validation, calls Lamatic GraphQL executeWorkflow, robust error handling, 60s timeout).
  • Frontend: app/page.tsx client UI — prompt input, sandboxed iframe preview, dimension detection, responsive scaling, and exports (HTML, PNG/JPG via html2canvas, SVG when applicable).
  • Utilities & helpers: slugify, poster/root detection, element dimension heuristics, lamaticEnv parsing, cn class merger.
  • UI & styling: Adds ThemeProvider (theme hotkey), multiple reusable UI components (accordion, alert, button, card, separator, skeleton, textarea), Tailwind + custom theme tokens, globals.css, Prettier/Tailwind integration.
  • Flow artifacts: flows/poster-generator (config.json, inputs.json, meta.json, README) included and documented.
  • Project scaffolding: package.json, tsconfig, next.config, PostCSS, ESLint, Prettier, .gitignore, README with curl example and local run steps.
  • Notable fixes/docs: image rendering bug fixed (commit message).
  • Dev setup: cd kits/agentic/poster-generator → npm install → cp .env.example .env → fill LAMATIC_* values → npm run dev.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 21, 2026

📝 Walkthrough

Walkthrough

Adds a new Next.js poster generation app under kits/agentic/poster-generator/ that provides a Poster Studio UI, Lamatic-backed workflow integration via a POST API, theme/UI components, tooling configs, and flow artifacts to generate, preview, and export HTML posters from text prompts.

Changes

Cohort / File(s) Summary
Project metadata & config
kits/agentic/poster-generator/package.json, kits/agentic/poster-generator/components.json, kits/agentic/poster-generator/next.config.mjs, kits/agentic/poster-generator/tsconfig.json, kits/agentic/poster-generator/postcss.config.mjs, kits/agentic/poster-generator/.stylelintrc.json
New project manifest and environment for a Next.js app: package metadata, Next/TypeScript/PostCSS/Stylelint configs, and UI metadata.
Tooling & formatting
kits/agentic/poster-generator/.gitignore, kits/agentic/poster-generator/.prettierignore, kits/agentic/poster-generator/.prettierrc, kits/agentic/poster-generator/eslint.config.mjs
Added ignore rules and Prettier/ESLint configs for consistent formatting and linting.
Environment example
kits/agentic/poster-generator/.env.example
Adds required LAMATIC_* environment variable placeholders.
Documentation
kits/agentic/poster-generator/README.md, kits/agentic/poster-generator/flows/poster-generator/README.md, kits/agentic/poster-generator/flows/poster-generator/meta.json
README and flow docs describing setup, env vars, API usage, and flow metadata.
Lamatic flow artifacts
kits/agentic/poster-generator/flows/poster-generator/config.json, kits/agentic/poster-generator/flows/poster-generator/inputs.json
New Lamatic workflow definition (intent → design spec → code gen) and LLM input configuration for instructor nodes.
Application core
kits/agentic/poster-generator/app/layout.tsx, kits/agentic/poster-generator/app/globals.css, kits/agentic/poster-generator/app/page.tsx, kits/agentic/poster-generator/app/page-helpers.ts, kits/agentic/poster-generator/app/utils.ts
Root layout and ThemeProvider wiring, global Tailwind theme variables, Poster Studio page with prompt validation, generation/export flows (HTML/PNG/JPG/SVG), DOM/dimension helpers, and server-side env validation for Lamatic.
API route
kits/agentic/poster-generator/app/api/generate-poster/route.ts
Adds POST handler that validates prompt, calls Lamatic GraphQL executeWorkflow with project headers, parses/normalizes workflow response, and returns structured JSON (is_valid, validation_issues, html_code, poster_name).
UI components
kits/agentic/poster-generator/components/theme-provider.tsx, kits/agentic/poster-generator/components/ui/...
New ThemeProvider (with 'd' hotkey to toggle theme) and a suite of shadcn-style UI primitives: accordion, alert, button (cva), card, separator, skeleton, textarea.
Utilities
kits/agentic/poster-generator/lib/utils.ts
Exports cn(...) combining clsx + tailwind-merge for class merging.

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Add poster-generator AgentKit' directly and clearly describes the main change: introducing a new poster-generator AgentKit component to the repository.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 metadata export. 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 a SyntaxError (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 treats 0 as falsy.

The chain rect.width || element.scrollWidth || ... will skip over 0 values and continue to fallbacks. While this is likely intentional (treating zero-dimension elements as needing fallbacks), it means a legitimately zero-sized element will get defaultPosterDimensions instead. 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 0 values (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

📥 Commits

Reviewing files that changed from the base of the PR and between e1ceb47 and 140d32d.

⛔ Files ignored due to path filters (5)
  • kits/agentic/poster-generator/app/favicon.ico is excluded by !**/*.ico
  • kits/agentic/poster-generator/package-lock.json is excluded by !**/package-lock.json
  • kits/agentic/poster-generator/public/docs/celestial-julian-invitation.png is excluded by !**/*.png
  • kits/agentic/poster-generator/public/docs/home-page.png is excluded by !**/*.png
  • kits/agentic/poster-generator/public/docs/subhi-dairy-diwali-bulk-promotion-poster.png is excluded by !**/*.png
📒 Files selected for processing (34)
  • kits/agentic/poster-generator/.env.example
  • kits/agentic/poster-generator/.gitignore
  • kits/agentic/poster-generator/.prettierignore
  • kits/agentic/poster-generator/.prettierrc
  • kits/agentic/poster-generator/README.md
  • kits/agentic/poster-generator/app/api/generate-poster/route.ts
  • kits/agentic/poster-generator/app/globals.css
  • kits/agentic/poster-generator/app/layout.tsx
  • kits/agentic/poster-generator/app/page-helpers.ts
  • kits/agentic/poster-generator/app/page.tsx
  • kits/agentic/poster-generator/app/utils.ts
  • kits/agentic/poster-generator/components.json
  • kits/agentic/poster-generator/components/.gitkeep
  • kits/agentic/poster-generator/components/theme-provider.tsx
  • kits/agentic/poster-generator/components/ui/accordion.tsx
  • kits/agentic/poster-generator/components/ui/alert.tsx
  • kits/agentic/poster-generator/components/ui/button.tsx
  • kits/agentic/poster-generator/components/ui/card.tsx
  • kits/agentic/poster-generator/components/ui/separator.tsx
  • kits/agentic/poster-generator/components/ui/skeleton.tsx
  • kits/agentic/poster-generator/components/ui/textarea.tsx
  • kits/agentic/poster-generator/eslint.config.mjs
  • kits/agentic/poster-generator/flows/poster-generator/README.md
  • kits/agentic/poster-generator/flows/poster-generator/config.json
  • kits/agentic/poster-generator/flows/poster-generator/inputs.json
  • kits/agentic/poster-generator/flows/poster-generator/meta.json
  • kits/agentic/poster-generator/hooks/.gitkeep
  • kits/agentic/poster-generator/lib/.gitkeep
  • kits/agentic/poster-generator/lib/utils.ts
  • kits/agentic/poster-generator/next.config.mjs
  • kits/agentic/poster-generator/package.json
  • kits/agentic/poster-generator/postcss.config.mjs
  • kits/agentic/poster-generator/public/.gitkeep
  • kits/agentic/poster-generator/tsconfig.json

Comment thread kits/agentic/poster-generator/app/globals.css
Comment thread kits/agentic/poster-generator/app/page.tsx
Comment thread kits/agentic/poster-generator/app/page.tsx
Comment thread kits/agentic/poster-generator/app/page.tsx
Comment thread kits/agentic/poster-generator/app/page.tsx
Comment thread kits/agentic/poster-generator/components/ui/button.tsx Outdated
Comment thread kits/agentic/poster-generator/components/ui/textarea.tsx
Comment thread kits/agentic/poster-generator/flows/poster-generator/config.json Outdated
Comment thread kits/agentic/poster-generator/flows/poster-generator/inputs.json
Comment thread kits/agentic/poster-generator/README.md
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (4)
kits/agentic/poster-generator/app/page.tsx (4)

72-90: ⚠️ Potential issue | 🔴 Critical

Keep export rendering sandboxed or script-free.

This helper loads model-generated poster HTML into an unsandboxed same-origin srcdoc iframe 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 | 🟠 Major

Capture the poster root, not documentElement.

Using doc.documentElement ties raster export to the hidden iframe’s 2000×2000 viewport, so PNG/JPG can include framing whitespace or the wrong aspect ratio. getPosterRoot() and getElementDimensions() 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 | 🟠 Major

Only export SVG when the poster itself is a single styled SVG.

Falling back to the first nested svg can 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 | 🟠 Major

Both 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> or aria-label to 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: Make id="poster" part of the HTML-generation contract.

The preview/export helpers in kits/agentic/poster-generator/app/page-helpers.ts:19-76 look for id="poster" first, but this node never tells the HTML generator to put that id on the fixed-size poster root. The current note in Intent Parser cannot 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

📥 Commits

Reviewing files that changed from the base of the PR and between 140d32d and ea7f673.

⛔ Files ignored due to path filters (1)
  • kits/agentic/poster-generator/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • kits/agentic/poster-generator/.stylelintrc.json
  • kits/agentic/poster-generator/README.md
  • kits/agentic/poster-generator/app/page-helpers.ts
  • kits/agentic/poster-generator/app/page.tsx
  • kits/agentic/poster-generator/components/ui/button.tsx
  • kits/agentic/poster-generator/components/ui/textarea.tsx
  • kits/agentic/poster-generator/flows/poster-generator/README.md
  • kits/agentic/poster-generator/flows/poster-generator/config.json
  • kits/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

Comment thread kits/agentic/poster-generator/app/page.tsx
@amanintech amanintech merged commit 3aa4bf4 into Lamatic:main Mar 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants