<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Muhammad Ali Raza</title>
    <description>The latest articles on DEV Community by Muhammad Ali Raza (@ceo_quantumines).</description>
    <link>https://dev.to/ceo_quantumines</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4235163%2Fe716f54a-bb25-436e-b348-2205443ef45f.png</url>
      <title>DEV Community: Muhammad Ali Raza</title>
      <link>https://dev.to/ceo_quantumines</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ceo_quantumines"/>
    <language>en</language>
    <item>
      <title>How we cut our homepage from 4 MB to 179 KB and reached Lighthouse 100</title>
      <dc:creator>Muhammad Ali Raza</dc:creator>
      <pubDate>Fri, 13 Nov 2026 05:15:59 +0000</pubDate>
      <link>https://dev.to/ceo_quantumines/how-we-cut-our-homepage-from-4-mb-to-179-kb-and-reached-lighthouse-100-1aln</link>
      <guid>https://dev.to/ceo_quantumines/how-we-cut-our-homepage-from-4-mb-to-179-kb-and-reached-lighthouse-100-1aln</guid>
      <description>&lt;p&gt;Two PNG images made up almost all of quantumines.com's 4 MB homepage. Serving them as AVIF and WebP at the size each screen needs cut the page to 179 KB and the mobile Largest Contentful Paint (LCP) from about 17 seconds to 1.8 seconds. Self-hosted fonts with size-matched fallbacks, two colour fixes and an accessible-name fix took the remaining Lighthouse scores to 100. We made all of these changes on 10 November 2026 in one commit. This write-up lists each one, with the code, so another small team can repeat it in an afternoon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where did the 4 MB come from?
&lt;/h2&gt;

&lt;p&gt;The network list in Lighthouse and Chrome DevTools answered that quickly. The homepage loaded a 2.0 MB PNG for the hero sculpture and a 2.1 MB PNG for the product artwork, both exported straight from a design tool at full quality. Everything else on the page, HTML, CSS, JavaScript and icons, was small. A 1.6 MB logo PNG was also referenced from our structured data, though not displayed.&lt;/p&gt;

&lt;p&gt;On a phone over a throttled mobile connection, which is what Lighthouse simulates, two megabytes take many seconds to arrive. And because the hero is the largest thing on screen, it is the element LCP measures: until it finishes, the page counts as not loaded.&lt;/p&gt;

&lt;p&gt;quantumines.com homepage before and after (Lighthouse mobile, 10 November 2026)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Measure&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Total page weight&lt;/td&gt;
&lt;td&gt;about 4 MB&lt;/td&gt;
&lt;td&gt;179 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Largest Contentful Paint (mobile)&lt;/td&gt;
&lt;td&gt;about 17 s&lt;/td&gt;
&lt;td&gt;1.8 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accessibility score&lt;/td&gt;
&lt;td&gt;96&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All four Lighthouse categories&lt;/td&gt;
&lt;td&gt;not all 100&lt;/td&gt;
&lt;td&gt;100 / 100 / 100 / 100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cumulative Layout Shift&lt;/td&gt;
&lt;td&gt;not recorded&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 1: serve images as AVIF and WebP, at the right size
&lt;/h2&gt;

&lt;p&gt;We exported each large image three times (480, 768 and 1,024 pixels wide for the hero) in AVIF and in WebP, and let the browser pick with &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;, &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt;. The 1,024-pixel hero dropped from 2.0 MB as PNG to 44 KB as AVIF; a phone downloads the 480-pixel AVIF, which is 12.5 KB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"image/avif"&lt;/span&gt;
    &lt;span class="na"&gt;srcset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"assets/hero-480.avif 480w, assets/hero-768.avif 768w, assets/hero-1024.avif 1024w"&lt;/span&gt;
    &lt;span class="na"&gt;sizes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 760px) 100vw, 55vw"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"image/webp"&lt;/span&gt;
    &lt;span class="na"&gt;srcset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"assets/hero-480.webp 480w, assets/hero-768.webp 768w, assets/hero-1024.webp 1024w"&lt;/span&gt;
    &lt;span class="na"&gt;sizes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 760px) 100vw, 55vw"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hero-image"&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"assets/hero-1024.webp"&lt;/span&gt;
    &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Sculpture of mint metal, glass and textured stone"&lt;/span&gt;
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1024"&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1280"&lt;/span&gt; &lt;span class="na"&gt;fetchpriority&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"high"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three details matter. The &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes let the browser reserve the space before the image arrives, so nothing jumps. &lt;code&gt;fetchpriority="high"&lt;/code&gt; tells it to fetch the LCP image before other images. And the hero is never lazy-loaded: lazy loading the largest image on screen delays exactly the thing LCP measures. The product artwork, further down the page, got the same AVIF and WebP treatment at 768 and 1,536 pixels.&lt;/p&gt;

