https://yellowraincoat.co.uk/blog/feed/atom Yellow Raincoat's Blog Feed for Yellow Raincoat's blog 2026-04-04T10:47:29+00:00 Feedamic: the Atom and RSS Feed generator for Statamic Caching Static Pages in a Laravel Application https://yellowraincoat.co.uk/blog/caching-static-pages-in-a-laravel-application 2026-04-03T23:00:00+00:00 2026-04-04T10:46:42+00:00 <p><img src="https://yellowraincoat.co.uk/img/containers/assets/blog/2026/04/04/caching-static-pages-in-a-laravel-application.webp/4da554339a8bb66ab47677eae6375224/caching-static-pages-in-a-laravel-application.webp" width="0" height="0" alt="Caching Static Pages in a Laravel Application"></p> <p>How to manage landing pages and other static content in Laravel, from a dedicated middleware group to cache rules in Cloudflare's free plan.</p> <p>If your Laravel application has one or more public-facing pages that never change between requests – e.g. a landing page, or a teaser like <a href="https://pixelwatcher.io/">PixelWatcher</a> at the moment – there is no reason for them to reach your server on every visit. Serving those pages from a CDN edge cache instead is a small change with a meaningful impact on both performance and cost.</p> <p>This post covers the full setup: from a dedicated middleware group in Laravel to the Cloudflare cache rules that wire it all together.</p> <h2>The problem</h2> <p>Out of the box, Laravel adds session and cookie handling to every response. Even for a page that doesn't use a session, the framework will set headers like <code>Set-Cookie</code> and <code>Cache-Control: no-cache, private</code>. CDNs typically treat these as signals not to cache the response, so every request hits your server.</p> <p>The fix is to handle static and dynamic pages separately.</p> <h2>Static routes</h2> <p>First, create a dedicated route file for static pages (e.g. <code>routes/static.php</code>):</p> <pre><code class="language-php">&lt;?php use Illuminate\Support\Facades\Route; Route::get('/', fn () =&gt; view('welcome'))-&gt;name('home'); </code></pre> <p>Here, it contains a single route, pointing to the default &quot;welcome&quot; page.</p> <h2>Middleware</h2> <p>Then, create a dedicated middleware:</p> <pre><code class="language-php">&lt;?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; final class SetStaticCacheHeaders { public function handle(Request $request, Closure $next): Response { $response = $next($request); $response-&gt;headers-&gt;set( 'Cache-Control', 'public, max-age=0, s-maxage=3600, stale-while-revalidate=60', ); $response-&gt;headers-&gt;remove('Set-Cookie'); return $response; } } </code></pre> <p>This produces the following <code>Cache-Control</code> header:</p> <pre><code class="language-shell">Cache-Control: public, max-age=0, s-maxage=3600, stale-while-revalidate=60 </code></pre> <p><code>max-age=0</code> tells browsers not to serve a stale copy without revalidating — so users always get a fresh response.</p> <p><code>s-maxage=3600</code> tells shared caches (like Cloudflare's edge) to cache the response for one hour.</p> <p><code>stale-while-revalidate=60</code> allows the CDN to serve a stale response while it fetches a fresh one in the background, keeping latency low.</p> <p>The middleware also ensures that no <code>Set-Cookie</code> header is present, so that the response won't contain a cookie that would otherwise prevent caching.</p> <h2>Route declaration and middleware group</h2> <p>Finally, declare our route file in <code>bootstrap/app.php</code>, as well as a custom <code>static</code> middleware group:</p> <pre><code class="language-php">return Application::configure(basePath: dirname(__DIR__)) -&gt;withRouting( web: __DIR__.'/../routes/web.php', commands: __DIR__.'/../routes/console.php', health: '/up', then: function (): void { Route::middleware('static')-&gt;group(base_path('routes/static.php')); }, ) -&gt;withMiddleware(function (Middleware $middleware): void { $middleware-&gt;group('static', [SetStaticCacheHeaders::class]); }) </code></pre> <p>The <code>static</code> middleware group only has the <code>SetStaticCacheHeaders</code>, deliberately omitting all session and cookie middlewares (as opposed to the <code>web</code> middleware group, which is applied to all routes in <code>web.php</code> by default).</p> <h2>Cloudflare cache rules</h2> <p>On its own, the middleware isn't enough – Cloudflare needs to be told when to cache and when to bypass, which is handled through Cloudflare’s Cache Rules.</p> <p>Here, the order matters: the <em>bypass</em> rules must come before the caching rule.</p> <p class="info"><span class="title">Note </span>The below is covered by Cloudflare’s free plan.</p> <h3>Rule 1: Bypass stateful routes</h3> <p>Some routes must never be cached, like anything involving authentication, Livewire AJAX calls, or internal framework endpoints.</p> <p>Here is an example filter expression:</p> <pre><code class="language-shell">(starts_with(http.request.uri.path, &quot;/dashboard&quot;) or starts_with(http.request.uri.path, &quot;/login&quot;) or starts_with(http.request.uri.path, &quot;/auth&quot;) or starts_with(http.request.uri.path, &quot;/livewire&quot;) or http.request.uri.path eq &quot;/up&quot;) </code></pre> <p>For this rule, select <em>Bypass cache</em> under <em>Cache eligibility</em>:</p> <p><img src="/assets/blog/2026/04/04/rule-expression.webp" alt="Rule expression screenshot" /></p> <h3>Rule 2: Bypass when session cookies are present</h3> <p>Once a user is logged in, their requests carry <code>laravel_session</code> and <code>XSRF-TOKEN</code> cookies. You don't want to serve them a cached page that was built for an anonymous visitor.</p> <p>Expression:</p> <pre><code class="language-shell">(http.cookie contains &quot;laravel_session&quot; or http.cookie contains &quot;XSRF-TOKEN&quot;) </code></pre> <p>Also select <em>Bypass cache</em> for this rule.</p> <h3>Rule 3: Cache the static page</h3> <p>Finally, the actual caching rule, targeting the home page:</p> <pre><code class="language-shell">http.request.uri.path eq &quot;/&quot; </code></pre> <p>For this one, select <em>Eligible for cache</em>, a custom 1-hour TTL for <em>Edge TTL</em>, and <em>Respect origin TTL</em> under <em>Browser TTL</em>:</p> <p><img src="/assets/blog/2026/04/04/rule-settings.webp" alt="Rule settings screenshot" /></p> <h2>Verifying it works</h2> <p>Load your page and inspect the response headers. On the first request you should see:</p> <pre><code class="language-shell">CF-Cache-Status: MISS Cache-Control: public, max-age=0, s-maxage=3600, stale-while-revalidate=60 </code></pre> <p>On subsequent requests:</p> <pre><code class="language-shell">CF-Cache-Status: HIT </code></pre> <p>No <code>Set-Cookie</code> header should appear.</p> <p>For dynamic pages, the opposite should be true – <code>CF-Cache-Status: DYNAMIC</code> and <code>Cache-Control: no-cache, private</code>, confirming that Cloudflare is bypassing the cache entirely.</p> <h2>Resources</h2> <ul> <li>Laravel’s <a href="https://laravel.com/docs/13.x/routing">Routing documentation</a></li> <li>Laravel’s <a href="https://laravel.com/docs/13.x/middleware">Middleware documentation</a></li> <li>Cloudflare <a href="https://developers.cloudflare.com/cache/how-to/cache-rules/">Cache Rules documentation</a></li> </ul> Yellow Raincoat news@yellowraincoat.co.uk Why I’m Building PixelWatcher https://yellowraincoat.co.uk/blog/why-im-building-pixelwatcher 2026-03-06T00:00:00+00:00 2026-03-06T13:38:52+00:00 <p><img src="https://yellowraincoat.co.uk/img/containers/assets/blog/2026/03/06/why-im-building-pixelwatcher.webp/4376403388cbb308d03aa9f73ac56392/why-im-building-pixelwatcher.webp" width="0" height="0" alt="Why I’m Building PixelWatcher"></p> <p>In many ways, it is a strange time to be building a SaaS. This article addresses some common concerns and further explains my approach with PixelWatcher.</p> <p>In many ways, it is a strange time to be building a SaaS. Between the doomsayers warning of an impending <a href="https://techcrunch.com/2026/03/01/saas-in-saas-out-heres-whats-driving-the-saaspocalypse/">SaaSpocalypse</a> and social media teeming with people launching startups on their lunch breaks, aspiring entrepreneurs could easily feel dispirited – and confused.</p> <p>Yet here I am, working on <a href="https://pixelwatcher.io/">PixelWatcher</a>. So why now? Let me try and address some common concerns below, and further explain my approach.</p> <p class="info"><span class="title">What is PixelWatcher?</span>PixelWatcher is a website monitoring service. Give it a URL, describe the change you want to know about, and PixelWatcher notifies you when it happens. Register for early access <a href="https://pixelwatcher.io" >here</a>. As a beta user, you’ll get a free account with generous limits.</p> <h2>The SaaS Model is Dead</h2> <p>Companies are building their own CRMs. Individuals are vibe-coding project management tools. Crustacean-themed bots are ordering people’s shopping and answering their emails. Why would anyone pay for a SaaS when all digital needs can supposedly be fulfilled with the right prompt?</p> <p>One word: Convenience.</p> <p>Companies already have their own core business to run, and building internal solutions means <em>someone</em> has to maintain them, whether AI is part of the process or not. It’s a distraction.</p> <p>As for individuals, coming up with a setup that actually works still requires some technical know-how that only a few will bother acquiring. That part will get better, but it will take time. And my bet is that most people will still prefer using off-the-shelf products anyway – for the right price. I’ll come back to that.</p> <h2>Everyone is Launching a SaaS</h2> <p>Spend more than five minutes on X or LinkedIn and you will come across a product launch announcement or some aspirational post followed by the <code>#buildInPublic</code> hashtag, leaving you with the strong impression that everyone and their uncle are starting companies these days.</p> <p>But of course, they’re not. Well, at least not their uncle. While it’s true that building software is easier than ever, and that more and more people are doing it, there is also a lot of daylight between toying with an idea and launching a full-fledged product. Very few will actually get there, and building is only a small part of the story.</p> <h2>Distribution is the Final Boss</h2> <p>This is going to be the real challenge for me when it comes to PixelWatcher. I’ve got the technical background, but marketing is still a mystery to me. I’m currently trying to get more people to <a href="https://pixelwatcher.io/">sign up for early access</a>, and this is already proving tricky.</p> <p>While I’m convinced that people who are serious about building products still represent a tiny fraction of the population, the SaaS landscape is a competitive one nonetheless – and when it comes to distribution, incumbents have a significant advantage.</p> <p>Which brings me to the next point.</p> <h2>Many Companies Already do this</h2> <p>Website monitoring is a crowded space. Well-established players are already dominating the market. So why am I <a href="/blog/another-hat-in-the-ring/">throwing my hat in that particular ring</a>? Precisely because I tried the competition.</p> <p>PixelWatcher is an idea born out of frustration. A few months ago, I found myself needing to monitor changes on a website that did not offer any kind of newsletter. I created an account on one of those monitoring services and was able to use their free plan for a while – until I needed to monitor another page. I quickly hit the free-checks limit, so I had a look at their paid plans, only to realise that their cheapest offer started at $10 per month. And they’re far from being the most expensive option out there.</p> <p>I was already feeling <a href="https://www.digitalroute.com/resources/glossary/subscription-fatigue/">subscription fatigue</a> like many others, and was absolutely not ready to spend that much every month for just a few more checks.</p> <p>This got me thinking – how much would I actually pay for this? I came up with a number, and looked into whether it would be workable. PixelWatcher’s seed was planted.</p> <p>I was also frustrated with the UX of most of these websites, and thought I could come up with a much simpler interface – one without all the bells and whistles. Just the essential features, for the right price.</p> <p>Because in the end, that’s what it’s all about.</p> <h2>It’s all About Price</h2> <p>To be clear, I don’t believe in the SaaSpocalypse, for the reasons mentioned above (technical know-how, maintenance burden, convenience). But I do believe that many SaaS companies currently apply margins that are increasingly hard to justify, and that AI tools have opened a boulevard for leaner, cheaper competition to emerge.</p> <p>In other words, while many SaaS products compete on features, I suspect the next wave will compete on efficiency.</p> <p>This is PixelWatcher’s bet – that the website monitoring landscape is ripe for disruption, and that there is room for a service with a far more appealing <em>price-to-convenience</em> ratio.</p> <h2>In Closing</h2> <p>Let’s not ignore the <a href="https://www.citriniresearch.com/p/2028gic?hide_intro_popup=true">potential wider implications</a> of this paradigm shift. I honestly don’t know where this AI-powered Fourth Industrial Revolution ends. But for my part, I’m choosing to see it as an opportunity.</p> <p>As already mentioned in <a href="/blog/another-hat-in-the-ring/">Another Hat in the Ring</a>, if we’re about to enter an extended period of creative destruction on an unprecedented scale, I’d much rather be on the creative side.</p> Yellow Raincoat news@yellowraincoat.co.uk Animate your Logo with Remotion and Claude Code https://yellowraincoat.co.uk/blog/animate-your-logo-with-remotion-and-claude-code 2026-02-17T00:00:00+00:00 2026-02-19T10:36:06+00:00 <p><img src="https://yellowraincoat.co.uk/img/containers/assets/blog/2026/02/17/remotion-claude.avif/89181fdaf1d7b47fdf4ade5387515f9c/remotion-claude.avif" width="0" height="0" alt="Animate your Logo with Remotion and Claude Code"></p> <p>Want to animate your logo without learning motion design? This short tutorial shows how to create a production-ready animation using Remotion and Claude Code.</p> <p class="info">Note: This article assumes that you already have a Claude Code subscription. If you don’t, or if you’re not familiar with Claude Code yet, I recommend completing the first module of <a href="https://ccforeveryone.com/">this free course</a> before continuing.</p> <p>I am a backend developer by trade. I know nothing about motion design. Yet it only took me a couple of hours to animate PixelWatcher’s logo:</p> <video controls> <source src="/assets/blog/2026/02/17/logowithtagline.mp4" type="video/mp4"> </video> <h2>Remotion</h2> <p><a href="https://www.remotion.dev/">Remotion</a> is a tool for creating videos with React. I don’t know the first thing about React, but that’s OK because Remotion <a href="https://x.com/Remotion/status/2013626968386765291">recently released some agent skills</a>, meaning we can now prompt Claude in natural language to create animations.</p> <p>The other good news? Anything you create with Remotion is <a href="https://www.remotion.pro/license">free for commercial use for individuals and companies of up to three people</a>.</p> <p>To get started with Remotion and Claude Code, follow <a href="https://www.remotion.dev/docs/ai/claude-code">these steps</a> and come back here when Claude is running in your project’s folder.</p> <h2>Animate your logo</h2> <p>Now the fun part. Get a picture of your logo (preferably an SVG for scalable graphics, but other image formats work too). Place it in the <code>public/</code> folder of your project so it is registered as an asset.</p> <p>Now use the following prompt to create a composition from your logo:</p> <blockquote> <p>This is a Remotion project, so use the Remotion best practices skill. Start a new composition from @public/logo.svg, using the same dimensions as the image</p> </blockquote> <p>Claude will create the composition. Once it’s done, specify which parts of the image you’d like to animate.</p> <p>This is the prompt I used for PixelWatcher’s logo:</p> <blockquote> <p>Let's separate the various components of the animation. The isolated black square hanging from the bottom of the larger, rounded square is one. The rest of that rounded square and its contents are another. Then there's the &quot;ixelWatcher&quot; text, which is another component. And finally, the &quot;Never miss a change.&quot; tagline is the last component</p> </blockquote> <p>Claude will proceed to create separate components for each of those, naming them in the process. Feel free to change the names for something more descriptive – the trick is that you can now refer to each component by name to animate them separately.</p> <p>Here are some example prompts I used:</p> <blockquote> <p>The animation will start with MainLogo and HangingSquare zoomed in at the centre of the composition. The other components aren't displayed.</p> </blockquote> <blockquote> <p>Let's animate the HangingSquare. It starts as if it were part of MainLogo's outer black outline, and eases down into it final position</p> </blockquote> <p>You get the idea.</p> <p>Once you’re happy with the animation, click the “Render” button to export it as a video.</p> <h2>Tips</h2> <p>Sometimes, the exported video doesn’t match the preview exactly. If that happens, explain the issue to Claude and re-render until you’re satisfied with the result.</p> <p>Don’t hesitate to ask Claude to polish up the animation:</p> <blockquote> <p>Can you now make the animation smoother</p> </blockquote> <p>Or to clean up after itself:</p> <blockquote> <p>Can you now simplify and optimise the code, making sure the animation stays the same</p> </blockquote> <p>You can also ask Claude about the effects it’s been using, or spot them in the code directly: learning and remembering the names of those effects can make for better prompting in the future.</p> <hr /> <p>PixelWatcher is currently under development. If you’d like updates ahead of launch and get early access, subscribe to the newsletter at <a href="http://pixelwatcher.io">pixelwatcher.io</a>.</p> Yellow Raincoat news@yellowraincoat.co.uk Another Hat in the Ring https://yellowraincoat.co.uk/blog/another-hat-in-the-ring 2026-01-13T00:00:00+00:00 2026-01-13T16:54:27+00:00 <p><img src="https://yellowraincoat.co.uk/img/containers/assets/blog/2026/01/13/another-hat-in-the-ring.webp/7210b6bc066ce048342ee51ab9d27ff5/another-hat-in-the-ring.webp" width="0" height="0" alt="Another Hat in the Ring"></p> <p>I’m building my own SaaS, joining a growing cohort of AI-powered developers choosing to go it alone. This is why, and what to expect.</p> <p>I’m building my own SaaS.</p> <p>I’m joining a growing cohort of AI-powered developers choosing to go it alone. Or at least try.</p> <p>This isn’t coming out of nowhere. The contracting market has been rough for the past three years. My LinkedIn inbox is eerily silent, when recruiters used to cold-contact me 2–3 times a week. This isn’t a brag – I have just never seen the market in such a terrible state for such a long time in my 20-year career.</p> <p>Maybe it’s the lingering effects of Brexit. Or the post-Covid hiring spree still correcting. Or the competition from cheaper labour overseas. Or the AI storm making companies question their headcount. Or maybe it’s the PHP language finally, actually losing steam. Whatever the reason, it’s time for a rethink.</p> <p>And now feels like a good time to give entrepreneurship – or “solopreneurship” – a try. Everyone seems to agree that recent model upgrades (Opus 4.5, Gemini 3, ChatGPT 5.2…) represent a new milestone in capability, so much so that unsupervised agentic work is now a <a href="https://world.hey.com/dhh/promoting-ai-agents-3ee04945">viable option</a>. That changes the economics of building software as a small team... or a team of one.</p> <p>Generative AI can make up for a lack of skills in many areas. A hardened backend developer like me should be able to conjure up half-decent frontend code without losing his mind. Heck, I even think I can come up with a respectable design, so long as the right <a href="https://code.claude.com/docs/en/skills">skills</a> are loaded.</p> <p>It’s too early to be specific about the product I’m intending to build. What I can say though is that it’s hardly an original idea. There are plenty of competitors doing more or less the same thing already, but I think I can do it simpler and cheaper. Instead of being disrupted, I’d rather do a bit of the disrupting myself.</p> <p>To be clear though, this is an experiment. How far can I go on my own? Design and frontend are one thing, but how about marketing? UX? Customer support? SEO? (If that’s even a thing in the age of LLMs.)</p> <p>There’s a lot of hype out there, and while I’m confident some of it is justified, I also want to see for myself. But there’s one thing I’m absolutely certain of: software development has changed forever. And there is no way in hell I’ll be late to the party.</p> <p>As <a href="https://steve-yegge.medium.com/the-death-of-the-stubborn-developer-b5e8f78d326b">others</a> have pointed out, developers resisting AI today look a lot like assembly programmers resisting high-level languages in the 80s – too slow, not “crafty” enough. History didn’t side with them.</p> <p>The problem is that no one will let you tear down and rebuild your workflow during office hours. Some companies might encourage a level of experimentation, but it will always be constrained by culture and deadlines. It’s no coincidence that the most interesting AI setups are coming from independent developers and founders.</p> <p>So I’m using this project as a playground. I’ll test tools, workflows, and ideas, and build an AI-powered setup that reflects this new era of software development. If the SaaS takes off, great. If not, the learning alone is worth it.</p> <p>And I’m planning to write about it, too. Good old written blog posts, right here. So make sure to subscribe to the newsletter below if that sounds good. No videos with silly faces. Promise.</p> Yellow Raincoat news@yellowraincoat.co.uk