@easybits.cloud/html-tailwind-generator 0.2.80 → 0.2.81

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.
@@ -77,14 +77,28 @@ The HTML must include a <link> tag for Google Fonts and a <section> tag.
77
77
  This is a LETTER-SIZE document cover page (8.5" \xD7 11"), NOT a website hero.
78
78
  Use the EXACT fonts and colors provided. The cover must feel premium and print-ready.
79
79
  Use real-looking content specific to the brief (Spanish text).
80
- Include: document title (large), subtitle or description, date, optional author/company name.
80
+
81
+ CRITICAL \u2014 TEXT MUST BE VISIBLE AND READABLE:
82
+ - The document title MUST be large (text-4xl or bigger), bold, and clearly visible
83
+ - Include: document title, subtitle or description, date, optional author/company name
84
+ - ALL text must have strong contrast against its background \u2014 if background is dark, text MUST be white/light
85
+ - NEVER let text disappear into the background
86
+
87
+ DESIGN APPROACHES (vary across directions):
88
+ - Approach A: Solid color background (bg-[primary]) with large white text \u2014 NO image needed
89
+ - Approach B: Split layout \u2014 image on one half, text on solid color half
90
+ - Approach C: Full-bleed image WITH a solid overlay (bg-black/50 or bg-[primary]/80) AND white text on top
91
+ - Approach D: Geometric/abstract design with color blocks, no image
92
+ - Choose the approach that best fits the mood. NOT every cover needs a full-bleed image.
93
+
94
+ If using images:
95
+ - Pattern: <img data-image-query="specific english search query" alt="description" class="absolute inset-0 w-full h-full object-cover"/>
96
+ - ALWAYS add a dark overlay on top: <div class="absolute inset-0 bg-black/50"></div>
97
+ - Text goes ABOVE the overlay with z-10 and text-white
98
+ - NEVER include a src attribute \u2014 ONLY data-image-query
99
+
81
100
  NO buttons or CTAs \u2014 this is a print document cover.
82
- NO emoji \u2014 use geometric shapes or SVG icons for decoration.
83
- MANDATORY IMAGE: Include exactly 1 full-bleed background image covering the entire page or a large section.
84
- Pattern: <img data-image-query="specific english search query" alt="description" class="absolute inset-0 w-full h-full object-cover"/>
85
- Then overlay text on top with a semi-transparent backdrop: <div class="absolute inset-0 bg-black/40"></div> or similar.
86
- NEVER include a src attribute \u2014 ONLY data-image-query. The system resolves real Unsplash photos automatically.
87
- NEVER place images in small corners \u2014 they must be dramatic, full-bleed backgrounds.` : `You create stunning hero sections with HTML + Tailwind CSS.
101
+ NO emoji \u2014 use geometric shapes or SVG icons for decoration.` : `You create stunning hero sections with HTML + Tailwind CSS.
88
102
  Output ONLY the raw HTML \u2014 no markdown fences, no explanation.
89
103
  The HTML must include a <link> tag for Google Fonts and a <section> tag.