&lt;p&gt;The 1.6 MB logo in our Organization schema was replaced with a 512-pixel PNG of 137 KB. Search engines don't need more than that, and it no longer turns up in audits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: self-host the fonts and stop the text from jumping
&lt;/h2&gt;

&lt;p&gt;The site used Manrope and DM Sans from Google Fonts. That meant a render-blocking stylesheet request to another domain, then the font files from a third. We downloaded the variable versions of both (they are under the SIL Open Font License), serve them as WOFF2 from our own domain and preload them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"preload"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/fonts/manrope-var.woff2"&lt;/span&gt; &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"font"&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"font/woff2"&lt;/span&gt; &lt;span class="na"&gt;crossorigin&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"preload"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/fonts/dm-sans-var.woff2"&lt;/span&gt; &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"font"&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"font/woff2"&lt;/span&gt; &lt;span class="na"&gt;crossorigin&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;font-display: swap&lt;/code&gt;, text appears at once in a fallback font and switches when the web font arrives. The switch can move text, because Arial is wider or taller than the real font. So we defined fallback faces measured against Arial, with &lt;code&gt;size-adjust&lt;/code&gt; and the ascent and descent overrides, and listed them right after the real font:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@font-face&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Manrope Fallback'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Arial'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Liberation Sans'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Helvetica'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;size-adjust&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;94.9&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;ascent-override&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;112.4&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;descent-override&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;31.6&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-gap-override&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;--display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Manrope'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Manrope Fallback'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Together with the image dimensions, this is why Cumulative Layout Shift is 0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: fix the last accessibility points
&lt;/h2&gt;

&lt;p&gt;Accessibility was at 96. Lighthouse flagged two things. Some muted text in the light theme was below the 4.5:1 contrast ratio that WCAG requires for normal text, so we darkened those colours until each passed. And the mobile menu button's accessible name didn't match its visible label "Menu", which confuses people who use voice control: they say what they see. Making the name match the label fixed it. Both changes took minutes; finding them is what the audit is for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: cache by file type
&lt;/h2&gt;

&lt;p&gt;Our Node server sets &lt;code&gt;Cache-Control&lt;/code&gt; from the file extension. Fonts never change under the same name, so browsers may keep them for a year. Images can be kept for a week and refreshed in the background. HTML, CSS and JavaScript are checked again after an hour, so a deploy shows up quickly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'.woff2'&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'public, max-age=31536000, immutable'&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/^&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;\&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;avif&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;\&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;webp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;\&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;\&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jpe&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;\&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;svg&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;\&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ico&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;$&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'public, max-age=604800, stale-while-revalidate=86400'&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'public, max-age=3600'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: make the next page feel instant
&lt;/h2&gt;

&lt;p&gt;Two newer browser features cost a few lines each. Speculation Rules tell Chrome to prefetch a same-site page when the visitor hovers over its link, so the click usually lands on a page that is already downloaded. We exclude anything with side effects or private data, such as log-in, the app, admin pages and the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"speculationrules"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"prefetch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"document"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"where"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"and"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"href_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"/*"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"not"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"href_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/login"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"/app/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"/admin/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"/api/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"/logout"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"eagerness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"moderate"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cross-document view transitions add a short cross-fade between pages with one CSS rule, turned off for people who ask their system for reduced motion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@view-transition&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@view-transition&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browsers that don't support either feature ignore them, so there is no downside for anyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do we keep it at 100?
&lt;/h2&gt;

