<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Nicolás Deyros Blog</title><description>Programmer, Designer, and Creator - Insights on web development, AI, and technology</description><link>https://www.nicolasdeyros.dev/</link><language>en-us</language><managingEditor>Nicolás Deyros</managingEditor><webMaster>Nicolás Deyros</webMaster><generator>Astro RSS Generator</generator><ttl>60</ttl><item><title>DevLog: Building an Agentic Travel Planner</title><link>https://www.nicolasdeyros.dev/blog/building-agentic-travel-planner-astro-gemini/</link><guid isPermaLink="true">https://www.nicolasdeyros.dev/blog/building-agentic-travel-planner-astro-gemini/</guid><description>A deep dive into building a high-performance itinerary generator using Astro, React, and Gemini 3 Search Grounding in collaboration with an AI coding agent.</description><pubDate>Wed, 04 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;
For the past 24 hours, I’ve been working on &lt;strong&gt;Travel AI&lt;/strong&gt;, a high-performance itinerary generator. This wasn’t a solo project, nor was it a simple “AI prompt-to-code” session. I collaborated with a coding agent (&lt;strong&gt;Antigravity&lt;/strong&gt;) in a shared workspace where the agent had terminal access, managed the file system, and handled the DevOps pipeline.
Here is the technical breakdown of how we built it and how the human-agent collaboration actually functioned.&lt;/p&gt;
&lt;h2&gt;The Architecture: Astro Islands &amp;amp; Gemini 3&lt;/h2&gt;
&lt;p&gt;The goal was to build a fast, SEO-friendly site that still felt like a premium SPA. We chose Astro for its Multi-Page Application (MPA) benefits and used React islands for the complex form state management.&lt;/p&gt;
&lt;h3&gt;Brain: Gemini 3 (Flash-Preview)&lt;/h3&gt;
&lt;p&gt;We integrated the latest Gemini 3 model, specifically using the &lt;strong&gt;Search Grounding&lt;/strong&gt; feature. Unlike standard LLM responses, we configured the model to validate locations, opening hours, and travel routes against live web data.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Infrastructure&lt;/strong&gt;: We used a backend-first approach for the API to hide the API keys and handle rate limiting (5 req/hour) via server-side logic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation&lt;/strong&gt;: Every response from Gemini is piped through a Zod schema to ensure the JSON structure doesn’t break our frontend rendering.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Engineering Workflow: Collaborative Debugging&lt;/h2&gt;
&lt;p&gt;This is where the “Agentic” part gets real. It wasn’t just about writing code; it was about maintaining a high-quality codebase.&lt;/p&gt;
&lt;h3&gt;1. The Accessibility Fix (Pa11y &amp;amp; WCAG 2.1 AA)&lt;/h3&gt;
&lt;p&gt;The initial &lt;code&gt;TravelForm&lt;/code&gt; was functional but failed accessibility audits. &lt;strong&gt;Antigravity&lt;/strong&gt; ran Pa11y locally and identified 6 critical violations (WCAG 2.1 AA) related to dynamic inputs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Discovery&lt;/strong&gt;: The city autocomplete component (&lt;code&gt;CityInput&lt;/code&gt;) and the dynamic child-age inputs were missing proper ARIA relationships.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Fix&lt;/strong&gt;: Instead of me manually fixing labels, the agent implemented a dynamic ID system (&lt;code&gt;child-age-${i}&lt;/code&gt;) and added full keyboard navigation (ArrowUp/Down, Enter, Esc) to the search results. We re-ran the audit until we hit 0 errors.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. Solving the Union Type Mismatch&lt;/h3&gt;
&lt;p&gt;Right before the final push, we ran a strict TypeScript check (&lt;code&gt;tsc --noEmit&lt;/code&gt;). We hit a &lt;code&gt;TS2345&lt;/code&gt; error in &lt;code&gt;TravelForm.tsx&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Problem&lt;/strong&gt;: We were attempting to map a dynamic key from an &lt;code&gt;Object.entries&lt;/code&gt; iterator into a strict Union Type of travel priorities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Resolution&lt;/strong&gt;: We discussed the trade-off between softening the types or using a safer cast. We ended up implementing a verified type assertion to ensure the frontend wouldn’t crash during the translation lookup.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. Internationalization (i18n) Logic&lt;/h3&gt;
&lt;p&gt;We didn’t want to use client-side translation libraries that increase bundle size. We built a static translation map supporting 6 languages (ES, EN, PT, FR, IT, DE).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Agent’s Role&lt;/strong&gt;: Antigravity handled the heavy lifting of populating the missing translation keys for the &lt;code&gt;ErrorDisplay&lt;/code&gt; and &lt;code&gt;LoadingItinerary&lt;/code&gt; components, ensuring the UX was consistent regardless of the &lt;code&gt;serverLang&lt;/code&gt; prop.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Key Technical Specs&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance&lt;/strong&gt;: 100/100 Lighthouse score on Home and Plan pages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Management&lt;/strong&gt;: Localized React state for the multi-step form, synced with local storage for draft persistence.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animations&lt;/strong&gt;: Used &lt;code&gt;AnimatePresence&lt;/code&gt; from Framer Motion for a premium feel without sacrificing fluidity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI/CD&lt;/strong&gt;: Governed by a strict Git flow. Changes were never committed to main directly; the agent created branches, pushed to GitHub, and opened PRs using the GitHub CLI.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Final Reflection&lt;/h2&gt;
&lt;h2&gt;Collaborating with an agent that can execute &lt;code&gt;npm run build&lt;/code&gt; and &lt;code&gt;git push&lt;/code&gt; while you’re architecting the next feature is a game-changer. It’s no longer about “generating code,” but about &lt;strong&gt;Engineering Management&lt;/strong&gt; where the agent handles the technical audits (Lighthouse, Pa11y, TSC) and the human handles the product vision and logic edge cases.&lt;/h2&gt;
&lt;p&gt;Check out the project: 👉 &lt;strong&gt;&lt;a href=&quot;https://github.com/nicolas-deyros/travel-ai-agentic&quot;&gt;travel-ai-agentic&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content:encoded><category>AI Development</category><author>Nicolás Deyros</author></item><item><title>Engineering the Agentic Loop: Antigravity, Gemini &amp; MCPs</title><link>https://www.nicolasdeyros.dev/blog/from-zero-to-ai-hero/</link><guid isPermaLink="true">https://www.nicolasdeyros.dev/blog/from-zero-to-ai-hero/</guid><description>A technical deep dive into building an autonomous development workflow with Antigravity, Gemini CLI, and the Model Context Protocol (MCP).</description><pubDate>Fri, 16 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;
The transition from “AI as a Chatbot” to “AI as an Engineering Agent” happens when you close the loop between reasoning and execution. In this technical deep dive, I’ll explain how I architected an autonomous engineering system using &lt;strong&gt;Antigravity&lt;/strong&gt;, &lt;strong&gt;Gemini CLI&lt;/strong&gt;, and a specialized stack of &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; servers.&lt;/p&gt;
&lt;h3&gt;🛸 The Antigravity Orchestration Engine&lt;/h3&gt;
&lt;p&gt;At the heart of my workflow is &lt;strong&gt;Antigravity&lt;/strong&gt;—an autonomous agent designed to navigate complex codebases. Unlike standard LLMs, Antigravity operates as a “Pilot” that connects &lt;strong&gt;Gemini’s 1.5 Pro/Flash&lt;/strong&gt; reasoning models directly to my local filesystem and terminal.
The connection is established via a suite of automation tools in &lt;code&gt;tools/&lt;/code&gt; that standardize our interactions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;session:init&lt;/code&gt;&lt;/strong&gt;: An AI-driven environment audit that syncs Git state, verifies Node/NPM versions, and updates dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;git:start&lt;/code&gt;&lt;/strong&gt;: A programmatic bridge that initializes features, creates conventional branches, and uses the &lt;strong&gt;GitHub CLI&lt;/strong&gt; to open Draft PRs automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;git:ship&lt;/code&gt;&lt;/strong&gt;: The final delivery sequence—Antigravity runs a full validation suite (Lighthouse, Vitest, Playwright), pushes the code, and initiates an auto-merge via GitHub.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;🔌 Scaling Intelligence with MCP&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; is the “USB-C for AI.” It allows Antigravity to plug into specialized intelligence silos. My current “Agentic Stack” includes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;TestSprite MCP&lt;/strong&gt;: This is my autonomous QA department. It analyzes my code, generates a &lt;strong&gt;Standardized PRD&lt;/strong&gt;, and writes/executes its own end-to-end tests without human intervention.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Astro Docs MCP&lt;/strong&gt;: Provides Antigravity with real-time, RAG-enhanced access to the latest Astro documentation, preventing “hallucinations” on new framework features.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub MCP&lt;/strong&gt;: Deep integration with the repository lifecycle—managing issues, PR comments, and CI/CD status checks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chrome DevTools MCP&lt;/strong&gt;: Allows the agent to “see” into the browser during E2E testing, inspecting the DOM and console logs to debug hydration issues in real-time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESLint &amp;amp; CSS MCPs&lt;/strong&gt;: Programmatic code quality gates that ensure every line Antigravity writes adheres to the project’s strict styling and logic rules.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;🧠 The Hybrid AI Architecture&lt;/h3&gt;
&lt;p&gt;For the blog’s frontend features (like Summarization and Translation), I engineered a &lt;strong&gt;Hybrid AI Strategy&lt;/strong&gt; designed for resilience:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[User Request] --&amp;gt; B{Browser Support?}
    B -- Yes --&amp;gt; C[Gemini Nano / Chrome AI]
    B -- No --&amp;gt; D[Gemini 1.5 Flash Cloud]
    C -- Timeout/Fail --&amp;gt; D
    D --&amp;gt; E[Astro DB Cache Check]
    E -- Miss --&amp;gt; F[Cloud Generation]
    F --&amp;gt; G[Store in AICache]
    G --&amp;gt; H[Return Result]
    E -- Hit --&amp;gt; H
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Local Processing&lt;/strong&gt;: We prioritize &lt;strong&gt;Gemini Nano&lt;/strong&gt; (Chrome’s on-device model) for data privacy and zero-latency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resilient Fallback&lt;/strong&gt;: If the experimental Chrome APIs fail (e.g., model download timeouts), the system transparently flips to a server-side endpoint powered by &lt;code&gt;gemini-1.5-flash&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Intelligent Caching&lt;/strong&gt;: We implemented an &lt;code&gt;AICache&lt;/code&gt; table in &lt;strong&gt;Astro DB&lt;/strong&gt;. By hashing the content, we ensure that we never pay for the same summary twice, significantly reducing API overhead and improving user response times.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;🛠️ Technical Resilience in Agentic Workflows&lt;/h3&gt;
&lt;p&gt;Building with autonomous agents requires “Defensive Engineering.” Every tool Antigravity uses is wrapped in robust error handling. For instance, our &lt;strong&gt;GitHub Automation&lt;/strong&gt; handles merge conflicts via the AI’s own reasoning, while our &lt;strong&gt;Grammar Checker&lt;/strong&gt; utility (&lt;code&gt;tools/grammar-checker.ts&lt;/code&gt;) automatically cleans up residual metadata to keep the history clean.&lt;/p&gt;
&lt;h3&gt;🎯 Conclusion: The Future of DevEx&lt;/h3&gt;
&lt;p&gt;By combining Gemini’s reasoning with the tool-using capabilities of Antigravity and the extensibility of MCP, I’ve moved from “coding” to “orchestrating.” This setup allows me to maintain a &lt;strong&gt;100 Lighthouse score&lt;/strong&gt; and 80%+ test coverage while focusing 100% on architecture rather than boilerplate.
The era of the “Solo Dev” is ending; the era of the &lt;strong&gt;Orchestrator&lt;/strong&gt; has begun.&lt;/p&gt;
</content:encoded><category>Artificial Intelligence</category><author>Nicolás Deyros</author></item><item><title>Implementing Chrome AI APIs in Astro Blog</title><link>https://www.nicolasdeyros.dev/blog/chrome-ai-translation-summarizer-implementation/</link><guid isPermaLink="true">https://www.nicolasdeyros.dev/blog/chrome-ai-translation-summarizer-implementation/</guid><description>Deep dive into implementing Chrome&apos;s experimental AI Translation and Summarizer APIs in an Astro-powered blog.</description><pubDate>Wed, 13 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The future of web development is here, and it runs directly in your browser. Recently, I integrated Chrome’s experimental &lt;strong&gt;AI Translation API&lt;/strong&gt; and &lt;strong&gt;Summarizer API&lt;/strong&gt; into this Astro-powered blog, bringing client-side AI capabilities to enhance the reading experience. This implementation showcases how modern browsers are becoming powerful AI platforms.&lt;/p&gt;
&lt;h2&gt;Why Browser-Native AI?&lt;/h2&gt;
&lt;p&gt;Traditional AI implementations require server-side processing, API keys, and external service dependencies. Chrome’s experimental AI APIs change this paradigm by running &lt;strong&gt;entirely in the browser&lt;/strong&gt;, offering:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Zero latency&lt;/strong&gt; - No network requests needed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Privacy-first&lt;/strong&gt; - Content never leaves the user’s device&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost-effective&lt;/strong&gt; - No API usage fees or rate limits&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Offline capability&lt;/strong&gt; - Works without internet connectivity&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Progressive enhancement&lt;/strong&gt; - Graceful fallbacks for unsupported browsers&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Technical Architecture Overview&lt;/h2&gt;
&lt;p&gt;The implementation consists of two main components integrated into the Astro blog architecture:&lt;/p&gt;
&lt;h3&gt;Core Components Structure&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;src/
├── components/
│   ├── Translation/
│   │   └── BlogTranslator.astro
│   └── Summary/
│       └── BlogSummarizer.astro
├── utils/
│   ├── translator.ts
│   └── summarizer.ts
└── pages/blog/
    └── [slug].astro
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Chrome AI Translation API Implementation&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/ai/translator-api&quot;&gt;Chrome AI Translation API&lt;/a&gt; provides on-device language translation capabilities. Here’s how I implemented it:&lt;/p&gt;
&lt;h3&gt;1. TypeScript Interface Definition&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// translator.ts
declare global {
	interface Window {
		translation: {
			canTranslate(options: {
				sourceLanguage: string
				targetLanguage: string
			}): Promise&amp;lt;&apos;readily&apos; | &apos;after-download&apos; | &apos;no&apos;&amp;gt;
			createTranslator(options: {
				sourceLanguage: string
				targetLanguage: string
			}): Promise&amp;lt;{
				translate(text: string): Promise&amp;lt;string&amp;gt;
				destroy(): void
			}&amp;gt;
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Translation Service Class&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;export class BlogTranslator {
	private translator: any = null
	private isInitialized = false
	async isSupported(): Promise&amp;lt;boolean&amp;gt; {
		return &apos;translation&apos; in window &amp;amp;&amp;amp; &apos;canTranslate&apos; in window.translation
	}
	async canTranslate(
		sourceLanguage: string,
		targetLanguage: string,
	): Promise&amp;lt;string&amp;gt; {
		if (!(await this.isSupported())) {
			return &apos;no&apos;
		}
		return await window.translation.canTranslate({
			sourceLanguage,
			targetLanguage,
		})
	}
	async translateBlogPost(
		content: string,
		targetLanguage: string,
		onProgress?: (progress: number) =&amp;gt; void,
	): Promise&amp;lt;TranslationResult&amp;gt; {
		// Implementation details...
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Astro Component Integration&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;BlogTranslator.astro&lt;/code&gt; component provides a clean UI with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Language selection dropdown&lt;/strong&gt; with 50+ supported languages&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-time progress tracking&lt;/strong&gt; using semantic HTML &lt;code&gt;&amp;lt;progress&amp;gt;&lt;/code&gt; elements&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error handling&lt;/strong&gt; with user-friendly dialog messages&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Responsive design&lt;/strong&gt; that works across all device sizes&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- BlogTranslator.astro --&amp;gt;
&amp;lt;div class=&quot;blog-translator&quot;&amp;gt;
	&amp;lt;select id=&quot;language-selector&quot;&amp;gt;
		&amp;lt;option value=&quot;es&quot;&amp;gt;Spanish&amp;lt;/option&amp;gt;
		&amp;lt;option value=&quot;fr&quot;&amp;gt;French&amp;lt;/option&amp;gt;
		&amp;lt;!-- ... more languages --&amp;gt;
	&amp;lt;/select&amp;gt;
	&amp;lt;button id=&quot;translate-btn&quot;&amp;gt;🌐 Translate Article&amp;lt;/button&amp;gt;
	&amp;lt;progress id=&quot;progress-bar&quot; value=&quot;0&quot; max=&quot;100&quot;&amp;gt;&amp;lt;/progress&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Chrome AI Summarizer API Implementation&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/ai/summarizer-api&quot;&gt;Chrome AI Summarizer API&lt;/a&gt; generates intelligent content summaries. The implementation follows similar patterns:&lt;/p&gt;
&lt;h3&gt;1. Summarizer TypeScript Interface&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// summarizer.ts
type SummarizerType = &apos;teaser&apos; | &apos;key-points&apos; | &apos;headline&apos;
type SummarizerLength = &apos;short&apos; | &apos;medium&apos; | &apos;long&apos;
declare global {
	interface Window {
		Summarizer: {
			availability(): Promise&amp;lt;&apos;available&apos; | &apos;downloadable&apos; | &apos;no&apos;&amp;gt;
			create(options: {
				type?: SummarizerType
				length?: SummarizerLength
				format?: &apos;markdown&apos; | &apos;plain-text&apos;
			}): Promise&amp;lt;{
				summarize(text: string): Promise&amp;lt;string&amp;gt;
				destroy(): void
			}&amp;gt;
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Summarizer Service Implementation&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;export class BlogSummarizer {
	async summarizeBlogPost(
		markdown: string,
		options: SummaryOptions,
		onProgress?: (status: string) =&amp;gt; void,
	): Promise&amp;lt;SummaryResult&amp;gt; {
		// Check API availability
		const availability = await window.Summarizer.availability()
		if (availability === &apos;downloadable&apos;) {
			onProgress?.(&apos;Model downloading...&apos;)
			await this.waitForModelDownload()
		}
		// Create summarizer instance
		const summarizer = await window.Summarizer.create(options)
		// Process and clean markdown content
		const cleanText = this.cleanMarkdownForSummarization(markdown)
		// Generate summary
		const summary = await summarizer.summarize(cleanText)
		return {
			summary,
			type: options.type,
			length: options.length,
			wordCount: summary.trim().split(/\s+/).length,
			timestamp: new Date().toISOString(),
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Enhanced UI with Multiple Summary Types&lt;/h3&gt;
&lt;p&gt;The summarizer component offers three summary types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TL;DR (Teaser)&lt;/strong&gt; - Quick, engaging overview&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key Points&lt;/strong&gt; - Main concepts and takeaways&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Headline&lt;/strong&gt; - Concise, social-media ready summary&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;summary-controls&quot;&amp;gt;
	&amp;lt;button data-type=&quot;teaser&quot;&amp;gt;TL;DR&amp;lt;/button&amp;gt;
	&amp;lt;button data-type=&quot;key-points&quot;&amp;gt;Key Points&amp;lt;/button&amp;gt;
	&amp;lt;button data-type=&quot;headline&quot;&amp;gt;Headline&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Key Implementation Challenges &amp;amp; Solutions&lt;/h2&gt;
&lt;h3&gt;1. API Compatibility Issues&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: The &lt;code&gt;&apos;tl;dr&apos;&lt;/code&gt; summary type wasn’t recognized by the API.
&lt;strong&gt;Solution&lt;/strong&gt;: Mapped user-friendly “TL;DR” to the valid &lt;code&gt;&apos;teaser&apos;&lt;/code&gt; type internally while maintaining the familiar UI label.&lt;/p&gt;
&lt;h3&gt;2. Progress Bar Standardization&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Inconsistent progress implementations using div-based fake progress bars.
&lt;strong&gt;Solution&lt;/strong&gt;: Migrated to semantic HTML &lt;code&gt;&amp;lt;progress&amp;gt;&lt;/code&gt; elements with cross-browser CSS styling:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;progress {
	appearance: none;
	-webkit-appearance: none;
}
progress::-webkit-progress-value {
	background-color: rgb(37 99 235);
	border-radius: 0.5rem;
	transition: all 0.3s ease-in-out;
}
progress::-moz-progress-bar {
	background-color: rgb(37 99 235);
	border-radius: 0.5rem;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Button Selection State Management&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Selected summary type buttons had conflicting CSS classes causing invisible text.
&lt;strong&gt;Solution&lt;/strong&gt;: Implemented proper state management with complete class replacement:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Remove all state classes, then add appropriate ones
summaryTypeBtns.forEach(b =&amp;gt; {
	b.classList.remove(
		&apos;bg-blue-600&apos;,
		&apos;text-white&apos;,
		&apos;border-blue-600&apos;,
		&apos;shadow-md&apos;,
	)
	b.classList.add(&apos;bg-white&apos;, &apos;text-gray-700&apos;, &apos;border-gray-300&apos;)
})
// Apply selected state to clicked button
btn.classList.remove(&apos;bg-white&apos;, &apos;text-gray-700&apos;, &apos;border-gray-300&apos;)
btn.classList.add(&apos;bg-blue-600&apos;, &apos;text-white&apos;, &apos;border-blue-600&apos;, &apos;shadow-md&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Browser Support &amp;amp; Progressive Enhancement&lt;/h2&gt;
&lt;h3&gt;Feature Detection&lt;/h3&gt;
&lt;p&gt;Both APIs implement robust feature detection:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async isSupported(): Promise&amp;lt;boolean&amp;gt; {
  return &apos;translation&apos; in window &amp;amp;&amp;amp; &apos;canTranslate&apos; in window.translation
}
async checkSummarizer(): Promise&amp;lt;boolean&amp;gt; {
  return &apos;Summarizer&apos; in window
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Graceful Fallbacks&lt;/h3&gt;
&lt;p&gt;When APIs aren’t available, users see helpful information dialogs explaining:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to enable Chrome flags&lt;/li&gt;
&lt;li&gt;Alternative browser recommendations&lt;/li&gt;
&lt;li&gt;Manual summarization suggestions&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Chrome Flags Required&lt;/h3&gt;
&lt;p&gt;Users need these experimental flags enabled:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chrome://flags/#optimization-guide-on-device-model
chrome://flags/#translation-api
chrome://flags/#summarization-api-for-gemini-nano
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Performance Optimizations&lt;/h2&gt;
&lt;h3&gt;1. Lazy Loading&lt;/h3&gt;
&lt;p&gt;Components only initialize when needed, reducing initial bundle size.&lt;/p&gt;
&lt;h3&gt;2. Efficient Content Processing&lt;/h3&gt;
&lt;p&gt;Markdown content is cleaned and optimized before API processing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private cleanMarkdownForSummarization(markdown: string): string {
  return markdown
    .replace(/```[\s\S]*?```/g, &apos;&apos;) // Remove code blocks
    .replace(/`([^`]+)`/g, &apos;$1&apos;)     // Remove inline code
    .replace(/!\[([^\]]*)\]\([^)]+\)/g, &apos;$1&apos;) // Keep alt text only
    .replace(/\[([^\]]+)\]\([^)]+\)/g, &apos;$1&apos;)  // Keep link text only
    .replace(/^#{1,6}\s+/gm, &apos;&apos;)     // Remove headers
    .replace(/\n\s*\n/g, &apos;\n\n&apos;)     // Clean whitespace
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Smart Progress Animation&lt;/h3&gt;
&lt;p&gt;Realistic progress indication based on actual processing stages rather than arbitrary increments.&lt;/p&gt;
&lt;h2&gt;Integration with Astro&lt;/h2&gt;
&lt;p&gt;The APIs integrate seamlessly with Astro’s architecture:&lt;/p&gt;
&lt;h3&gt;1. Component Props&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;---
interface Props {
	className?: string
	markdown?: string
}
const { className = &apos;&apos;, markdown = &apos;&apos; } = Astro.props
---
&amp;lt;BlogSummarizer className={className} markdown={markdown} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. SSR Compatibility&lt;/h3&gt;
&lt;p&gt;All AI processing happens client-side, maintaining Astro’s SSR benefits while adding progressive enhancement.&lt;/p&gt;
&lt;h3&gt;3. View Transitions Support&lt;/h3&gt;
&lt;p&gt;Components properly handle Astro’s view transitions with cleanup functions:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;document.addEventListener(&apos;astro:before-preparation&apos;, () =&amp;gt; {
	if (cleanup) {
		cleanup()
		cleanup = null
	}
})
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Future Possibilities&lt;/h2&gt;
&lt;p&gt;This implementation opens doors for exciting possibilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi-language content creation&lt;/strong&gt; workflows&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessibility improvements&lt;/strong&gt; with AI-generated descriptions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content optimization&lt;/strong&gt; based on AI-generated insights&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Personalized reading experiences&lt;/strong&gt; with AI-driven customization&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;Want to implement these APIs in your own project? Here’s the checklist:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Enable Chrome flags&lt;/strong&gt; for AI APIs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implement TypeScript interfaces&lt;/strong&gt; for type safety&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create service classes&lt;/strong&gt; for API interaction&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build UI components&lt;/strong&gt; with proper error handling&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add progressive enhancement&lt;/strong&gt; for unsupported browsers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test thoroughly&lt;/strong&gt; across different content types&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;h2&gt;Chrome’s AI APIs represent a paradigm shift toward privacy-focused, client-side AI processing. This implementation demonstrates how modern web applications can leverage browser-native AI capabilities while maintaining excellent user experiences and progressive enhancement principles.
The integration of translation and summarization features directly into the blog enhances accessibility and user engagement without compromising performance or privacy. As these APIs mature and gain broader browser support, they’ll become essential tools for creating intelligent, user-centric web applications.&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This implementation was developed with assistance from &lt;strong&gt;Claude Sonnet&lt;/strong&gt;, whose insights were invaluable in solving complex integration challenges and optimizing the user experience. The complete source code is available in the &lt;a href=&quot;https://github.com/nicolas-deyros/astro-portfolio-v2&quot;&gt;astro-portfolio-v2&lt;/a&gt; repository.&lt;/em&gt;
&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/ai/translator-api&quot;&gt;Chrome AI Translation API Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/ai/summarizer-api&quot;&gt;Chrome AI Summarizer API Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build&quot;&gt;Astro Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Web Development</category><author>Nicolás Deyros</author></item><item><title>Pokémon Card Battle Arena</title><link>https://www.nicolasdeyros.dev/blog/pokemon-card-battle-arena/</link><guid isPermaLink="true">https://www.nicolasdeyros.dev/blog/pokemon-card-battle-arena/</guid><description>Learn how I built a Pokémon Card Battle Arena using React, TypeScript, and the PokeAPI.</description><pubDate>Thu, 07 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Welcome, developers and Pokémon trainers! Today, we’re taking a deep dive into the code behind the &lt;strong&gt;Pokémon Card Battle Arena&lt;/strong&gt;, a dynamic web application built with modern frontend technologies. This app allows users to search for their favorite Pokémon, build a custom team of three, and face off against a computer-controlled opponent in a turn-based battle. It also features a Pokémon evolution explorer.&lt;/p&gt;
&lt;aside&gt;
	**TL;DR:** This article breaks down the architecture of a Pokémon battle
	simulator built with React, TypeScript, and Tailwind CSS, and explores how to
	enhance it with Generative AI.
&lt;/aside&gt;
Let&apos;s unpack the key technologies and architectural decisions that bring this interactive experience to life.
## The Tech Stack
The application is built on a robust and modern foundation:
- **Framework**: React with TypeScript for a type-safe, component-based UI.
- **Styling**: Tailwind CSS for rapid, utility-first styling, augmented with custom CSS for complex animations and the signature holographic card effect.
- **Data Source**: The invaluable [PokeAPI](https://pokeapi.co/), a free and open-source RESTful API for all things Pokémon.
- **State Management**: A combination of React&apos;s `useState` and `useReducer` hooks, creating a powerful and predictable state machine for the complex game logic.
## Core Feature Deep Dive
### The Holographic Card Effect
The centerpiece of the UI is the interactive, holographic Pokémon card. It&apos;s not just a static image; it&apos;s a multi-layered component that responds to user interaction, creating a stunning 3D effect.

Here’s how it works:
1.  **Perspective &amp;amp; 3D Transform**: The parent `card-wrapper` div establishes a `perspective`, creating a 3D space for its children. The `holo-card` itself uses `transform: rotateX() rotateY()` to tilt in 3D space.
2.  **Mouse Tracking**: An `onMouseMove` event handler on the card&apos;s wrapper captures the mouse&apos;s X and Y coordinates relative to the card&apos;s dimensions.
3.  **Dynamic CSS Variables**: The JavaScript logic calculates the desired rotation based on the mouse position and updates CSS custom properties (`--x`, `--y`, `--color1`, `--color2`) in real-time.
4.  **Layered Gradients &amp;amp; Effects**: The magic lies in the `::before` and `::after` pseudo-elements.
    - The `::before` element creates the holographic sheen using a `linear-gradient`. Its background position is updated via the `--x` and `--y` variables, making the light source appear to move with the user&apos;s cursor.
    - The `::after` element overlays sparkle and texture images, further enhancing the holographic illusion.
```typescript
// In PokemonCard.tsx
const handleMouseMove = (e: React.MouseEvent) =&amp;gt; {
	const { clientX, clientY, currentTarget } = e
	const { top, left, width, height } = currentTarget.getBoundingClientRect()
	const mouseX = (clientX - left) / width
	const mouseY = (clientY - top) / height
	const rotateX = 15 * (mouseY - 0.5)
	const rotateY = -15 * (mouseX - 0.5)
	setStyle({
		transform: `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`,
		&apos;--x&apos;: `${mouseX * 100}%`,
		&apos;--y&apos;: `${mouseY * 100}%`,
	})
}
```
### The Game Logic
Managing the state of a turn-based game can be complex. To handle this cleanly, all battle logic is encapsulated within a custom React hook: `useGameLogic`. This hook employs a `useReducer` state machine, which is perfect for managing state transitions with discrete actions.
The `gameReducer` function handles actions like:
- `START_SUCCESS`: Initializes the game with player and computer teams.
- `ATTACK`: Kicks off the turn, setting an attack in motion.
- `PROCESS_TURN`: Calculates and applies damage to the defending Pokémon.
- `FAINT_SWITCH`: Handles the logic when a Pokémon faints, forcing a switch or ending the game.
- `SWITCH_POKEMON`: Manages a player switching their active Pokémon.
- `GAME_OVER`: Declares a winner and transitions to the game-over screen.
&lt;aside&gt;
	**Pro Tip:** Using a reducer for game logic makes it easy to debug and test,
	as each state transition is a pure function.
&lt;/aside&gt;
### Team Selection
Before battling, a trainer must choose their team. The `TeamSelection` component provides a seamless experience for this:
- **Pokémon Discovery**: An `AutocompleteSearch` component allows users to find any Pokémon by name.
- **Drag-and-Drop Interface**: The core of the team builder uses the native HTML5 Drag and Drop API. Users can drag Pokémon from a &quot;popular&quot; list or reorder their chosen Pokémon within the three team slots.
## Future Potential: Integrating Generative AI with Gemini
While the current application is fully functional, its architecture is ripe for enhancement with a powerful large language model like Google&apos;s Gemini. Here are a few ways we could level-up the experience:
### A Truly Intelligent AI Opponent
The current rule-based AI could be replaced with a call to the Gemini API. We could send the entire game state and ask Gemini to act as a Pokémon battle strategist.
&lt;aside&gt;
	**Prompt:** &quot;You are a Pokémon battle AI. The player&apos;s active Pokémon is a
	Charizard with 150 HP. Your active Pokémon is a Blastoise with 160 HP. Your
	available moves are Hydro Pump (110 power), Skull Bash (130 power), and Water
	Gun (40 power). Choose the best move and explain your reasoning in one
	sentence.&quot;
&lt;/aside&gt;
### Dynamic Battle Commentary
The static battle log could be transformed into a lively, narrative experience. After each action, we could ask Gemini to generate flavorful text.
&lt;aside&gt;
	**Prompt:** &quot;Generate a short, exciting battle commentary line. Pikachu used
	Thunderbolt on Gyarados. It was super effective!&quot;
&lt;/aside&gt;
&lt;aside&gt;
	**Gemini Response:** &quot;A massive bolt of lightning erupts from Pikachu,
	engulfing the colossal Gyarados in a crackling storm of energy!&quot;
&lt;/aside&gt;
## Conclusion
The Pokémon Card Battle Arena is a testament to what can be achieved with modern web technologies. By combining the component-based power of React, the vast data source of the PokeAPI, and the aesthetic flexibility of advanced CSS, we can create rich, engaging, and performant web applications. The modular design not only makes the code maintainable but also opens the door for exciting future integrations with generative AI.
_Want to explore the code? Check out the [live demo](https://pok-mon-card-battle-arena-1071820676408.us-west1.run.app/)_</content:encoded><category>Web Development</category><author>Nicolás Deyros</author></item><item><title>AI-Powered Weather App Development</title><link>https://www.nicolasdeyros.dev/blog/ai-powered-weather-app-development/</link><guid isPermaLink="true">https://www.nicolasdeyros.dev/blog/ai-powered-weather-app-development/</guid><description>Learn how I built a modern weather app using Astro, TypeScript, and AI assistants like GitHub Copilot and Google Jules.</description><pubDate>Sun, 03 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Building a Production-Ready Weather App: A Journey with AI-Powered Development&lt;/h1&gt;
&lt;div&gt;
	_How I built a comprehensive weather application using Astro, TypeScript, and
	Tailwind CSS with the help of AI assistants - and what I learned along the
	way._
&lt;/div&gt;
---
## The Beginning: A Simple Idea
It started as many projects do - with a simple need. I wanted to build a modern weather application that would showcase real-world development practices, from initial concept to production deployment. But this wasn&apos;t going to be just another tutorial project. I wanted to explore something exciting: **AI-assisted development**.
Armed with access to two cutting-edge AI assistants - GitHub Copilot and Jules (Google&apos;s experimental AI) - I embarked on a journey that would teach me as much about collaborative AI development as it would about building great software.
&lt;div&gt;
	&lt;h4&gt;
		💡 Key Insight
	&lt;/h4&gt;
	&lt;p&gt;
		This wasn&apos;t just about building a weather app - it was about exploring a new
		paradigm of development where AI assistants become collaborative partners in
		the creative process.
	&lt;/p&gt;
&lt;/div&gt;
## The Tech Stack: Modern and Minimal
Before diving into code, I needed to choose the right tools. After some consideration, I settled on:
&lt;div&gt;
	&lt;div&gt;
		&lt;h3&gt;
			🚀 Astro 5.12.6
		&lt;/h3&gt;
		&lt;p&gt;
			For its islands architecture and excellent performance
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;div&gt;
		&lt;h3&gt;
			📘 TypeScript
		&lt;/h3&gt;
		&lt;p&gt;
			For type safety and better developer experience
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;div&gt;
		&lt;h3&gt;
			🎨 Tailwind CSS 4.1.11
		&lt;/h3&gt;
		&lt;p&gt;
			For rapid, utility-first styling
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;div&gt;
		&lt;h3&gt;
			🌤️ Open-Meteo API
		&lt;/h3&gt;
		&lt;p&gt;
			For reliable, free weather data
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;div&gt;
		&lt;h3&gt;
			⚡ Vercel
		&lt;/h3&gt;
		&lt;p&gt;
			For seamless deployment and serverless functions
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;div&gt;
		&lt;h3&gt;
			🤖 AI Assistants
		&lt;/h3&gt;
		&lt;p&gt;
			GitHub Copilot &amp;amp; Google Jules
		&lt;/p&gt;
	&lt;/div&gt;
&lt;/div&gt;
The beauty of this stack is its simplicity. No complex state management, no unnecessary abstractions - just modern web technologies working together harmoniously.
## Chapter 1: Building the Foundation
### The Core Architecture
The first major decision was how to structure the application. I chose Astro&apos;s file-based routing with a server-side rendering approach:
This API endpoint became the backbone of the application. Notice how I implemented proper error handling from the start - a practice that would prove crucial as the app grew in complexity.
### The Weather Data Transformation
One of the most interesting challenges was transforming the Open-Meteo API response into something more usable. The raw API returns weather codes (integers) that need to be mapped to human-readable descriptions and appropriate icons:
```typescript
// src/utils/weatherMapping.ts
export const WEATHER_CODE_MAPPING = {
	0: { icon: &apos;meteocons:clear-day-fill&apos;, description: &apos;Clear sky&apos; },
	1: { icon: &apos;meteocons:partly-cloudy-day-fill&apos;, description: &apos;Mainly clear&apos; },
	2: { icon: &apos;meteocons:partly-cloudy-day-fill&apos;, description: &apos;Partly cloudy&apos; },
	3: { icon: &apos;meteocons:overcast-fill&apos;, description: &apos;Overcast&apos; },
	45: { icon: &apos;meteocons:fog-fill&apos;, description: &apos;Fog&apos; },
	48: { icon: &apos;meteocons:fog-fill&apos;, description: &apos;Depositing rime fog&apos; },
	51: { icon: &apos;meteocons:drizzle-fill&apos;, description: &apos;Light drizzle&apos; },
	// ... 50+ more mappings
} as const
```
This mapping system proved to be one of the most valuable parts of the application - it centralized all weather interpretation logic and made testing much easier.
## Chapter 2: The AI Collaboration Begins
### Working with GitHub Copilot
&lt;div&gt;
	&lt;div&gt;
		&lt;span&gt;🤖&lt;/span&gt;
		&lt;h4&gt;
			GitHub Copilot
		&lt;/h4&gt;
		&lt;span&gt;
			Code Completion Specialist
		&lt;/span&gt;
	&lt;/div&gt;
	&lt;div&gt;
		&lt;strong&gt;Strengths:&lt;/strong&gt; Pattern recognition, code completion, repetitive
		tasks
	&lt;/div&gt;
&lt;/div&gt;
GitHub Copilot became my constant companion during the development process. Its suggestions were particularly brilliant when working on repetitive patterns. For example, when building the weather icon animations, Copilot helped me create a comprehensive set of CSS keyframes:
```css
/* AI-assisted animation creation */
@keyframes rainDrop {
	0%,
	100% {
		transform: translateY(0px);
	}
	50% {
		transform: translateY(-10px);
	}
}
@keyframes snowFloat {
	0%,
	100% {
		transform: translateY(0px) rotate(0deg);
	}
	33% {
		transform: translateY(-8px) rotate(120deg);
	}
	66% {
		transform: translateY(-4px) rotate(240deg);
	}
}
@keyframes thunderPulse {
	0%,
	100% {
		transform: scale(1);
		opacity: 1;
	}
	25% {
		transform: scale(1.1);
		opacity: 0.8;
	}
	50% {
		transform: scale(1.05);
		opacity: 1;
	}
	75% {
		transform: scale(1.15);
		opacity: 0.7;
	}
}
```
Copilot didn&apos;t just suggest code - it understood the context and helped me maintain consistency across all animations.
### The Jules (Google AI) Experience
&lt;div&gt;
	&lt;div&gt;
		&lt;span&gt;🧠&lt;/span&gt;
		&lt;h4&gt;
			Jules (Google AI)
		&lt;/h4&gt;
		&lt;span&gt;
			Strategic Architecture Advisor
		&lt;/span&gt;
	&lt;/div&gt;
	&lt;div&gt;
		&lt;strong&gt;Strengths:&lt;/strong&gt; Strategic guidance, debugging, architectural
		decisions
	&lt;/div&gt;
&lt;/div&gt;
Working with Jules brought a different perspective to the development process. Where Copilot excelled at code completion and pattern recognition, Jules provided more strategic guidance on architecture decisions and debugging complex issues.
When I encountered a tricky bug where weather icons weren&apos;t displaying properly, Jules helped me trace through the entire data flow:
&lt;div&gt;
	&lt;ol&gt;
		&lt;li&gt;
			&lt;strong&gt;API Response Analysis&lt;/strong&gt; - Verified the Open-Meteo API was
			returning correct data
		&lt;/li&gt;
		&lt;li&gt;
			&lt;strong&gt;Data Transformation&lt;/strong&gt; - Checked that weather codes were
			being mapped correctly
		&lt;/li&gt;
		&lt;li&gt;
			&lt;strong&gt;Icon Resolution&lt;/strong&gt; - Identified that the Astro Icon
			component needed proper fallbacks
		&lt;/li&gt;
		&lt;li&gt;
			&lt;strong&gt;Client-Side Rendering&lt;/strong&gt; - Discovered issues with hydration
			timing
		&lt;/li&gt;
	&lt;/ol&gt;
&lt;/div&gt;
This systematic approach led to implementing a robust fallback system:
```typescript
// Emoji-based fallback system for reliable icon display
function createWeatherIcon(iconName: string, isLarge: boolean = false): string {
	const sizeClass = isLarge ? &apos;text-8xl&apos; : &apos;text-4xl&apos;
	let emoji = &apos;☁️&apos;
	let animationClass = &apos;&apos;
	switch (iconName) {
		case &apos;meteocons:clear-day-fill&apos;:
			emoji = &apos;☀️&apos;
			animationClass = &apos;animate-bounce&apos;
			break
		case &apos;meteocons:rain-fill&apos;:
			emoji = &apos;🌧️&apos;
			animationClass = &apos;animate-rain-drop&apos;
			break
		// Smart pattern matching for unknown icons
		default:
			if (iconName.includes(&apos;clear&apos;) &amp;amp;&amp;amp; iconName.includes(&apos;day&apos;)) {
				emoji = &apos;☀️&apos;
				animationClass = &apos;animate-bounce&apos;
			} else if (iconName.includes(&apos;rain&apos;)) {
				emoji = &apos;🌧️&apos;
				animationClass = &apos;animate-rain-drop&apos;
			}
		// ... more intelligent fallbacks
	}
	return `&lt;span&gt;${emoji}&lt;/span&gt;`
}
```
## Chapter 3: The Iteration Cycles
### First Iteration: Basic Functionality
The first working version was surprisingly straightforward:
- Simple location input
- Basic weather display
- Minimal styling
But as I started using it, the limitations became apparent. The user experience was clunky, error handling was minimal, and the design felt amateurish.
### Second Iteration: Enhanced UX
This is where the AI collaboration really shone. Both Copilot and Jules helped me identify UX improvements:
**Quick Location Buttons:**
```astro

&lt;div&gt;
	
		🇬🇧 London
	
	
		🇺🇸 New York
	
	
&lt;/div&gt;
```
**Geolocation Integration:**
```javascript
// AI-assisted geolocation with proper error handling
async function getCurrentLocation() {
	if (!navigator.geolocation) {
		throw new Error(&apos;Geolocation is not supported by this browser&apos;)
	}
	return new Promise((resolve, reject) =&amp;gt; {
		const options = {
			enableHighAccuracy: true,
			timeout: 15000,
			maximumAge: 300000, // 5 minutes
		}
		navigator.geolocation.getCurrentPosition(
			position =&amp;gt; {
				const { latitude, longitude } = position.coords
				resolve({ lat: latitude, lon: longitude })
			},
			error =&amp;gt; {
				const errorMessages = {
					1: &apos;Location access denied by user&apos;,
					2: &apos;Location information is unavailable&apos;,
					3: &apos;Location request timed out&apos;,
				}
				reject(new Error(errorMessages[error.code] || &apos;Unknown location error&apos;))
			},
			options,
		)
	})
}
```
### Third Iteration: Production Polish
The final iteration focused on production readiness. This meant:
1. **Comprehensive Error Handling**
2. **Performance Optimization**
3. **Accessibility Improvements**
4. **Mobile Responsiveness**
5. **SEO Optimization**
## Chapter 4: The Testing Revolution
### AI-Assisted Test Development
One of the most impressive aspects of working with AI was how it helped me build a comprehensive test suite. Starting with utility tests:
```typescript
// src/test/utils.test.ts - AI helped structure comprehensive tests
	getWeatherDescription,
	getWeatherIcon,
	convertToFahrenheit,
	convertToCelsius,
} from &apos;../utils/weatherMapping&apos;
describe(&apos;Weather Utilities&apos;, () =&amp;gt; {
	describe(&apos;Temperature Conversion&apos;, () =&amp;gt; {
		it(&apos;should convert Celsius to Fahrenheit correctly&apos;, () =&amp;gt; {
			expect(convertToFahrenheit(0)).toBe(32)
			expect(convertToFahrenheit(25)).toBe(77)
			expect(convertToFahrenheit(-10)).toBe(14)
		})
		it(&apos;should convert Fahrenheit to Celsius correctly&apos;, () =&amp;gt; {
			expect(convertToCelsius(32)).toBe(0)
			expect(convertToCelsius(77)).toBe(25)
			expect(convertToCelsius(14)).toBe(-10)
		})
	})
	describe(&apos;Weather Code Mapping&apos;, () =&amp;gt; {
		it(&apos;should return correct descriptions for all weather codes&apos;, () =&amp;gt; {
			expect(getWeatherDescription(0)).toBe(&apos;Clear sky&apos;)
			expect(getWeatherDescription(3)).toBe(&apos;Overcast&apos;)
			expect(getWeatherDescription(95)).toBe(&apos;Thunderstorm&apos;)
		})
		it(&apos;should handle invalid weather codes gracefully&apos;, () =&amp;gt; {
			expect(getWeatherDescription(999)).toBe(&apos;Unknown weather condition&apos;)
		})
	})
})
```
### Integration Testing
The AI assistants helped me build integration tests that actually start the development server and test the full application flow:
```typescript
// src/test/frontend.test.ts
describe(&apos;Frontend Integration&apos;, () =&amp;gt; {
	const baseUrl = &apos;http://localhost:3001&apos;
	it(&apos;should load the main page successfully&apos;, async () =&amp;gt; {
		const response = await fetch(baseUrl)
		expect(response.status).toBe(200)
		const html = await response.text()
		expect(html).toContain(&apos;Weather&apos;)
		expect(html).toContain(&apos;App&apos;)
	})
	it(&apos;should display weather data when coordinates are provided&apos;, async () =&amp;gt; {
		const response = await fetch(`${baseUrl}?lat=51.5074&amp;amp;lon=-0.1278`)
		const html = await response.text()
		expect(html).toContain(&apos;London&apos;)
		expect(html).toContain(&apos;°C&apos;)
		expect(html).toContain(&apos;Next 3 Days&apos;)
	})
})
```
The final test suite included **40 passing tests** covering:
- **11 utility tests** - Temperature conversion, weather mapping, data validation
- **14 API tests** - Endpoint responses, error handling, data transformation
- **15 frontend tests** - Component rendering, user interactions, responsive design
## Chapter 5: The Developer Experience Revolution
### Tooling Setup with AI Guidance
One of the most time-consuming aspects of modern development is setting up proper tooling. Here&apos;s where the AI collaboration truly excelled. Instead of spending hours configuring ESLint, Stylelint, Prettier, and Git hooks, the AI assistants helped me create a production-ready setup in minutes.
**ESLint Configuration:**
```javascript
// eslint.config.js - AI-optimized configuration
export default [
	...typescriptEslint.configs.strict,
	...astro.configs.recommended,
	{
		plugins: {
			&apos;simple-import-sort&apos;: simpleImportSort,
		},
		rules: {
			&apos;simple-import-sort/imports&apos;: &apos;error&apos;,
			&apos;simple-import-sort/exports&apos;: &apos;error&apos;,
			&apos;@typescript-eslint/no-unused-vars&apos;: [
				&apos;error&apos;,
				{
					argsIgnorePattern: &apos;^_&apos;,
					varsIgnorePattern: &apos;^_&apos;,
				},
			],
		},
	},
]
```
**Stylelint for Tailwind CSS:**
```json
{
	&quot;extends&quot;: [&quot;stylelint-config-standard&quot;],
	&quot;rules&quot;: {
		&quot;at-rule-no-unknown&quot;: [
			true,
			{
				&quot;ignoreAtRules&quot;: [
					&quot;tailwind&quot;,
					&quot;apply&quot;,
					&quot;variants&quot;,
					&quot;responsive&quot;,
					&quot;screen&quot;,
					&quot;layer&quot;
				]
			}
		],
		&quot;no-descending-specificity&quot;: null,
		&quot;selector-class-pattern&quot;: null,
		&quot;custom-property-pattern&quot;: null
	},
	&quot;ignoreFiles&quot;: [
		&quot;dist/**/*&quot;,
		&quot;.vercel/**/*&quot;,
		&quot;.astro/**/*&quot;,
		&quot;node_modules/**/*&quot;
	]
}
```
**Pre-commit Hooks with Husky and Lint-staged:**
```json
{
	&quot;lint-staged&quot;: {
		&quot;*.{js,ts,astro,jsx,tsx}&quot;: [&quot;eslint --fix&quot;],
		&quot;*.css&quot;: [&quot;stylelint --fix&quot;],
		&quot;*.{js,ts,astro,jsx,tsx,css,json,md}&quot;: [&quot;prettier --write&quot;]
	}
}
```
This setup meant that every commit was automatically:
- Linted for code quality issues
- Formatted consistently
- Tested to ensure nothing was broken
- Validated for commit message format
### The Power of Automated Scripts
The AI assistants helped me create a comprehensive set of npm scripts that made development a breeze:
```json
{
	&quot;scripts&quot;: {
		&quot;dev&quot;: &quot;astro dev --port 3001 --open&quot;,
		&quot;build&quot;: &quot;astro build&quot;,
		&quot;lint:all&quot;: &quot;npm run lint &amp;amp;&amp;amp; npm run lint:css&quot;,
		&quot;test:all&quot;: &quot;npm run test:unit &amp;amp;&amp;amp; npm run test:integration&quot;,
		&quot;test:integration&quot;: &quot;start-server-and-test dev http://localhost:3001 \&quot;vitest run src/test/api.test.ts src/test/frontend.test.ts\&quot;&quot;,
		&quot;test:coverage&quot;: &quot;vitest --coverage src/test/utils.test.ts&quot;
	}
}
```
The `test:integration` script was particularly clever - it automatically starts the development server, waits for it to be ready, runs the integration tests, then shuts down the server. No manual server management required!
## Chapter 6: Advanced Features and Polish
### Smart Icon System
One of the features I&apos;m most proud of is the intelligent weather icon system. Instead of relying solely on SVG icons (which can fail to load), I implemented a dual-system approach:
```typescript
// Primary: SVG icons with Astro Icon component

// Fallback: Animated emoji system
function createWeatherIcon(iconName: string, isLarge: boolean = false): string {
  const sizeClass = isLarge ? &apos;text-8xl&apos; : &apos;text-4xl&apos;
  let emoji = &apos;☁️&apos;
  let animationClass = &apos;&apos;
  // Comprehensive mapping with intelligent pattern matching
  switch (iconName) {
    case &apos;meteocons:clear-day-fill&apos;:
      emoji = &apos;☀️&apos;
      animationClass = &apos;animate-bounce&apos;
      break
    case &apos;meteocons:thunderstorms-fill&apos;:
      emoji = &apos;⛈️&apos;
      animationClass = &apos;animate-thunder-pulse&apos;
      break
    // ... 18+ weather conditions covered
    default:
      // Smart fallback based on icon name patterns
      if (iconName.includes(&apos;clear&apos;) &amp;amp;&amp;amp; iconName.includes(&apos;day&apos;)) {
        emoji = &apos;☀️&apos;
        animationClass = &apos;animate-bounce&apos;
      } else if (iconName.includes(&apos;thunder&apos;) || iconName.includes(&apos;storm&apos;)) {
        emoji = &apos;⛈️&apos;
        animationClass = &apos;animate-thunder-pulse&apos;
      }
      // ... more intelligent pattern matching
  }
  return `&lt;span&gt;${emoji}&lt;/span&gt;`
}
```
This system ensures that users always see appropriate weather icons, even if the SVG icon set fails to load.
### Temperature Unit Persistence
A small but important UX detail was remembering the user&apos;s temperature unit preference:
```javascript
// Temperature toggle with localStorage persistence
window.switchToUnit = function (unit) {
	localStorage.setItem(&apos;temperatureUnit&apos;, unit)
	// Update toggle state
	const toggleCheckbox = document.getElementById(&apos;temp-toggle-checkbox&apos;)
	if (toggleCheckbox) {
		toggleCheckbox.checked = unit === &apos;fahrenheit&apos;
	}
	// Convert all displayed temperatures
	document.querySelectorAll(&apos;[data-temp-c]&apos;).forEach(element =&amp;gt; {
		const celsius = parseFloat(element.dataset.tempC)
		const converted =
			unit === &apos;fahrenheit&apos; ? Math.round((celsius * 9) / 5 + 32) : celsius
		const suffix = unit === &apos;fahrenheit&apos; ? &apos;°F&apos; : &apos;°C&apos;
		element.textContent = `${converted}${suffix}`
	})
}
// Restore user preference on page load
const savedUnit = localStorage.getItem(&apos;temperatureUnit&apos;) || &apos;celsius&apos;
window.switchToUnit(savedUnit)
```
### Responsive Design Excellence
The application needed to work perfectly on all devices. Tailwind CSS made this straightforward, but the AI assistants helped me think through the user experience:
```astro

&lt;div&gt;
	
	&lt;div&gt;
		&lt;div&gt;
			
		&lt;/div&gt;
		&lt;div&gt;
			
		&lt;/div&gt;
	&lt;/div&gt;
	
	&lt;div&gt;
		
	&lt;/div&gt;
&lt;/div&gt;
```
## Chapter 7: Deployment and Production
### Vercel Integration
Deploying to Vercel was remarkably smooth thanks to Astro&apos;s built-in adapter:
```javascript
// astro.config.mjs
export default defineConfig({
	vite: {
		plugins: [tailwindcss()],
	},
	integrations: [icon()],
	adapter: vercel(),
})
```
That&apos;s it! The application automatically builds and deploys with:
- Server-side rendering for initial page loads
- Static generation for optimal performance
- Serverless API routes for weather data
- Edge caching for global performance
### Performance Optimization
The final application achieved excellent performance metrics:
&lt;div&gt;
	&lt;div&gt;
		&lt;div&gt;1.2s&lt;/div&gt;
		&lt;div&gt;
			First Contentful Paint
		&lt;/div&gt;
		&lt;div&gt;✓ Under 1.2s target&lt;/div&gt;
	&lt;/div&gt;
	&lt;div&gt;
		&lt;div&gt;2.1s&lt;/div&gt;
		&lt;div&gt;
			Largest Contentful Paint
		&lt;/div&gt;
		&lt;div&gt;✓ Under 2.5s target&lt;/div&gt;
	&lt;/div&gt;
	&lt;div&gt;
		&lt;div&gt;0.08&lt;/div&gt;
		&lt;div&gt;
			Cumulative Layout Shift
		&lt;/div&gt;
		&lt;div&gt;✓ Under 0.1 target&lt;/div&gt;
	&lt;/div&gt;
	&lt;div&gt;
		&lt;div&gt;2.8s&lt;/div&gt;
		&lt;div&gt;
			Time to Interactive
		&lt;/div&gt;
		&lt;div&gt;✓ Under 3.0s target&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
	&lt;div&gt;🏆&lt;/div&gt;
	&lt;div&gt;
		&lt;h4&gt;
			Performance Achievement
		&lt;/h4&gt;
		&lt;p&gt;
			All Core Web Vitals passed Google&apos;s &quot;Good&quot; thresholds, resulting in better
			search rankings and user experience scores.
		&lt;/p&gt;
	&lt;/div&gt;
&lt;/div&gt;
These scores were achieved through:
- **Astro&apos;s islands architecture** - Minimal JavaScript footprint
- **Efficient CSS with Tailwind&apos;s purging** - Only unused styles removed
- **Optimized weather API calls** - Smart caching and request batching
- **Proper image optimization** - WebP format with fallbacks
- **Strategic use of SSR vs static generation** - Best of both worlds
## Chapter 8: Lessons Learned
### AI as a Development Partner
Working with AI assistants fundamentally changed how I approach development:
&lt;div&gt;
	&lt;div&gt;
		&lt;h4&gt;✅ What AI Excels At&lt;/h4&gt;
		&lt;ul&gt;
			&lt;li&gt;
				&lt;span&gt;•&lt;/span&gt;
				&lt;strong&gt;Pattern Recognition&lt;/strong&gt; - Spotting repetitive code and
				suggesting abstractions
			&lt;/li&gt;
			&lt;li&gt;
				&lt;span&gt;•&lt;/span&gt;
				&lt;strong&gt;Boilerplate Generation&lt;/strong&gt; - Creating comprehensive
				configurations and test setups
			&lt;/li&gt;
			&lt;li&gt;
				&lt;span&gt;•&lt;/span&gt;
				&lt;strong&gt;Error Debugging&lt;/strong&gt; - Systematically working through
				complex issues
			&lt;/li&gt;
			&lt;li&gt;
				&lt;span&gt;•&lt;/span&gt;
				&lt;strong&gt;Code Consistency&lt;/strong&gt; - Maintaining style and patterns
				across the codebase
			&lt;/li&gt;
			&lt;li&gt;
				&lt;span&gt;•&lt;/span&gt;
				&lt;strong&gt;Documentation&lt;/strong&gt; - Generating thorough comments and README
				content
			&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
    &lt;div&gt;
    	&lt;h4&gt;⚠️ What AI Struggles With&lt;/h4&gt;
    	&lt;ul&gt;
    		&lt;li&gt;
    			&lt;span&gt;•&lt;/span&gt;
    			&lt;strong&gt;Creative Problem Solving&lt;/strong&gt; - Novel solutions to unique
    			problems
    		&lt;/li&gt;
    		&lt;li&gt;
    			&lt;span&gt;•&lt;/span&gt;
    			&lt;strong&gt;Business Logic Decisions&lt;/strong&gt; - Understanding user needs and
    			requirements
    		&lt;/li&gt;
    		&lt;li&gt;
    			&lt;span&gt;•&lt;/span&gt;
    			&lt;strong&gt;Performance Trade-offs&lt;/strong&gt; - Making architectural decisions
    			based on constraints
    		&lt;/li&gt;
    		&lt;li&gt;
    			&lt;span&gt;•&lt;/span&gt;
    			&lt;strong&gt;User Experience&lt;/strong&gt; - Understanding subtle UX implications
    		&lt;/li&gt;
    	&lt;/ul&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
	&lt;div&gt;🎯&lt;/div&gt;
	&lt;div&gt;
		&lt;h4&gt;
			The Sweet Spot
		&lt;/h4&gt;
		&lt;p&gt;
			The most productive development happened when I provided the creative
			direction and architectural decisions, while the AI assistants handled
			implementation details, testing strategies, and tooling configuration.
		&lt;/p&gt;
	&lt;/div&gt;
&lt;/div&gt;
### Technical Insights
&lt;div&gt;
	&lt;div&gt;
		&lt;div&gt;📝&lt;/div&gt;
		&lt;h4&gt;TypeScript is Essential&lt;/h4&gt;
		&lt;p&gt;
			Even for a relatively simple application, TypeScript caught numerous
			potential runtime errors and made refactoring much safer.
		&lt;/p&gt;
	&lt;/div&gt;
    &lt;div&gt;
    	&lt;div&gt;🧪&lt;/div&gt;
    	&lt;h4&gt;Testing Pays Off&lt;/h4&gt;
    	&lt;p&gt;
    		The comprehensive test suite caught several bugs during development and
    		gave me confidence to refactor aggressively.
    	&lt;/p&gt;
    &lt;/div&gt;
    &lt;div&gt;
    	&lt;div&gt;🔧&lt;/div&gt;
    	&lt;h4&gt;Tooling Investment&lt;/h4&gt;
    	&lt;p&gt;
    		Spending time upfront on proper ESLint, Stylelint, and pre-commit hooks
    		paid dividends throughout development.
    	&lt;/p&gt;
    &lt;/div&gt;
    &lt;div&gt;
    	&lt;div&gt;⚡&lt;/div&gt;
    	&lt;h4&gt;Performance by Default&lt;/h4&gt;
    	&lt;p&gt;
    		Astro&apos;s architecture meant the application was fast without additional
    		optimization effort.
    	&lt;/p&gt;
    &lt;/div&gt;
    &lt;div&gt;
    	&lt;div&gt;🚀&lt;/div&gt;
    	&lt;h4&gt;Progressive Enhancement&lt;/h4&gt;
    	&lt;p&gt;
    		Building the core functionality to work without JavaScript, then enhancing
    		with interactivity, created a more robust application.
    	&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;
## The Final Product
The completed weather application showcases modern web development best practices:
### 🌟 **Features**
- **Global Weather Data** - Any location worldwide via Open-Meteo API
- **Responsive Design** - Seamless experience across all devices
- **Smart Weather Icons** - 18+ animated weather conditions with intelligent fallbacks
- **3-Day Forecasts** - Current conditions plus detailed forecasts
- **Unit Conversion** - Celsius/Fahrenheit toggle with preference persistence
- **Location Search** - City search with geolocation support
- **Performance Optimized** - Fast loading with excellent Core Web Vitals
- **Accessibility Ready** - Proper ARIA labels, keyboard navigation, screen reader support
### 🧪 **Quality Assurance**
- **40 Comprehensive Tests** - Unit, integration, and API testing
- **100% TypeScript** - Full type safety throughout the application
- **Automated Code Quality** - ESLint, Stylelint, Prettier with pre-commit hooks
- **Production Deployment** - Live on Vercel with serverless functions
### 🚀 **Performance Metrics**
- **Lighthouse Score**: 95+ across all categories
- **Bundle Size**: &amp;lt; 50KB gzipped
- **First Load**: &amp;lt; 1.2s on 3G
- **SEO Optimized**: Proper meta tags, structured data, semantic HTML
## Reflections on AI-Assisted Development
This project proved that AI isn&apos;t replacing developers - it&apos;s making us more effective. The combination of human creativity and AI efficiency created something neither could have built alone.
**The Future of Development:**
- AI handles boilerplate, configuration, and testing setup
- Developers focus on architecture, user experience, and business logic
- Code quality improves through AI-assisted best practices
- Development velocity increases without sacrificing quality
**Key Takeaways:**
1. **AI is a Force Multiplier** - It amplifies good development practices but won&apos;t fix poor ones
2. **Human Judgment Remains Critical** - AI suggestions need evaluation and refinement
3. **Iteration is Key** - The best results come from multiple AI-assisted refinement cycles
4. **Testing Becomes Essential** - AI can generate comprehensive tests that catch issues early
5. **Documentation Quality Improves** - AI helps maintain thorough, up-to-date documentation
## What&apos;s Next?
The weather app serves as a foundation for exploring more advanced concepts:
- **Real-time Updates** - WebSocket connections for live weather changes
- **Offline Support** - Service workers and cached data
- **Advanced Visualizations** - Weather maps and interactive charts
- **Machine Learning** - Personalized weather insights
- **Mobile App** - React Native or Flutter implementation
But more importantly, this project demonstrated a new way of building software - one where AI assistants handle the mechanical aspects of development while humans focus on the creative and strategic elements.
The future of web development isn&apos;t about humans vs. AI - it&apos;s about humans **with** AI, building better software faster than either could alone.
---
_Want to explore the code? Check out the [live demo](https://weather-app-pink-phi-60.vercel.app/) or browse the [source code on GitHub](https://github.com/nicolas-deyros/weather-app). The complete test suite, tooling configuration, and deployment setup are all available for reference._
**Final Stats:**
- **Lines of Code**: ~2,000
- **Development Time**: 3 days
- **Tests Written**: 40
- **AI Interactions**: 200+
- **Coffee Consumed**: ☕☕☕
_This project was built with the assistance of GitHub Copilot and Jules (Google AI). All code, architecture decisions, and final implementation were human-reviewed and approved._</content:encoded><category>Web Development</category><author>Nicolás Deyros</author></item><item><title>Vibe coding has made me more productive</title><link>https://www.nicolasdeyros.dev/blog/vibe-coding-productivity/</link><guid isPermaLink="true">https://www.nicolasdeyros.dev/blog/vibe-coding-productivity/</guid><description>A personal journey on how vibe coding and AI tools have dramatically increased development productivity over the past two years.</description><pubDate>Fri, 18 Jul 2025 00:00:00 GMT</pubDate><content:encoded>
## Introduction
I know the image and video will generate clickbait, and that is the idea. Numerous articles, videos, podcasts, and books discuss the benefits and risks of vibe coding. This is not another article intended to discuss that. This is a **personal article** based on my experience with Vibe Coding and how it has increased my productivity over the past two years.
## Context: My AI Journey
First, let&apos;s give some context. Since the AI era began, I have been utilizing various AI tools to enhance my productivity and discover solutions that would have been difficult to find using traditional methods, such as Google. Learning and working as a **pair programmer** is another plus for me.
My career has been a journey of continuous evolution. I come from the advertising world but found my place in development. I worked in the internet industry before YouTube, Facebook, and many other companies. I consider myself a **pioneer user**.
### The Evolution I&apos;ve Witnessed
The evolution that I&apos;ve experienced in my 20+ years of career is incredible. I recall when we had to:
- 💾 Send all our banners and files to the media on a **CD or USB drive**
- 🔧 Update files directly on production using **FTP**
- 🎬 Add animations only with **GIF files**
- ⚡ When **Flash was the king** of the world
What humanity has achieved with AI is incredible, and this is only the tip of the iceberg. I won&apos;t deny that AI is overwhelming. Trying to stay up to date with everything is impossible. However, I have felt this way in the past, when a new JS framework was released every week, claiming to solve problems existing in React or promising a breakthrough or some magical trick.
&amp;gt; Do not forget that everything JS Nation is offering has already been resolved in PHP, Ruby, or many other languages.
## The Productivity Breakthrough
For the past few years, I have been struggling to find time for research and development. I love coding and creating stuff. I enjoy the challenge of solving a puzzle and finding new ways to approach tasks. I consider myself a **problem solver**.
Since I started using **Copilot in Visual Studio Code**, I have seen an increase in my productivity. I have also begun playing and investigating the use of **Google AI Studio**. Over the past month, I have developed more applications than I have in the past two years combined.
## Google AI Studio Journey
### 🎮 Pokémon Battle Arena
I started my journey creating a Pokémon card game, **Pokémon Battle Arena**—a simple and silly game, but with an incredible UI for the cards.

**[🚀 Play Pokémon Battle Arena](https://pok-mon-card-battle-arena-1071820676408.us-west1.run.app/)**
&amp;gt; I&apos;ve always believed that the right tools don&apos;t just make you faster—they fundamentally change how you create. While building this interactive Pokémon Battle Arena, I experienced that firsthand by integrating the Gemini API into my development workflow. What would have been a multi-week project, bogged down by complex game logic, API data modeling, and intricate UI styling, was completed in a fraction of the time.
The AI served as my tireless pair programmer, helping me:
- 🏗️ Scaffold complex React hooks
- ✨ Design holographic card effects
- 🧠 Generate deterministic logic for the computer opponent
This wasn&apos;t about offloading work; it was about elevating my focus from the mundane to the truly creative.
_Note: The card design was taken from Codepen, following the example created by [Simon 🦝 G.](https://codepen.io/simeydotme/pen/PrQKgo)_
### 🐉 Dragon Ball Universe Explorer
The second application I built, concurrently with the Pokémon Battle Arena, is a Dragon Ball Universe version utilizing the Dragon Ball API.

**[🚀 Play Dragon Ball Universe](https://dragon-ball-universe-explorer-135079448490.us-west1.run.app/)**
&amp;gt; As a lifelong Dragon Ball fan, I always dreamed of creating an immersive digital encyclopedia for its iconic characters. What would typically have been a months-long solo project, the &apos;Dragon Ball Universe Explorer,&apos; was brought to life in a fraction of the time, and the secret weapon was AI.
Leveraging Google&apos;s Gemini API was a paradigm shift in productivity:
- 🏛️ Architecting component structure
- 🔄 Generating complex sorting logic
- 🎨 Refining UI/UX for dynamic feel
### 🤖 AI Conversation Log
My latest creation, inspired by other things I&apos;ve heard, and I was eager to try, is the **AI Conversation app**.

**[🚀 Try AI Conversation Log](https://ai-conversation-log-252745535225.us-west1.run.app/)**
&amp;gt; Building the &quot;AI Conversation Log&quot; was a powerful lesson in what&apos;s possible when human creativity is amplified by artificial intelligence. By leveraging the Gemini API as a development partner, what would have been a complex, multi-week project was brought to life in a fraction of the time.
The AI seamlessly handled:
- 🎭 Generating diverse character personas
- 💬 Drafting complex conversational logic
- 🌍 Providing real-time translation capabilities
### 📋 Neon Kanban Board
These are the three applications that I have published; however, I have developed many more. For example, a **Kanban Board with a neon look and feel**.

&amp;gt; The Neon Kanban To-Do App! It&apos;s a vibrant, Jira-inspired task manager with seamless drag-and-drop functionality, designed to make productivity visually engaging. What&apos;s truly revolutionary about this project, however, is how it was built.
By leveraging the power of Gemini as a coding partner, I was able to:
- ⚡ Accelerate development significantly
- 🔧 Generate boilerplate code automatically
- 🎯 Implement complex drag-and-drop UI logic
- 🎨 Focus on architectural design and user experience
## Portfolio Renaissance
This inspired me to retake a long-abandoned project: **my portfolio**. Although it is still a work in progress, with the help of AI, I have made significant progress over the last couple of weeks.
### Copilot as a Coding Partner
I generally program alone. I do not work on my project with other developers. This is a challenge because my learning curve depends entirely on me. In my daily role as a developer manager, my work is reflected in the work of my team.
For my portfolio, which is still under development, I&apos;m using **Astro**. I have found in Astro a great tool that allows me to do all I want. If I need to add additional functionality, I can incorporate React, Vue, or another framework to make it more complete.
## The Future of Creative Development

I have a long road to travel in this continuous learning process. When I get accustomed to something new, something new will come up to amaze me.
### 🎬 AI-Generated Content
The video of this article was created using **Gemini Veo**. A simple prompt can now create beautiful animation. The possibilities are endless when we combine:
- 🤖 AI-powered development tools
- 🎨 Creative vision and experience
- 🚀 Rapid prototyping capabilities
## Key Takeaways
My journey with vibe coding has taught me that AI tools like GitHub Copilot and Google AI Studio are not just productivity enhancers—they&apos;re **creativity amplifiers**. They allow us to:
- ⚡ **Build faster** without sacrificing quality
- 🎯 **Focus on creativity** instead of boilerplate
- 🧠 **Learn continuously** through AI pair programming
- 🚀 **Prototype rapidly** and iterate quickly

## Join the Conversation
Share with me your thoughts, opinions, or journey about AI. How has AI transformed your development workflow?
---
_Originally published on [Nicolas Deyros&apos; LinkedIn](https://www.linkedin.com/pulse/vibe-coding-has-made-me-more-productive-nicolas-deyros-x8rff/)_</content:encoded><category>Development</category><author>Nicolás Deyros</author></item><item><title>AI Debate Arena Using Google AI Studio</title><link>https://www.nicolasdeyros.dev/blog/ai-debate-arena-google-ai-studio/</link><guid isPermaLink="true">https://www.nicolasdeyros.dev/blog/ai-debate-arena-google-ai-studio/</guid><description>Experience vibrant AI debates with dynamic personas powered by Google AI Studio and Gemini API.</description><pubDate>Tue, 15 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;
Have you ever imagined witnessing a lively debate between a &lt;strong&gt;Sarcastic Wit&lt;/strong&gt; and a &lt;strong&gt;Shakespearean Poet&lt;/strong&gt; discussing the future of technology? Now you can embark on this journey as I introduce the innovative &lt;strong&gt;AI Conversation Log&lt;/strong&gt;, developed with Google AI Studio.
This web application, powered by the Gemini API, reshapes our interaction with artificial intelligence, allowing you to orchestrate vibrant, real-time debates between two dynamic AI personas.


&lt;/p&gt;
&lt;h2&gt;What Makes This Project Special&lt;/h2&gt;
&lt;p&gt;This project is a testament to the endless possibilities of creating an engaging and interactive experience. Here’s what makes it truly remarkable:&lt;/p&gt;
&lt;h3&gt;🎭 Choose Your Fighters&lt;/h3&gt;
&lt;p&gt;Say goodbye to mundane prompts. In the AI Conversation Log, you can select and personalize vivid personalities for your AI participants. Dive into a rich tapestry of personas, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Pragmatist&lt;/strong&gt; vs. &lt;strong&gt;The Philosopher&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Enthusiast&lt;/strong&gt; vs. &lt;strong&gt;The Cynical Critic&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Wise Mentor&lt;/strong&gt; vs. &lt;strong&gt;The Curious Child&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Data Analyst&lt;/strong&gt; vs. &lt;strong&gt;The Storyteller&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;And many more!
Each persona embodies unique behaviors and traits that transform the conversation into something truly memorable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;🧠 Strategic Token Limits&lt;/h3&gt;
&lt;p&gt;This application introduces a fascinating challenge to interaction. Each debate is bound by a &lt;strong&gt;limited token budget&lt;/strong&gt;, compelling the AIs to articulate their arguments concisely and with purpose. This urgency amplifies creativity and encourages impactful exchanges.&lt;/p&gt;
&lt;h3&gt;📊 Intelligent Conversation Summary&lt;/h3&gt;
&lt;p&gt;When the conversation concludes, whether by your direction or reaching the token limit, the application generates a &lt;strong&gt;concise, neutral summary&lt;/strong&gt; using advanced AI algorithms. This summary captures the essence of the dialogue, ensuring that the key arguments and tone are preserved for deeper reflection.&lt;/p&gt;
&lt;h3&gt;🔊 Integrated Web-Native APIs&lt;/h3&gt;
&lt;p&gt;The app enhances the debate experience through seamless integration of Google’s advanced AI and web-native technologies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gemini API&lt;/strong&gt; for real-time dialogue generation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web Speech API&lt;/strong&gt; for distinct, customizable voices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-language support&lt;/strong&gt; expanding your experience and understanding
Each debate comes alive with unique voices, making the experience truly immersive.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;More Than Entertainment&lt;/h2&gt;
&lt;p&gt;This tool is more than entertainment; it is a &lt;strong&gt;powerful gateway&lt;/strong&gt; to explore complex topics from diverse perspectives. It can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✨ Inspire creative brainstorming sessions&lt;/li&gt;
&lt;li&gt;🤝 Foster meaningful discussions&lt;/li&gt;
&lt;li&gt;📚 Serve as an engaging educational model for growth&lt;/li&gt;
&lt;li&gt;🎯 Help explore different viewpoints on complex topics&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Technical Innovation&lt;/h2&gt;
&lt;p&gt;Creating this project with Google AI Studio has been an inspiring journey, showcasing the potential for sophisticated AI interactions that blend intellect with excitement. The application demonstrates how modern AI can create:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dynamic personality simulation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contextual conversation flow&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-time response generation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Intelligent content summarization&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Experience It Yourself&lt;/h2&gt;
&lt;h2&gt;Ready to witness AI debates that will challenge your perspective and entertain your mind?
&lt;strong&gt;&lt;a href=&quot;https://ai-conversation-log-252745535225.us-west1.run.app/&quot;&gt;🚀 Try the AI Debate Arena&lt;/a&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a href=&quot;https://www.linkedin.com/pulse/ai-debate-arena-using-google-studio-nicolas-deyros-zzaff/&quot;&gt;Nicolas Deyros’ LinkedIn&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content:encoded><category>Artificial Intelligence</category><author>Nicolás Deyros</author></item><item><title>Relative Mobile Conversion Rate Dashboard</title><link>https://www.nicolasdeyros.dev/blog/relative-mobile-conversion-rate-dashboard/</link><guid isPermaLink="true">https://www.nicolasdeyros.dev/blog/relative-mobile-conversion-rate-dashboard/</guid><description>A comprehensive guide to building a Relative Mobile Conversion Rate dashboard in Google Data Studio, based on Lina Hansson&apos;s speed optimization concepts.</description><pubDate>Mon, 16 Mar 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;
In a really interesting post &lt;a href=&quot;https://web.dev/value-of-speed/&quot;&gt;The value of speed&lt;/a&gt;, written by Lina Hansson, she develops the concept of &lt;strong&gt;Relative Mobile Conversion Rate (Rel mCvR)&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Since you’re interested in how site speed affects conversions, the mobile site is most relevant—that’s where you’re most likely to see the benefits of speed improvements. Rather than looking at the mobile conversion rate alone, though, you’ll be analyzing the relative mobile conversion rate (Rel mCvr), which is calculated by dividing the mobile conversion rate by the desktop conversion rate. This approach reduces the noise from external factors, which tend to affect both desktop and mobile, and makes it easier to see whether any increases in the mobile site’s effectiveness were actually caused by the speed improvements.

I’m not going to cover all the posts written by Lina because she does a great job. Her post is a must-read. I’m just going to present my approach for developing her dashboard in Google Data Studio.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Relative Mobile Conversion Rate Data Studio Dashboard&lt;/h2&gt;
&lt;p&gt;
Below you’ll find a step by step procedure for reproducing Rel mCvr report in
Google Data Studio. In order to create this dashboard you need to take into
consideration the following steps:&lt;/p&gt;
&lt;h3&gt;1. Data Source&lt;/h3&gt;
&lt;p&gt;You should use the &lt;strong&gt;blended data&lt;/strong&gt; of the same data source.

The join keys you should select are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Date&lt;/li&gt;
&lt;li&gt;Week of year and Week of the year&lt;/li&gt;
&lt;li&gt;Month of year and Month of the year
After that you should proceed and select the following metrics:&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Speed Metrics Sample&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ecommerce Conversion Rate&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sessions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avg. Page Load Time (sec)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Revenue&lt;/strong&gt;
As you can see, you should rename the metrics adding “Mobile” or “Desktop” for differentiation purposes.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. Filters&lt;/h3&gt;
&lt;p&gt;You should apply filters to each data source before you blend them.

You should create two filters, one for mobile and the other for desktop. To perform this task, just include the information from the metric “Device Category” equal to mobile or desktop.

&lt;strong&gt;Filter Configuration:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mobile Filter: &lt;code&gt;Device Category = mobile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Desktop Filter: &lt;code&gt;Device Category = desktop&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. Relative Mobile Conversion Rate Formula&lt;/h3&gt;
&lt;p&gt;The process, for calculating the formula of the Rel mCvR, is that you should create a custom field. The formula is the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SUM(NARY_MAX(Mobile Ecommerce Conversion Rate,0))/SUM(NARY_MAX(Desktop Ecommerce Conversion Rate,0))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The process for creating a custom calculated field involves:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Adding the formula above&lt;/li&gt;
&lt;li&gt;Defining the type as a &lt;strong&gt;percent&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Naming the field “Relative Mobile Conversion Rate”
The image below shows you the process for creating a custom calculated field, adding the formula and the define the type as a percent.
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Video Tutorial&lt;/h3&gt;

## Implementation Steps
Here&apos;s a quick checklist for implementation:
- [ ] Set up blended data source in Google Data Studio
- [ ] Configure join keys (Date, Week, Month)
- [ ] Apply device category filters
- [ ] Rename metrics with Mobile/Desktop prefixes
- [ ] Create custom calculated field for Rel mCvR
- [ ] Set field type to percentage
- [ ] Build dashboard visualizations
## Final Thoughts
As mentioned at the beginning of this article, Lina&apos;s post is a must-read in order to get a deep understanding of the Relative Mobile Conversion Rate (Rel mCvR).
This dashboard approach allows you to:
- **Isolate mobile performance** from external factors
- **Track speed optimization impact** on conversions
- **Make data-driven decisions** about mobile improvements
- **Benchmark mobile against desktop** performance
Don&apos;t hesitate to contact me if you have any doubts or if you need help implementing this dashboard.
---
_Originally published on [Nicolas Deyros&apos; LinkedIn](https://www.linkedin.com/pulse/relative-mobile-conversion-rate-dashboard-nicolas-deyros/)_</content:encoded><category>Analytics</category><author>Nicolás Deyros</author></item><item><title>Programmatic Advertising for Digital Project Manager</title><link>https://www.nicolasdeyros.dev/blog/programmatic-advertising-guide/</link><guid isPermaLink="true">https://www.nicolasdeyros.dev/blog/programmatic-advertising-guide/</guid><description>A comprehensive guide for Digital Project Managers on setting up programmatic advertising campaigns, including roles, responsibilities, and best practices.</description><pubDate>Thu, 31 May 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Programmatic advertising is the best solution for delivering creative content/advertising to consumers according to their phase in the consumer journey. Programmatic gives brands the power of creating specific creativity adapted to the consumer necessity, voice, etc.&lt;/p&gt;
&lt;h2&gt;Objective&lt;/h2&gt;
&lt;p&gt;This article is written as a guide for Digital Project Manager. It provides an overview of what needs to be done in order to setup a programmatic advertising campaign.&lt;/p&gt;
&lt;h2&gt;Scope&lt;/h2&gt;
&lt;p&gt;The Digital Project Manager is responsible for the scope definition, coordination and execution. In order to do so, he needs to understand the roles and responsibilities of all the FTEs involved.&lt;/p&gt;
&lt;h2&gt;Roles &amp;amp; Responsibilities&lt;/h2&gt;
&lt;h3&gt;Trafficker&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;DoubleClick Manager (DCM) setup&lt;/li&gt;
&lt;li&gt;Placement tag creation&lt;/li&gt;
&lt;li&gt;DoubleClick Studio profile creation&lt;/li&gt;
&lt;li&gt;DoubleClick Manager (DCM) floodlights setup&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Bid Manager&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;DoubleClick Bid Manager (DBM) setup&lt;/li&gt;
&lt;li&gt;Suggest media investment and advertising buying deal types (Open Auction, Private Auctions, Preferred Deals, Guaranteed Deals &amp;amp; Traditional Tag Based)&lt;/li&gt;
&lt;li&gt;Suggest and implement media optimizations&lt;/li&gt;
&lt;li&gt;Connects DBM with the DMP&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Business Intelligence&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Defines control metrics cross platform&lt;/li&gt;
&lt;li&gt;Defines Google Analytics funnel goals&lt;/li&gt;
&lt;li&gt;Report campaign &amp;amp; site (landing page) performance&lt;/li&gt;
&lt;li&gt;Define media &amp;amp; site A/B test&lt;/li&gt;
&lt;li&gt;Setup Google DataStudio&lt;/li&gt;
&lt;li&gt;Defines naming convention&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Designer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Adapt creativity to Google Web Designer&lt;/li&gt;
&lt;li&gt;Creates media feed&lt;/li&gt;
&lt;li&gt;Connect Google Web Designer with DoubleClick Studio profile&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Media Planner&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Defines media mix&lt;/li&gt;
&lt;li&gt;Media planning&lt;/li&gt;
&lt;li&gt;Defines reach and frequency&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Strategic Planner&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Define strategy&lt;/li&gt;
&lt;li&gt;Define feed rules&lt;/li&gt;
&lt;li&gt;Define consumer journey’s&lt;/li&gt;
&lt;li&gt;Define campaign audience&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Project Manager&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Define scope of work&lt;/li&gt;
&lt;li&gt;Estimate timeline&lt;/li&gt;
&lt;li&gt;Project control and follow up&lt;/li&gt;
&lt;li&gt;Defines deliverables&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Audience Manager&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Create campaign audiences&lt;/li&gt;
&lt;li&gt;Manage Data Management Platform (DMP)&lt;/li&gt;
&lt;li&gt;Defines floodlights&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Creative&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Campaign concept creation&lt;/li&gt;
&lt;li&gt;Creative development&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Developer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Google Tag Manager implementation&lt;/li&gt;
&lt;li&gt;Implement tracking tags&lt;/li&gt;
&lt;li&gt;DoubleClick Manager (DCM) floodlights implementation&lt;/li&gt;
&lt;li&gt;Site performance analysis&lt;/li&gt;
&lt;li&gt;Integrates client CRM&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Quality Assurance (QA)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Creativity QA&lt;/li&gt;
&lt;li&gt;Media Tags QA&lt;/li&gt;
&lt;li&gt;Platforms Tags QA&lt;/li&gt;
&lt;li&gt;Programmatic feed QA&lt;/li&gt;
&lt;li&gt;Media performance QA&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Project Plan&lt;/h2&gt;
&lt;p&gt;Below’s graphic presents a macro overview of time, priority and effort required:&lt;/p&gt;
&lt;div&gt;
  &lt;div&gt;
    &lt;h3&gt;Programmatic Advertising Project Workflow&lt;/h3&gt;
    {/* Phase 1: Planning */}
    &lt;div&gt;
      &lt;div&gt;
        &lt;h4&gt;1. Planning&lt;/h4&gt;
        &lt;div&gt;
          &lt;div&gt;Strategic Planner&lt;/div&gt;
          &lt;div&gt;Media Planner&lt;/div&gt;
          &lt;div&gt;Audience Manager&lt;/div&gt;
          &lt;div&gt;Business Intelligence&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    {/* Phase 2: Creative &amp;amp; Development */}
    &lt;div&gt;
      {/* Phase 2.1: Creative */}
      &lt;div&gt;
        &lt;h4&gt;2.1. Creative&lt;/h4&gt;
        &lt;div&gt;
          &lt;div&gt;Creative&lt;/div&gt;
          &lt;div&gt;Designer&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      {/* Phase 2.2: Development */}
      &lt;div&gt;
        &lt;h4&gt;2.2. Development&lt;/h4&gt;
        &lt;div&gt;
          &lt;div&gt;Trafficker&lt;/div&gt;
          &lt;div&gt;Developer&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    {/* Phase 3: Implementation */}
    &lt;div&gt;
      &lt;div&gt;
        &lt;h4&gt;3. Implementation&lt;/h4&gt;
        &lt;div&gt;
          &lt;div&gt;Bid Manager&lt;/div&gt;
          &lt;div&gt;Trafficker&lt;/div&gt;
          &lt;div&gt;Media Planner&lt;/div&gt;
          &lt;div&gt;Audience Manager&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    {/* Phase 4: Optimization */}
    &lt;div&gt;
      &lt;div&gt;
        &lt;h4&gt;4. Optimization&lt;/h4&gt;
        &lt;div&gt;
          &lt;div&gt;Bid Manager&lt;/div&gt;
          &lt;div&gt;Media Planner&lt;/div&gt;
          &lt;div&gt;Business Intelligence&lt;/div&gt;
          &lt;div&gt;Audience Manager&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    {/* Quality Assurance &amp;amp; Project Manager - Always Present */}
    &lt;div&gt;
      &lt;div&gt;
        &lt;h4&gt;Quality Assurance&lt;/h4&gt;
        &lt;p&gt;Continuous oversight across all phases&lt;/p&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;h4&gt;Project Manager&lt;/h4&gt;
        &lt;p&gt;Coordination and execution management&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    {/* Timeline Indicator */}
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;&lt;/div&gt;
        &lt;div&gt;&lt;/div&gt;
        &lt;div&gt;&lt;/div&gt;
        &lt;div&gt;&lt;/div&gt;
        &lt;div&gt;&lt;/div&gt;
        &lt;div&gt;&lt;/div&gt;
        &lt;div&gt;&lt;/div&gt;
        &lt;div&gt;&lt;/div&gt;
      &lt;/div&gt;
      &lt;p&gt;Sequential workflow with parallel creative and development phases&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
## Tools
- DoubleClick Campaign Manager (DCM)
- DoubleClick Bid Manager (DBM)
- DoubleClick Rich Media
- DoubleClick Studio
- DoubleClick for Publishers (DFP)
- DoubleClick Ad Exchange (AdX)
- Google Analytics
- Google Data Studio
- Google Tag Manager
- Google Optimize
- Google Attribution
- Google Audience
- Google Web Designer
## Best Practices
1. **Define all scenarios** to test from the beginning in order to create DoubleClick Studio rules, programmatic feed structure and creativity design
2. **Control all platform metrics** in order to see gaps, delivery bounce rate, A/B test results
3. **Control default creative metrics** - Default creativity should print/consume less than 1% of the budget
4. **Manage default creatives** - Default creative is implemented on the feed and DCM, which means you have 2 defaults to control
5. **Create different insertion orders** (DBM) according to the audience strategy, geo localization and test
6. **Consider mobile devices** - Do not forget mobile device sizes when thinking of a creative
## Sources
- [The buyer&apos;s guide to Programmatic Direct](https://www.thinkwithgoogle.com/intl/en-154/insights-inspiration/industry-perspectives/buyers-guide-to-programmatic-direct/)
- [Google Studio](https://www.google.com/doubleclick/studio/homepage/)
- [Google DoubleClick Tools](https://www.thinkwithgoogle.com/intl/en-154/products/doubleclick/)
---
_Originally published on [Nicolas Deyros&apos; LinkedIn](https://www.linkedin.com/pulse/programmatic-advertising-digital-project-manager-nicolas-deyros/)_</content:encoded><category>Digital Marketing</category><author>Nicolás Deyros</author></item></channel></rss>