90
104
  Use the EXACT fonts and colors provided. The hero must feel premium and polished.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/directions.ts"],"sourcesContent":["import { generateObject, streamText } from \"ai\";\nimport { createAnthropic } from \"@ai-sdk/anthropic\";\nimport { createOpenAI } from \"@ai-sdk/openai\";\nimport { z } from \"zod\";\nimport { nanoid } from \"nanoid\";\n\nexport const DesignDirectionSchema = z.object({\n name: z.string().describe(\"Creative direction name, e.g. 'The Editorial'\"),\n tagline: z\n .string()\n .describe(\"One-line vibe description, e.g. 'Bold serif typography meets minimalist space'\"),\n headingFont: z\n .string()\n .describe(\"Google Font name for headings, e.g. 'Playfair Display'\"),\n bodyFont: z\n .string()\n .describe(\"Google Font name for body text, e.g. 'Inter'\"),\n colors: z.object({\n primary: z.string().describe(\"Main brand color as hex, e.g. '#6366f1'\"),\n accent: z.string().describe(\"Accent/CTA color as hex, e.g. '#f59e0b'\"),\n surface: z.string().describe(\"Background surface color as hex, e.g. '#ffffff'\"),\n surfaceAlt: z.string().describe(\"Alt surface (cards, alternating sections) as hex, e.g. '#f8fafc'\"),\n text: z.string().describe(\"Main text color as hex, e.g. '#0f172a'\"),\n }),\n mood: z.enum([\"dark\", \"light\", \"warm\", \"cool\", \"vibrant\"]),\n layoutHint: z\n .string()\n .describe(\"Layout archetype: 'split-screen', 'editorial', 'immersive-gallery', 'community-feed', 'bento-grid', 'magazine'\"),\n});\n\nexport type DesignDirection = z.infer<typeof DesignDirectionSchema>;\n\nexport interface DirectionsOptions {\n anthropicApiKey?: string;\n openaiApiKey?: string;\n prompt: string;\n count?: number;\n /** \"landing\" generates hero sections, \"document\" generates cover pages */\n product?: \"landing\" | \"document\";\n /** Override the model ID (default: gpt-4o-mini) */\n model?: string;\n}\n\nconst DIRECTIONS_SYSTEM = `You are an elite creative director at a top design agency (Pentagram, Sagmeister, Collins).\n\nGiven a project brief, propose design directions that are MAXIMALLY diverse from each other.\n\nRULES:\n- Each direction must feel like a completely DIFFERENT design agency made it\n- Vary these axes: typography style (geometric sans, humanist sans, serif, slab, display/decorative), color mood (dark, light, warm, cool, vibrant), layout approach (editorial, split-screen, immersive, bento-grid, community)\n- Fonts MUST be popular Google Fonts that render well. Good examples:\n SANS: Inter, DM Sans, Space Grotesk, Outfit, Plus Jakarta Sans, Manrope, Sora, Figtree, Urbanist\n SERIF: Playfair Display, Lora, Merriweather, Source Serif 4, Cormorant Garamond, Libre Baskerville, DM Serif Display\n DISPLAY: Bebas Neue, Oswald, Archivo Black, Righteous, Anton, Alfa Slab One\n MONO: JetBrains Mono, Space Mono, IBM Plex Mono\n- NEVER use the same heading font twice\n- NEVER use the same color palette twice\n- AT LEAST one direction must be dark-mode\n- AT LEAST one must use serif headings\n- AT LEAST one must be bold/editorial with huge typography\n- Colors must be cohesive palettes, not random. Think Dribbble-worthy.\n- Names should be evocative (\"The Chronicle\", \"Neon Pulse\", \"Warm Atelier\")`;\n\n/**\n * Generate N design directions for a landing page.\n * Uses generateObject for type-safe structured output.\n */\nexport async function generateDirections(\n options: DirectionsOptions\n): Promise<DesignDirection[]> {\n const { prompt, count = 4, openaiApiKey, model: modelId } = options;\n\n const apiKey = openaiApiKey || process.env.OPENAI_API_KEY;\n if (!apiKey) throw new Error(\"OpenAI API key required for generateDirections\");\n\n const openai = createOpenAI({ apiKey });\n const model = openai(modelId || \"gpt-4o-mini\");\n\n const { object } = await generateObject({\n model,\n schema: z.object({\n directions: z.array(DesignDirectionSchema).length(count),\n }),\n system: DIRECTIONS_SYSTEM,\n prompt: `Project brief: \"${prompt}\"\n\nGenerate ${count} design directions. Make them as visually distinct as possible.`,\n });\n\n return object.directions;\n}\n\n/**\n * Generate a hero section preview for a given design direction.\n * Fast Haiku call, returns raw HTML string with Google Fonts link.\n */\nexport async function generateHeroPreview(options: {\n anthropicApiKey?: string;\n openaiApiKey?: string;\n prompt: string;\n direction: DesignDirection;\n product?: \"landing\" | \"document\";\n /** Use 4o-mini instead of Haiku for cheaper previews */\n useOpenai?: boolean;\n /** Override model ID */\n model?: string;\n /** Called with partial HTML as it streams in */\n onChunk?: (partialHtml: string) => void;\n}): Promise<string> {\n const { prompt, direction, anthropicApiKey, openaiApiKey, product = \"landing\", useOpenai = false, model: modelId, onChunk } = options;\n\n let model: any;\n if (useOpenai) {\n const apiKey = openaiApiKey || process.env.OPENAI_API_KEY;\n if (!apiKey) throw new Error(\"OpenAI API key required\");\n const openai = createOpenAI({ apiKey });\n model = openai(modelId || \"gpt-4o-mini\");\n } else {\n const apiKey = anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n if (!apiKey) throw new Error(\"Anthropic API key required\");\n const anthropic = createAnthropic({ apiKey });\n model = anthropic(modelId || \"claude-haiku-4-5-20251001\");\n }\n\n const fontsUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(direction.headingFont).replace(/%20/g, \"+\")}:wght@400;700;900&family=${encodeURIComponent(direction.bodyFont).replace(/%20/g, \"+\")}:wght@400;500;600&display=swap`;\n\n const isDocument = product === \"document\";\n\n const systemPrompt = isDocument\n ? `You create stunning document cover pages with HTML + Tailwind CSS.\nOutput ONLY the raw HTML — no markdown fences, no explanation.\nThe HTML must include a <link> tag for Google Fonts and a <section> tag.\nThis is a LETTER-SIZE document cover page (8.5\" × 11\"), NOT a website hero.\nUse the EXACT fonts and colors provided. The cover must feel premium and print-ready.\nUse real-looking content specific to the brief (Spanish text).\nInclude: document title (large), subtitle or description, date, optional author/company name.\nNO buttons or CTAs — this is a print document cover.\nNO emoji — use geometric shapes or SVG icons for decoration.\nMANDATORY IMAGE: Include exactly 1 full-bleed background image covering the entire page or a large section.\nPattern: <img data-image-query=\"specific english search query\" alt=\"description\" class=\"absolute inset-0 w-full h-full object-cover\"/>\nThen overlay text on top with a semi-transparent backdrop: <div class=\"absolute inset-0 bg-black/40\"></div> or similar.\nNEVER include a src attribute — ONLY data-image-query. The system resolves real Unsplash photos automatically.\nNEVER place images in small corners — they must be dramatic, full-bleed backgrounds.`\n : `You create stunning hero sections with HTML + Tailwind CSS.\nOutput ONLY the raw HTML — no markdown fences, no explanation.\nThe HTML must include a <link> tag for Google Fonts and a <section> tag.\nUse the EXACT fonts and colors provided. The hero must feel premium and polished.\nUse real-looking content specific to the brief (Spanish text).\nInclude: headline (huge), subtitle, 1-2 CTAs, and optionally a hero image via <img data-image-query=\"...\" alt=\"...\" class=\"...\">.\nNEVER use src on img tags. Use data-image-query with English search terms.`;\n\n const sectionInstruction = isDocument\n ? `Generate a document cover page. Use inline style for font-family referencing the Google Fonts.\nStart with: <link href=\"${fontsUrl}\" rel=\"stylesheet\">\nThen a <section class=\"w-[8.5in] h-[11in] relative overflow-hidden\"> sized for letter paper.\nUse the exact hex colors in Tailwind arbitrary values like bg-[${direction.colors.primary}] text-[${direction.colors.text}] etc.\nUse full-bleed backgrounds, geometric accents, elegant typography hierarchy.\nMake it look like a $50K design agency document cover.`\n : `Generate a hero section. Use inline style for font-family referencing the Google Fonts.\nStart with: <link href=\"${fontsUrl}\" rel=\"stylesheet\">\nThen a <section> with min-h-[80vh].\nUse the exact hex colors in Tailwind arbitrary values like bg-[${direction.colors.primary}] text-[${direction.colors.text}] etc.\nMake it look like a $50K agency landing page hero.`;\n\n const result = streamText({\n model,\n system: systemPrompt,\n prompt: `Brief: \"${prompt}\"\n\nDesign direction: \"${direction.name}\" — ${direction.tagline}\nLayout: ${direction.layoutHint}\nHeading font: ${direction.headingFont}\nBody font: ${direction.bodyFont}\nColors: primary=${direction.colors.primary}, accent=${direction.colors.accent}, surface=${direction.colors.surface}, surfaceAlt=${direction.colors.surfaceAlt}, text=${direction.colors.text}\nMood: ${direction.mood}\n\n${sectionInstruction}`,\n });\n\n let html = \"\";\n let chunkCount = 0;\n for await (const chunk of result.textStream) {\n html += chunk;\n chunkCount++;\n if (onChunk && chunkCount % 3 === 0) {\n onChunk(html);\n }\n }\n if (onChunk) onChunk(html);\n\n // Clean markdown fences if present\n html = html.trim();\n if (html.startsWith(\"```\")) {\n html = html.replace(/^```(?:html|xml)?\\s*/, \"\").replace(/\\s*```$/, \"\");\n }\n\n return html;\n}\n"],"mappings":";AAAA,SAAS,gBAAgB,kBAAkB;AAC3C,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAGX,IAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,MAAM,EAAE,OAAO,EAAE,SAAS,+CAA+C;AAAA,EACzE,SAAS,EACN,OAAO,EACP,SAAS,gFAAgF;AAAA,EAC5F,aAAa,EACV,OAAO,EACP,SAAS,wDAAwD;AAAA,EACpE,UAAU,EACP,OAAO,EACP,SAAS,8CAA8C;AAAA,EAC1D,QAAQ,EAAE,OAAO;AAAA,IACf,SAAS,EAAE,OAAO,EAAE,SAAS,yCAAyC;AAAA,IACtE,QAAQ,EAAE,OAAO,EAAE,SAAS,yCAAyC;AAAA,IACrE,SAAS,EAAE,OAAO,EAAE,SAAS,iDAAiD;AAAA,IAC9E,YAAY,EAAE,OAAO,EAAE,SAAS,kEAAkE;AAAA,IAClG,MAAM,EAAE,OAAO,EAAE,SAAS,wCAAwC;AAAA,EACpE,CAAC;AAAA,EACD,MAAM,EAAE,KAAK,CAAC,QAAQ,SAAS,QAAQ,QAAQ,SAAS,CAAC;AAAA,EACzD,YAAY,EACT,OAAO,EACP,SAAS,gHAAgH;AAC9H,CAAC;AAeD,IAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwB1B,eAAsB,mBACpB,SAC4B;AAC5B,QAAM,EAAE,QAAQ,QAAQ,GAAG,cAAc,OAAO,QAAQ,IAAI;AAE5D,QAAM,SAAS,gBAAgB,QAAQ,IAAI;AAC3C,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,gDAAgD;AAE7E,QAAM,SAAS,aAAa,EAAE,OAAO,CAAC;AACtC,QAAM,QAAQ,OAAO,WAAW,aAAa;AAE7C,QAAM,EAAE,OAAO,IAAI,MAAM,eAAe;AAAA,IACtC;AAAA,IACA,QAAQ,EAAE,OAAO;AAAA,MACf,YAAY,EAAE,MAAM,qBAAqB,EAAE,OAAO,KAAK;AAAA,IACzD,CAAC;AAAA,IACD,QAAQ;AAAA,IACR,QAAQ,mBAAmB,MAAM;AAAA;AAAA,WAE1B,KAAK;AAAA,EACd,CAAC;AAED,SAAO,OAAO;AAChB;AAMA,eAAsB,oBAAoB,SAYtB;AAClB,QAAM,EAAE,QAAQ,WAAW,iBAAiB,cAAc,UAAU,WAAW,YAAY,OAAO,OAAO,SAAS,QAAQ,IAAI;AAE9H,MAAI;AACJ,MAAI,WAAW;AACb,UAAM,SAAS,gBAAgB,QAAQ,IAAI;AAC3C,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,yBAAyB;AACtD,UAAM,SAAS,aAAa,EAAE,OAAO,CAAC;AACtC,YAAQ,OAAO,WAAW,aAAa;AAAA,EACzC,OAAO;AACL,UAAM,SAAS,mBAAmB,QAAQ,IAAI;AAC9C,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,4BAA4B;AACzD,UAAM,YAAY,gBAAgB,EAAE,OAAO,CAAC;AAC5C,YAAQ,UAAU,WAAW,2BAA2B;AAAA,EAC1D;AAEA,QAAM,WAAW,4CAA4C,mBAAmB,UAAU,WAAW,EAAE,QAAQ,QAAQ,GAAG,CAAC,4BAA4B,mBAAmB,UAAU,QAAQ,EAAE,QAAQ,QAAQ,GAAG,CAAC;AAElN,QAAM,aAAa,YAAY;AAE/B,QAAM,eAAe,aACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6FAcA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQJ,QAAM,qBAAqB,aACvB;AAAA,0BACoB,QAAQ;AAAA;AAAA,iEAE+B,UAAU,OAAO,OAAO,WAAW,UAAU,OAAO,IAAI;AAAA;AAAA,0DAGnH;AAAA,0BACoB,QAAQ;AAAA;AAAA,iEAE+B,UAAU,OAAO,OAAO,WAAW,UAAU,OAAO,IAAI;AAAA;AAGvH,QAAM,SAAS,WAAW;AAAA,IACxB;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ,WAAW,MAAM;AAAA;AAAA,qBAER,UAAU,IAAI,YAAO,UAAU,OAAO;AAAA,UACjD,UAAU,UAAU;AAAA,gBACd,UAAU,WAAW;AAAA,aACxB,UAAU,QAAQ;AAAA,kBACb,UAAU,OAAO,OAAO,YAAY,UAAU,OAAO,MAAM,aAAa,UAAU,OAAO,OAAO,gBAAgB,UAAU,OAAO,UAAU,UAAU,UAAU,OAAO,IAAI;AAAA,QACpL,UAAU,IAAI;AAAA;AAAA,EAEpB,kBAAkB;AAAA,EAClB,CAAC;AAED,MAAI,OAAO;AACX,MAAI,aAAa;AACjB,mBAAiB,SAAS,OAAO,YAAY;AAC3C,YAAQ;AACR;AACA,QAAI,WAAW,aAAa,MAAM,GAAG;AACnC,cAAQ,IAAI;AAAA,IACd;AAAA,EACF;AACA,MAAI,QAAS,SAAQ,IAAI;AAGzB,SAAO,KAAK,KAAK;AACjB,MAAI,KAAK,WAAW,KAAK,GAAG;AAC1B,WAAO,KAAK,QAAQ,wBAAwB,EAAE,EAAE,QAAQ,WAAW,EAAE;AAAA,EACvE;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/directions.ts"],"sourcesContent":["import { generateObject, streamText } from \"ai\";\nimport { createAnthropic } from \"@ai-sdk/anthropic\";\nimport { createOpenAI } from \"@ai-sdk/openai\";\nimport { z } from \"zod\";\nimport { nanoid } from \"nanoid\";\n\nexport const DesignDirectionSchema = z.object({\n name: z.string().describe(\"Creative direction name, e.g. 'The Editorial'\"),\n tagline: z\n .string()\n .describe(\"One-line vibe description, e.g. 'Bold serif typography meets minimalist space'\"),\n headingFont: z\n .string()\n .describe(\"Google Font name for headings, e.g. 'Playfair Display'\"),\n bodyFont: z\n .string()\n .describe(\"Google Font name for body text, e.g. 'Inter'\"),\n colors: z.object({\n primary: z.string().describe(\"Main brand color as hex, e.g. '#6366f1'\"),\n accent: z.string().describe(\"Accent/CTA color as hex, e.g. '#f59e0b'\"),\n surface: z.string().describe(\"Background surface color as hex, e.g. '#ffffff'\"),\n surfaceAlt: z.string().describe(\"Alt surface (cards, alternating sections) as hex, e.g. '#f8fafc'\"),\n text: z.string().describe(\"Main text color as hex, e.g. '#0f172a'\"),\n }),\n mood: z.enum([\"dark\", \"light\", \"warm\", \"cool\", \"vibrant\"]),\n layoutHint: z\n .string()\n .describe(\"Layout archetype: 'split-screen', 'editorial', 'immersive-gallery', 'community-feed', 'bento-grid', 'magazine'\"),\n});\n\nexport type DesignDirection = z.infer<typeof DesignDirectionSchema>;\n\nexport interface DirectionsOptions {\n anthropicApiKey?: string;\n openaiApiKey?: string;\n prompt: string;\n count?: number;\n /** \"landing\" generates hero sections, \"document\" generates cover pages */\n product?: \"landing\" | \"document\";\n /** Override the model ID (default: gpt-4o-mini) */\n model?: string;\n}\n\nconst DIRECTIONS_SYSTEM = `You are an elite creative director at a top design agency (Pentagram, Sagmeister, Collins).\n\nGiven a project brief, propose design directions that are MAXIMALLY diverse from each other.\n\nRULES:\n- Each direction must feel like a completely DIFFERENT design agency made it\n- Vary these axes: typography style (geometric sans, humanist sans, serif, slab, display/decorative), color mood (dark, light, warm, cool, vibrant), layout approach (editorial, split-screen, immersive, bento-grid, community)\n- Fonts MUST be popular Google Fonts that render well. Good examples:\n SANS: Inter, DM Sans, Space Grotesk, Outfit, Plus Jakarta Sans, Manrope, Sora, Figtree, Urbanist\n SERIF: Playfair Display, Lora, Merriweather, Source Serif 4, Cormorant Garamond, Libre Baskerville, DM Serif Display\n DISPLAY: Bebas Neue, Oswald, Archivo Black, Righteous, Anton, Alfa Slab One\n MONO: JetBrains Mono, Space Mono, IBM Plex Mono\n- NEVER use the same heading font twice\n- NEVER use the same color palette twice\n- AT LEAST one direction must be dark-mode\n- AT LEAST one must use serif headings\n- AT LEAST one must be bold/editorial with huge typography\n- Colors must be cohesive palettes, not random. Think Dribbble-worthy.\n- Names should be evocative (\"The Chronicle\", \"Neon Pulse\", \"Warm Atelier\")`;\n\n/**\n * Generate N design directions for a landing page.\n * Uses generateObject for type-safe structured output.\n */\nexport async function generateDirections(\n options: DirectionsOptions\n): Promise<DesignDirection[]> {\n const { prompt, count = 4, openaiApiKey, model: modelId } = options;\n\n const apiKey = openaiApiKey || process.env.OPENAI_API_KEY;\n if (!apiKey) throw new Error(\"OpenAI API key required for generateDirections\");\n\n const openai = createOpenAI({ apiKey });\n const model = openai(modelId || \"gpt-4o-mini\");\n\n const { object } = await generateObject({\n model,\n schema: z.object({\n directions: z.array(DesignDirectionSchema).length(count),\n }),\n system: DIRECTIONS_SYSTEM,\n prompt: `Project brief: \"${prompt}\"\n\nGenerate ${count} design directions. Make them as visually distinct as possible.`,\n });\n\n return object.directions;\n}\n\n/**\n * Generate a hero section preview for a given design direction.\n * Fast Haiku call, returns raw HTML string with Google Fonts link.\n */\nexport async function generateHeroPreview(options: {\n anthropicApiKey?: string;\n openaiApiKey?: string;\n prompt: string;\n direction: DesignDirection;\n product?: \"landing\" | \"document\";\n /** Use 4o-mini instead of Haiku for cheaper previews */\n useOpenai?: boolean;\n /** Override model ID */\n model?: string;\n /** Called with partial HTML as it streams in */\n onChunk?: (partialHtml: string) => void;\n}): Promise<string> {\n const { prompt, direction, anthropicApiKey, openaiApiKey, product = \"landing\", useOpenai = false, model: modelId, onChunk } = options;\n\n let model: any;\n if (useOpenai) {\n const apiKey = openaiApiKey || process.env.OPENAI_API_KEY;\n if (!apiKey) throw new Error(\"OpenAI API key required\");\n const openai = createOpenAI({ apiKey });\n model = openai(modelId || \"gpt-4o-mini\");\n } else {\n const apiKey = anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n if (!apiKey) throw new Error(\"Anthropic API key required\");\n const anthropic = createAnthropic({ apiKey });\n model = anthropic(modelId || \"claude-haiku-4-5-20251001\");\n }\n\n const fontsUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(direction.headingFont).replace(/%20/g, \"+\")}:wght@400;700;900&family=${encodeURIComponent(direction.bodyFont).replace(/%20/g, \"+\")}:wght@400;500;600&display=swap`;\n\n const isDocument = product === \"document\";\n\n const systemPrompt = isDocument\n ? `You create stunning document cover pages with HTML + Tailwind CSS.\nOutput ONLY the raw HTML — no markdown fences, no explanation.\nThe HTML must include a <link> tag for Google Fonts and a <section> tag.\nThis is a LETTER-SIZE document cover page (8.5\" × 11\"), NOT a website hero.\nUse the EXACT fonts and colors provided. The cover must feel premium and print-ready.\nUse real-looking content specific to the brief (Spanish text).\n\nCRITICAL — TEXT MUST BE VISIBLE AND READABLE:\n- The document title MUST be large (text-4xl or bigger), bold, and clearly visible\n- Include: document title, subtitle or description, date, optional author/company name\n- ALL text must have strong contrast against its background — if background is dark, text MUST be white/light\n- NEVER let text disappear into the background\n\nDESIGN APPROACHES (vary across directions):\n- Approach A: Solid color background (bg-[primary]) with large white text — NO image needed\n- Approach B: Split layout — image on one half, text on solid color half\n- Approach C: Full-bleed image WITH a solid overlay (bg-black/50 or bg-[primary]/80) AND white text on top\n- Approach D: Geometric/abstract design with color blocks, no image\n- Choose the approach that best fits the mood. NOT every cover needs a full-bleed image.\n\nIf using images:\n- Pattern: <img data-image-query=\"specific english search query\" alt=\"description\" class=\"absolute inset-0 w-full h-full object-cover\"/>\n- ALWAYS add a dark overlay on top: <div class=\"absolute inset-0 bg-black/50\"></div>\n- Text goes ABOVE the overlay with z-10 and text-white\n- NEVER include a src attribute — ONLY data-image-query\n\nNO buttons or CTAs — this is a print document cover.\nNO emoji — use geometric shapes or SVG icons for decoration.`\n : `You create stunning hero sections with HTML + Tailwind CSS.\nOutput ONLY the raw HTML — no markdown fences, no explanation.\nThe HTML must include a <link> tag for Google Fonts and a <section> tag.\nUse the EXACT fonts and colors provided. The hero must feel premium and polished.\nUse real-looking content specific to the brief (Spanish text).\nInclude: headline (huge), subtitle, 1-2 CTAs, and optionally a hero image via <img data-image-query=\"...\" alt=\"...\" class=\"...\">.\nNEVER use src on img tags. Use data-image-query with English search terms.`;\n\n const sectionInstruction = isDocument\n ? `Generate a document cover page. Use inline style for font-family referencing the Google Fonts.\nStart with: <link href=\"${fontsUrl}\" rel=\"stylesheet\">\nThen a <section class=\"w-[8.5in] h-[11in] relative overflow-hidden\"> sized for letter paper.\nUse the exact hex colors in Tailwind arbitrary values like bg-[${direction.colors.primary}] text-[${direction.colors.text}] etc.\nUse full-bleed backgrounds, geometric accents, elegant typography hierarchy.\nMake it look like a $50K design agency document cover.`\n : `Generate a hero section. Use inline style for font-family referencing the Google Fonts.\nStart with: <link href=\"${fontsUrl}\" rel=\"stylesheet\">\nThen a <section> with min-h-[80vh].\nUse the exact hex colors in Tailwind arbitrary values like bg-[${direction.colors.primary}] text-[${direction.colors.text}] etc.\nMake it look like a $50K agency landing page hero.`;\n\n const result = streamText({\n model,\n system: systemPrompt,\n prompt: `Brief: \"${prompt}\"\n\nDesign direction: \"${direction.name}\" — ${direction.tagline}\nLayout: ${direction.layoutHint}\nHeading font: ${direction.headingFont}\nBody font: ${direction.bodyFont}\nColors: primary=${direction.colors.primary}, accent=${direction.colors.accent}, surface=${direction.colors.surface}, surfaceAlt=${direction.colors.surfaceAlt}, text=${direction.colors.text}\nMood: ${direction.mood}\n\n${sectionInstruction}`,\n });\n\n let html = \"\";\n let chunkCount = 0;\n for await (const chunk of result.textStream) {\n html += chunk;\n chunkCount++;\n if (onChunk && chunkCount % 3 === 0) {\n onChunk(html);\n }\n }\n if (onChunk) onChunk(html);\n\n // Clean markdown fences if present\n html = html.trim();\n if (html.startsWith(\"```\")) {\n html = html.replace(/^```(?:html|xml)?\\s*/, \"\").replace(/\\s*```$/, \"\");\n }\n\n return html;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easybits.cloud/html-tailwind-generator",
3
- "version": "0.2.80",
3
+ "version": "0.2.81",
4
4
  "description": "AI-powered landing page generator with Tailwind CSS — canvas editor, streaming generation, and one-click deploy",
5
5
  "license": "PolyForm-Noncommercial-1.0.0",
6
6
  "type": "module",