&lt;p&gt;Scores drift as pages are added. Every time the site is rebuilt, we run Lighthouse on the homepage, the newest post and one product page, and fix anything below 95 before it goes live. New images must be AVIF or WebP with width, height and &lt;code&gt;srcset&lt;/code&gt;. Each page's preview image for social media is generated at build time, so nobody uploads a multi-megabyte PNG by hand. The same discipline carried over to &lt;a href="https://quantumines.com/blog/how-we-added-webmcp-to-quantumines-com" rel="noopener noreferrer"&gt;adding WebMCP for AI agents&lt;/a&gt;: the site still scores 100 in all four categories with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would we tell another small team?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open the network list before touching code. On most small sites one or two images are most of the weight.&lt;/li&gt;
&lt;li&gt;Fix the LCP image first: modern format, right size, &lt;code&gt;fetchpriority="high"&lt;/code&gt;, never lazy.&lt;/li&gt;
&lt;li&gt;Give every image width and height, and give web fonts a size-matched fallback. That is most of CLS.&lt;/li&gt;
&lt;li&gt;Treat accessibility warnings as bugs. They are usually quick to fix and they affect real people.&lt;/li&gt;
&lt;li&gt;Re-run the audit on every build, not once a quarter.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is AVIF supported in all browsers?
&lt;/h3&gt;

&lt;p&gt;AVIF works in current versions of Chrome, Edge, Firefox and Safari. The &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element falls back to WebP and then to the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; source, so older browsers still get an image.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a good Largest Contentful Paint?
&lt;/h3&gt;

&lt;p&gt;Google's Core Web Vitals treat an LCP of 2.5 seconds or less as good, measured at the 75th percentile of real page loads. quantumines.com's homepage measures 1.8 seconds in Lighthouse's mobile test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does a Lighthouse score of 100 guarantee good Core Web Vitals?
&lt;/h3&gt;

&lt;p&gt;No. Lighthouse is a lab test on one simulated device. Core Web Vitals in Search Console come from real visitors' browsers. A high lab score makes good field data likely, but the field data is what Google uses.&lt;/p&gt;

&lt;p&gt;Quantumines is a technology and product studio in Lahore, Pakistan, founded by &lt;a href="https://quantumines.com/muhammad-ali-raza" rel="noopener noreferrer"&gt;Muhammad Ali Raza (Ali Arbi)&lt;/a&gt;. We build websites and web apps for clients with the same standards; see &lt;a href="https://quantumines.com/services" rel="noopener noreferrer"&gt;our services&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://quantumines.com/blog/how-quantumines-com-reached-lighthouse-100" rel="noopener noreferrer"&gt;quantumines.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>html</category>
      <category>css</category>
    </item>
    <item>
      <title>How to add WebMCP to a website: what we shipped on quantumines.com</title>
      <dc:creator>Muhammad Ali Raza</dc:creator>
      <pubDate>Thu, 12 Nov 2026 05:20:04 +0000</pubDate>
      <link>https://dev.to/ceo_quantumines/how-to-add-webmcp-to-a-website-what-we-shipped-on-quantuminescom-lbm</link>
      <guid>https://dev.to/ceo_quantumines/how-to-add-webmcp-to-a-website-what-we-shipped-on-quantuminescom-lbm</guid>
      <description>&lt;p&gt;&lt;strong&gt;To add WebMCP to a website, you register tools with the browser in JavaScript (the imperative API), or add a few attributes to an existing HTML form (the declarative API), and switch the feature on for real visitors with a Chrome origin-trial token.&lt;/strong&gt; On quantumines.com we did both on 10 November 2026: four read-only tools that answer questions about the studio and its products, and a contact form that an agent can fill in but only the visitor can send. The whole client-side part is one 76-line file. This write-up shows what we built, why each choice was made and what we would do differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is WebMCP, in one paragraph?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.chrome.com/docs/ai/webmcp" rel="noopener noreferrer"&gt;WebMCP&lt;/a&gt; is a proposed web standard from the Chrome team for exposing structured tools to AI agents that act inside a browser. Without it, an agent has to read the page, guess which button does what and simulate clicks and typing (Chrome's docs call this "actuation"). With it, the page says: here is a tool called &lt;code&gt;get_product&lt;/code&gt;, it takes a product name, and it returns these facts. Chrome offers it as an origin trial from Chrome 149, and as a flag (&lt;code&gt;chrome://flags/#enable-webmcp-testing&lt;/code&gt;) for local testing. It is still experimental and the API may change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why would a small studio site bother?
