/now
Right now: client work, writing, and the ongoing project of making this website match how we actually work. The two are more related than they sound – it's hard to pitch attention to detail as a service when your own site has been silently telling Google not to index it for two months. More on that below.
I'm Tanya. I run DNSK WORK, a small design studio in London. We work with startups and product teams on UX, interface design, and the kind of web presence that's supposed to do actual work rather than just exist. This page is where I keep track of what's happening with the studio itself – the version of the story that doesn't fit in a case study.
June 2026 – A language for the work
Spent a day building the thing every studio claims to have and mostly doesn't: a design system. It lives at /guidelines now – the palette (one grey, restraint as a feature rather than a budget), the type scale, the buttons we keep redeclaring in every block instead of writing once, and the part I hadn't planned to lose an afternoon to: the signs.
The brand mark is one fixed shape. Using it identically across six services felt lazy, so I built a small system to generate siblings from the same construction – square-framed, hairline, one grey weight, never filled – and assigned one to each service by meaning rather than by whichever looked nice that minute. UX Design gets a compass, because UX is wayfinding. SaaS Product Design gets rings spinning outward, because that's what scaling actually feels like. There is a real internal logic to all of it, which I will defend at length to anyone who makes the mistake of asking.
Generating a hundred-odd candidate marks is easy. Generating a hundred-odd that all read as the same family is the actual work, and naming them so they come out as "Triple Compass" rather than "gen 47" took longer than writing the generator did. I also built a section showing every component on the site, looked at it, decided it was clutter, and deleted it the same afternoon. Some features exist just long enough to confirm they shouldn't.
The signs went live across the services and their sub-pages, applied through a database migration rather than by hand – partly for safety, partly because assigning twenty-eight marks manually is how you give the wrong service the wrong one and don't notice for a week. The /guidelines page is public now, linked from the footer. It's the source of truth, which mostly means it's the page I'll be faintly embarrassed by in six months, when the system has moved on and the documentation hasn't.
June 2026 – The last 5%
The site is mostly where it should be, which means I've moved from fixing obvious things to fixing things that bother only me. Tag archive pages were running 91 database queries per page load; now they run 2. No visitor would have noticed the difference. That's not really the point.
Extended the audit. The footer was firing a separate database query for each service page link – six queries to build a navigation list that should take one. Every blog post page was also lazy-loading related post tags in a loop. Fixed both with proper eager loading. Added Model::preventLazyLoading() to the test suite so all 564 tests now catch N+1 queries automatically. The next one will fail CI before it reaches production.
Cloudflare’s bot protection script was loading on every page, including the ones with no contact form on them. Moved it to render only when the contact block is present. Also removed the Google Fonts import – it was loading Inter on every page view, and Inter appeared nowhere in the actual CSS. Two DNS lookups and a render-blocking request, for a font nobody was using. This one required a moment of quiet reflection.
Added fetchpriority=high to the first case study image on /work, and removed the fade-in transition from it. The LCP element fading up from zero opacity is technically correct and exactly the kind of thing PageSpeed Insights flags as a problem. It was flagging it as a problem.
Published a guide on the web design process – the first thing I've written here that I'd actually send to a prospective client without sheepishly adding "this was more of a rough draft" in the email. It's titled A Guide to the Web Design Process for People Whose Last Designer Was an AI Agent, which I stand by even if it makes the URL quite long. Writing for a real audience feels different from writing for the blog. Still calibrating the tone.
Added this page. Updated the legal pages to look like they belong to the site rather than something copy-pasted from a compliance generator in 2009. Nobody reads terms and conditions, but they do form an impression – and "I don't care about this page" is the wrong one for a design studio to give.
Late May 2026 – Infrastructure and consequences
The git log for this period reads like a changelog for a site that had been accumulating debt while we were busy doing actual work. Some of it was embarrassing. All of it is now fixed.
The slug incident. A CMS update in May rewrote 43 blog post URLs without asking. Google had the originals indexed. We didn't have analytics. We didn't have analytics because we hadn't turned them on. Enabling analytics and discovering the slug problem happened in the same sitting, which at least kept it efficient. All 43 slugs restored, locked permanently, 301 redirects in place.
Fonts. Moved Satoshi, Switzer, and Playfair Display off external CDNs and onto our own server. Faster loads, no third-party requests on every page view. This should have happened at launch. It didn't, because at launch we had other problems.
Performance. The hero image was arriving 400ms after everything else – technically correct, practically frustrating for Google's crawlers. Fixed the load order, which broke the animation, which we fixed, which revealed the opacity wasn't the delay, the delay was. Three commits. Several opinions.
Analytics. Set up GA4 via Google Tag Manager. Then set it up directly as well, because the first one wasn't visible in the commit history. Ran with two tracking scripts for approximately one deploy before noticing. Both the setup and the discovery are very on-brand for this phase of the project.
SEO audit. First Ahrefs crawl returned 67 broken links pointing at the old WordPress site. Also surfaced that /blog/page/10 was serving a blank 200 – Google had indexed it. Bots had apparently worked through pagination all the way to page 47 looking for content. We now return proper 404s. The 404 page also no longer looks like an error.
ROBOTS_NOINDEX. We had a flag in the codebase that told search engines not to index the site. It had been there since March – a sensible precaution during development that nobody removed when the site went live. We removed it in late May. The site had been live and invisible for roughly two months. These things happen, and then you fix them, and then you don't mention it in client pitches.
Security. Added proper HTTP security headers, input length limits, subresource integrity hashes on third-party scripts. None of this is interesting to read about. It was overdue.
May 2026 – The big redesign push
The month started with a designer handing over final layouts and ended with the site looking like a real product. In between: porting CSS from static HTML files into Blade templates, a complete blog redesign with proper BEM structure, a new expertise block to replace a component that had been doing the job without doing it well, and the case study pages finally getting a layout that matched the work inside them. The breadcrumbs now use the DNSK icon as a separator instead of a slash. This is the kind of detail that takes thirty minutes and stays forever.
The blog index got rebuilt properly – filters by post type, a sensible pagination design, the footer showing recent posts. The blog had existed since March in a fairly rudimentary form. May was when it started feeling like something you'd want to browse rather than just land on.
Somewhere in the middle of all this, we briefly built a /zine-preview page and removed it the same day. Some experiments are private. It might come back.
Also moved the Blog navigation link from hardcoded HTML into the CMS, which is a small thing that took two hours of debugging. The site runs on Laravel Octane, which boots the application once and keeps it warm across requests – great for performance, occasionally surprising when something that should be fresh isn't. The navigation was disappearing after the first request because of how singletons behave in that environment. The fix is three lines. The investigation was not three lines.
April 2026 – Getting the basics right
April was contact forms, character encoding bugs, and a significant design pivot. The encoding issue – Polish and Ukrainian characters arriving as corrupted garbage – took four commits to resolve. The problem was at the PostgreSQL connection level. The solution was one line of configuration. The four commits were the journey to that line, which included a brief detour through a fix that worked on local and broke on production, which is a journey everyone has taken and nobody enjoys.
The design changed to black and white in a single commit on April 20. The message was "new black&white design" – five words, complete pivot. It was the right call. The previous version had been trying to be too many things. The cleaner direction felt more honest about what the studio actually does: precise, considered, not particularly interested in decoration for its own sake.
The contact form got built properly this month: dynamic service options pulled from the CMS, required GDPR consent, budget range selector, spam protection via Cloudflare Turnstile. The commit history for this one week contains seven updates to the routes file and four to the form template. That's what building something properly in public looks like – a lot of small corrections in the right direction. Security fixes landed too: session hardening, a Laravel CVE patch, a dependency vulnerability from a library that processes SSH keys (we don't use SSH keys, but you patch what needs patching).
March 2026 – Init
March 3: first commit. The message was "init", which is honest if not illuminating. The second and third commits were both titled "removing junk". We were getting organised.
The previous site ran on WordPress. It had accumulated plugins, outdated templates, a theme that was impossible to edit without breaking something else, and a general sense that it had been built in several different eras by several different people with several different opinions. The decision to rebuild it from scratch was easy. The decision to build it on Laravel with a headless CMS was slightly more ambitious than it needed to be, and also absolutely the right call – the flexibility has paid for itself many times over.
The first few weeks were foundations: PostgreSQL, Twill CMS, blog post types (posts, guides, interviews, news), JSON-LD schema markup for every page type, RSS feed, contact form with email notifications, sitemap, 404 and 500 pages, admin rate limiting, image compression with Glide. The things you build so you can build everything else. Not glamorous. Completely necessary.
By the end of March the site had case studies, a services block, client logos with SVG support, testimonials, FAQ with open/closed states, and a working blog. Most of the content was placeholder. Most of the design was temporary. That's fine – the important thing is that the structure was right. What's slightly unusual is that we kept most of the database schema from those first weeks essentially intact. It was well thought through for something sketched out at 11pm.