&lt;/h2&gt;

&lt;p&gt;Quantumines is a technology and product studio in Lahore. Our site exists so that people, search engines and AI assistants get our facts right: who runs the studio, what each product does, how to reach us. We already publish those facts for machines in &lt;a href="https://quantumines.com/facts.json" rel="noopener noreferrer"&gt;/facts.json&lt;/a&gt;, &lt;a href="https://quantumines.com/llms.txt" rel="noopener noreferrer"&gt;/llms.txt&lt;/a&gt; and a &lt;a href="https://quantumines.com/ai" rel="noopener noreferrer"&gt;guide for AI readers&lt;/a&gt;. WebMCP was a small extra step that lets an agent working for a visitor ask the page directly instead of scraping it. It took us a morning, adds no weight for visitors whose browsers don't support it, and fits the rule we follow everywhere: one set of verified facts, served in every format people and machines use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which tools did we register?
&lt;/h2&gt;

&lt;p&gt;Four, all read-only:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;What it returns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_studio_facts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;What the studio does, its founder and co-founder, services, contact email, official profiles and the date the facts were last checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_products&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;The best-known products with a one-sentence summary, website and profile page for each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_product&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;name&lt;/code&gt; (string)&lt;/td&gt;
&lt;td&gt;One product's details, or a list of valid names if the name doesn't match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search_quantumines&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;query&lt;/code&gt; (string)&lt;/td&gt;
&lt;td&gt;Up to eight matching guides, answers and pages, with links&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;The WebMCP tools on quantumines.com, 12 November 2026.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All four read from files the site already publishes. The three fact tools read &lt;code&gt;/facts.json&lt;/code&gt;; the search tool reads the link list in &lt;code&gt;/llms.txt&lt;/code&gt;. That means there is no second copy of the facts to keep in sync: when the build script regenerates those files, the tools change with them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does the code look like?
&lt;/h2&gt;

&lt;p&gt;The file starts with feature detection, so browsers without WebMCP skip it entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;mc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;mc&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="n"&gt;mc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;registerTool&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s1"&gt;'function'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each tool is a plain object with a name, a description written for a language model, a JSON Schema for its input, an annotation and an &lt;code&gt;execute&lt;/code&gt; function. Here is the one that looks up a product:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'get_product'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Get the details of one Quantumines product by name ...'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'object'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'string'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Product name, for example "CryptoMerchant".'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;annotations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;readOnlyHint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* find it in /facts.json */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three details mattered more than we expected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forgiving matching.&lt;/strong&gt; &lt;code&gt;get_product&lt;/code&gt; compares names with spaces, case and punctuation removed, so "Crypto Merchant", "cryptomerchant" and "CryptoMerchant" all work. When nothing matches, it returns the valid names rather than an error, which gives the agent a way forward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One fetch, shared.&lt;/strong&gt; The facts file is fetched once per page and the promise is reused by every tool, so an agent calling three tools in a row costs one request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean-up.&lt;/strong&gt; Tools are registered with an &lt;code&gt;AbortController&lt;/code&gt; signal, and the controller is aborted on &lt;code&gt;pagehide&lt;/code&gt;, so nothing is left registered once the page is gone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The script is loaded with &lt;code&gt;defer&lt;/code&gt;, so it never blocks rendering. After this and the image work done the same day, Lighthouse scored the homepage 100 in performance, accessibility, best practices and SEO, with a mobile largest-contentful-paint time of 1.8 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you let an agent use a form without letting it send things?
&lt;/h2&gt;

&lt;p&gt;The contact form on our homepage uses the declarative API: three kinds of attributes on ordinary HTML.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;toolname="contactQuantumines"&lt;/code&gt; and a &lt;code&gt;tooldescription&lt;/code&gt; on the form element say what the form is for and when to use it.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;toolparamdescription&lt;/code&gt; on each field says what goes in it ("Email address where Quantumines should reply").&lt;/li&gt;
&lt;li&gt;The hidden anti-spam field gets one too: "Anti-spam field. Always leave this empty." Without that line, an eager agent may fill every input it finds and trip the spam filter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The attribute we deliberately left out is &lt;code&gt;toolautosubmit&lt;/code&gt;. Without it, an agent can fill the form, but the visitor still reviews the message and presses Send. Sending a message to someone is an action with consequences, and we think the person should make that final click. The same thinking is behind marking the other four tools &lt;code&gt;readOnlyHint: true&lt;/code&gt;: none of them can change anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you turn it on for real visitors?
&lt;/h2&gt;

&lt;p&gt;During the trial, WebMCP only runs on sites that present a valid origin-trial token. We registered quantumines.com in the Chrome Origin Trials console and got a token valid until 29 March 2027. You can put a token in an &lt;code&gt;origin-trial&lt;/code&gt; meta tag, but we send it as an HTTP response header instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Origin-Trial'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;ORIGIN_TRIALS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our Node server sets it on every response, including the static pages, so no page can be missing it, and renewing it later is a one-line change in one file. The token is public by design; it only works for the origin it was issued to. We have a reminder to renew it from 1 March 2027.&lt;/p&gt;

&lt;h2&gt;
  
  
  How did we test it?
&lt;/h2&gt;

&lt;p&gt;On the live site, in Chrome 156 under the origin trial, we checked that all four tools appear, that each returns what &lt;code&gt;/facts.json&lt;/code&gt; says, that a wrong product name gets a helpful reply, and that the form tool fills the fields but does not send. Chrome's docs also point to two extensions that act as test agents (the Model Context Tool Inspector and an example agentic extension) and to DevTools support for checking how the browser reads your JSON Schemas.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would we tell another small team?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start read-only.&lt;/strong&gt; Tools that only read public facts carry almost no risk and still help agents get you right.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reuse what you publish.&lt;/strong&gt; If you have a facts file, a sitemap or an llms.txt, build the tools on top of it instead of writing new data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write descriptions for a model, not a marketer.&lt;/strong&gt; Say what the tool returns and when to use it. Name the inputs with examples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the human in the loop for anything that sends, buys or deletes.&lt;/strong&gt; Leave out auto-submit and use a confirmation step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat it as an experiment.&lt;/strong&gt; Chrome says the API is subject to change, so keep the code small and check Chrome's docs whenever you touch it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does WebMCP replace llms.txt or structured data?
&lt;/h3&gt;

&lt;p&gt;No. Search engines and AI crawlers read pages, schema and files such as llms.txt without running your JavaScript. WebMCP helps a different reader: an agent acting inside a browser tab for a person. We keep all three, fed from the same facts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which browsers support WebMCP?
&lt;/h3&gt;

&lt;p&gt;As of November 2026, Chrome offers it as an origin trial from version 149 and behind a testing flag. It is a proposed standard, so other browsers may follow. Pages should treat it as a progressive enhancement and work fully without it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can WebMCP tools run in iframes?
&lt;/h3&gt;

&lt;p&gt;Tool registration is controlled by the &lt;code&gt;tools&lt;/code&gt; permissions policy, which defaults to &lt;code&gt;self&lt;/code&gt;: it works in the top-level page and same-origin frames. A cross-origin iframe needs &lt;code&gt;allow="tools"&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is it safe to expose a form to agents?
&lt;/h3&gt;

&lt;p&gt;It is as safe as the form itself, provided you keep the final submit with the person. Validate on the server as you would for any visitor, and don't add auto-submit to forms that send messages, place orders or change accounts.&lt;/p&gt;

&lt;p&gt;The tools are live on &lt;a href="https://quantumines.com/" rel="noopener noreferrer"&gt;quantumines.com&lt;/a&gt; and documented, with the rest of our machine-readable files, in the &lt;a href="https://quantumines.com/ai" rel="noopener noreferrer"&gt;guide for AI readers&lt;/a&gt;. Quantumines is the studio founded by &lt;a href="https://quantumines.com/muhammad-ali-raza" rel="noopener noreferrer"&gt;Muhammad Ali Raza (Ali Arbi)&lt;/a&gt;; for its products, see &lt;a href="https://quantumines.com/products" rel="noopener noreferrer"&gt;/products&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://quantumines.com/blog/how-we-added-webmcp-to-quantumines-com" rel="noopener noreferrer"&gt;quantumines.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>javascript</category>
      <category>chrome</category>
    </item>
    <item>
      <title>Why we built our own hosting after Railway kept our data</title>
      <dc:creator>Muhammad Ali Raza</dc:creator>
      <pubDate>Wed, 11 Nov 2026 05:19:48 +0000</pubDate>
      <link>https://dev.to/ceo_quantumines/why-we-built-our-own-hosting-after-railway-kept-our-data-47jj</link>
      <guid>https://dev.to/ceo_quantumines/why-we-built-our-own-hosting-after-railway-kept-our-data-47jj</guid>
      <description>&lt;p&gt;&lt;strong&gt;VPS Cloud Hostings was born out of a bad night.&lt;/strong&gt; In November 2026, Railway closed the Quantumines account without notice and without giving a reason. Every Quantumines project ran there. Railway kept the custom domains tied to the account and did not return the project databases, even after Quantumines asked in writing for a full export within 7 days. Quantumines covered its own users' losses with account credits. That same night, founder &lt;a href="https://quantumines.com/muhammad-ali-raza" rel="noopener noreferrer"&gt;Muhammad Ali Raza (Ali Arbi)&lt;/a&gt; and his younger brother and co-founder &lt;a href="https://quantumines.com/muhammad-anas" rel="noopener noreferrer"&gt;Muhammad Anas&lt;/a&gt; started building their own platform, so that no developer would have to go through the same thing. &lt;a href="https://vpscloudhostings.com" rel="noopener noreferrer"&gt;VPS Cloud Hostings&lt;/a&gt; is the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;We hosted every one of our products on Railway: &lt;a href="https://quantumines.com/products/hunt4coin" rel="noopener noreferrer"&gt;Hunt4Coin&lt;/a&gt;, &lt;a href="https://quantumines.com/products/chessmess" rel="noopener noreferrer"&gt;ChessMess&lt;/a&gt;, &lt;a href="https://quantumines.com/products/cryptomerchant" rel="noopener noreferrer"&gt;CryptoMerchant&lt;/a&gt;, &lt;a href="https://quantumines.com/products/verifdoc" rel="noopener noreferrer"&gt;VerifDoc&lt;/a&gt;, &lt;a href="https://quantumines.com/products/proxyfall" rel="noopener noreferrer"&gt;ProxyFall&lt;/a&gt;, &lt;a href="https://quantumines.com/products/twaptrade" rel="noopener noreferrer"&gt;TwapTrade&lt;/a&gt; and quantumines.com. In November 2026 our account was closed overnight, with no warning and no explanation.&lt;/p&gt;

&lt;p&gt;Our custom domains stayed locked to the closed account, so we could not attach them to a new one. Our databases, which we created and paid for, were not handed back. We asked in writing for a full export within 7 days and did not receive one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it cost
&lt;/h2&gt;

&lt;p&gt;Data stored on the closed account was lost to us, including our users' data. We paid our own users back in account credits and took the loss ourselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we decided
&lt;/h2&gt;

&lt;p&gt;That night we decided never to depend on someone else's goodwill for our own data again, and to build the hosting we wished we'd had: on our own servers, with no lock-in. Muhammad Anas and I started building it that same night.&lt;/p&gt;

&lt;h2&gt;
  
  
  What VPS Cloud Hostings is
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static sites:&lt;/strong&gt; free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small websites:&lt;/strong&gt; $1 a month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Professional apps:&lt;/strong&gt; $5 a month with $5 of usage included, then fair hourly pricing above that.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is a Quantumines project, and our own products move onto it first.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we promise
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Your data is yours.&lt;/strong&gt; Database backups and a full export are available from your panel at any time, including after you leave us and including if your account is ever suspended.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No silent bans.&lt;/strong&gt; If we suspend an account, we say which rule was broken.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your domains are yours.&lt;/strong&gt; Remove a domain from your project and it is released at once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fair prices.&lt;/strong&gt; Free static hosting, a $1 plan for small sites, and $5 a month with $5 of usage included for professional apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Moving your own project?
&lt;/h2&gt;

&lt;p&gt;If you are moving off Railway or any other host, start at &lt;a href="https://vpscloudhostings.com" rel="noopener noreferrer"&gt;vpscloudhostings.com&lt;/a&gt;. Keep a copy of your own database somewhere you control, whichever host you use; we learned that the hard way.&lt;/p&gt;

&lt;p&gt;— Muhammad Ali Raza (Ali Arbi), founder of Quantumines&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://quantumines.com/blog/why-we-built-our-own-hosting-after-railway-kept-our-data" rel="noopener noreferrer"&gt;quantumines.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>hosting</category>
      <category>devops</category>
      <category>startup</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Studio update, 9 November 2026: TwapTrade becomes a prediction market</title>
      <dc:creator>Muhammad Ali Raza</dc:creator>
      <pubDate>Tue, 10 Nov 2026 13:00:28 +0000</pubDate>
      <link>https://dev.to/ceo_quantumines/studio-update-9-november-2026-twaptrade-becomes-a-prediction-market-b1j</link>
      <guid>https://dev.to/ceo_quantumines/studio-update-9-november-2026-twaptrade-becomes-a-prediction-market-b1j</guid>
      <description>&lt;p&gt;The biggest change at Quantumines this week is TwapTrade: twaptrade.com is now a prediction market, where every market is a question with a deadline and prices act as live odds. It replaces the earlier trading workspace with bot controls and paper trading, so older descriptions of TwapTrade are out of date. Hunt4Coin also trimmed the coin pages it offers to search engines, and quantumines.com gained a founder note, two glossaries and several new guides and answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is TwapTrade now?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://twaptrade.com" rel="noopener noreferrer"&gt;TwapTrade&lt;/a&gt; describes itself as a prediction market: it shows live markets, odds, order books and trades on real-world events in politics, sports, crypto, finance and culture. Its &lt;a href="https://www.twaptrade.com/how-it-works" rel="noopener noreferrer"&gt;How it works&lt;/a&gt; page sets out the mechanics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each market is a question with a deadline, and each side trades between 1¢ and 99¢.&lt;/li&gt;
&lt;li&gt;A price is read as a probability: a Yes share at 34¢ means the market puts the chance at about 34%.&lt;/li&gt;
&lt;li&gt;When the market settles, each winning share pays $1 and each losing share pays nothing. A position can also be sold early at the current price.&lt;/li&gt;
&lt;li&gt;Users keep their funds in their own self-custody wallet. Deposits are by card, Apple Pay or Google Pay through a card partner, or in USDC and other crypto.&lt;/li&gt;
&lt;li&gt;Trading is not available in restricted jurisdictions, for example the US, UK and France. Browsing is open to everyone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The site's own summary for AI assistants says the prediction market replaced an earlier, unrelated product on the domain in November 2026. The old pages on TWAP, paper trading and trading-bot risk are no longer online.&lt;/p&gt;

&lt;p&gt;A prediction market carries real risk: a losing share is worth nothing at settlement. Nothing here is a recommendation to trade, and readers should check whether it is allowed where they live.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed on quantumines.com because of it?
&lt;/h2&gt;

&lt;p&gt;Every page that described TwapTrade was corrected: the &lt;a href="https://quantumines.com/facts" rel="noopener noreferrer"&gt;facts page&lt;/a&gt;, the &lt;a href="https://quantumines.com/about" rel="noopener noreferrer"&gt;about page&lt;/a&gt;, the homepage product card, &lt;a href="https://quantumines.com/blog/what-is-quantumines" rel="noopener noreferrer"&gt;What is Quantumines?&lt;/a&gt; and the &lt;a href="https://quantumines.com/blog/who-is-muhammad-ali-raza-ali-arbi-quantumines" rel="noopener noreferrer"&gt;founder note&lt;/a&gt;. The &lt;a href="https://quantumines.com/answers/what-is-twap-trading" rel="noopener noreferrer"&gt;answer on TWAP&lt;/a&gt; still explains the method, but its TwapTrade section was removed, because the product no longer offers TWAP tools. Each changed page carries a dated "What's changed" note.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed on Hunt4Coin?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://hunt4coin.com" rel="noopener noreferrer"&gt;Hunt4Coin&lt;/a&gt; now asks search engines to index fewer, more useful coin pages. Its coin sitemap lists 2,697 coin pages, down from more than 16,000 a few days ago, alongside 65 site pages. Pages for very small coins are still open to visitors but are marked "noindex, follow", so search engines skip them while still following their links. Major coins such as &lt;a href="https://hunt4coin.com/coin/cg-bitcoin" rel="noopener noreferrer"&gt;Bitcoin&lt;/a&gt; stay indexable, each with its own canonical address. The aim is to stop thousands of near-identical pages from diluting the ones people actually search for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was published on quantumines.com last week?
&lt;/h2&gt;

&lt;p&gt;From 3 to 8 November the studio site added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two plain-English glossaries: &lt;a href="https://quantumines.com/proxy-glossary" rel="noopener noreferrer"&gt;proxy terms&lt;/a&gt; and &lt;a href="https://quantumines.com/crypto-payments-glossary" rel="noopener noreferrer"&gt;crypto payment terms&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Guides on &lt;a href="https://quantumines.com/blog/crypto-payment-gateway-fees-explained" rel="noopener noreferrer"&gt;crypto payment gateway fees&lt;/a&gt;, &lt;a href="https://quantumines.com/blog/proxies-price-monitoring-seo-rank-tracking" rel="noopener noreferrer"&gt;proxies for price monitoring and rank tracking&lt;/a&gt; and &lt;a href="https://quantumines.com/blog/virtual-phone-number-business-email-small-business" rel="noopener noreferrer"&gt;a virtual number and business email for a small business&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Answers on &lt;a href="https://quantumines.com/answers/chess-bot-that-plays-like-a-human" rel="noopener noreferrer"&gt;chess bots that play like a person&lt;/a&gt;, &lt;a href="https://quantumines.com/answers/free-crypto-screener-rsi-macd" rel="noopener noreferrer"&gt;free crypto screeners with RSI and MACD&lt;/a&gt; and &lt;a href="https://quantumines.com/answers/what-is-twap-trading" rel="noopener noreferrer"&gt;what TWAP means&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://quantumines.com/about" rel="noopener noreferrer"&gt;about page&lt;/a&gt; and an updated &lt;a href="https://quantumines.com/facts" rel="noopener noreferrer"&gt;facts page&lt;/a&gt; listing the studio's best-known products with their one-line descriptions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where to check the current facts
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://quantumines.com/facts" rel="noopener noreferrer"&gt;facts page&lt;/a&gt; is the single place for each product's current one-line description and its main guides. When a product changes, as TwapTrade did this week, that page changes first.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://quantumines.com/blog/studio-update-2026-11-09-twaptrade-prediction-market" rel="noopener noreferrer"&gt;quantumines.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>startup</category>
      <category>crypto</category>
      <category>seo</category>
    </item>
  </channel>
</rss>
